From dc23211e72305c59eb5a8be748e3dea4ee6f60aa Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Thu, 18 Feb 2021 21:43:56 -0500 Subject: [PATCH 1/2] Update formatting script to use pre-commit and GitHub Actions --- .gitattributes | 7 ++++ .github/workflows/file_format.py | 52 +++++++++++++++++++++++++++++ .github/workflows/static_checks.yml | 24 +++++++++++++ .pre-commit-config.yaml | 16 +++++++++ appveyor.yml | 13 -------- format.sh | 47 -------------------------- 6 files changed, 99 insertions(+), 60 deletions(-) create mode 100755 .github/workflows/file_format.py create mode 100644 .github/workflows/static_checks.yml create mode 100644 .pre-commit-config.yaml delete mode 100755 format.sh diff --git a/.gitattributes b/.gitattributes index 7cf76504..0a5c249b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,8 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf +# Except for Windows-only / Visual Studio files +*.bat eol=crlf +*.sln eol=crlf +*.csproj eol=crlf + *.hdr binary diff --git a/.github/workflows/file_format.py b/.github/workflows/file_format.py new file mode 100755 index 00000000..8f511529 --- /dev/null +++ b/.github/workflows/file_format.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys + +if len(sys.argv) < 2: + print("Invalid usage of file_format.py, it should be called with a path to one or multiple files.") + sys.exit(1) + +BOM = b"\xef\xbb\xbf" + +changed = [] +invalid = [] + +for file in sys.argv[1:]: + try: + with open(file, "rt", encoding="utf-8") as f: + original = f.read() + except UnicodeDecodeError: + invalid.append(file) + continue + + if original == "": + continue + + EOL = "\r\n" if file.endswith((".csproj", ".sln", ".bat")) else "\n" + WANTS_BOM = file.endswith((".csproj", ".sln")) + + revamp = EOL.join([line.rstrip("\n\r\t ") for line in original.splitlines(True)]).rstrip(EOL) + EOL + + new_raw = revamp.encode(encoding="utf-8") + if not WANTS_BOM and new_raw.startswith(BOM): + new_raw = new_raw[len(BOM) :] + elif WANTS_BOM and not new_raw.startswith(BOM): + new_raw = BOM + new_raw + + with open(file, "rb") as f: + old_raw = f.read() + + if old_raw != new_raw: + changed.append(file) + with open(file, "wb") as f: + f.write(new_raw) + +if changed: + for file in changed: + print(f"FIXED: {file}") + +if invalid: + for file in invalid: + print(f"REQUIRES MANUAL CHANGES: {file}") + sys.exit(1) diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml new file mode 100644 index 00000000..1ed054a8 --- /dev/null +++ b/.github/workflows/static_checks.yml @@ -0,0 +1,24 @@ +name: 📊 Static Checks +on: [push, pull_request] + +concurrency: + group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static + +jobs: + static-checks: + name: Code style and file formatting + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Install Python dependencies and general setup + run: | + git config diff.wsErrorHighlight all + + - name: Style checks via pre-commit + uses: pre-commit/action@v3.0.1 + with: + extra_args: --all-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f2796719 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +default_language_version: + python: python3 + +exclude: | + (?x)^( + CODE_OF_CONDUCT.md + ) + +repos: + - repo: local + hooks: + - id: file-format + name: file-format + language: python + entry: python .github/workflows/file_format.py + types_or: [text] diff --git a/appveyor.yml b/appveyor.yml index 2e08df14..7dd4dcb0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,13 +10,6 @@ configuration: Release environment: APPVEYOR_YML_DISABLE_PS_LINUX: true -install: -- sh: | - if [ "$(uname)" != "Darwin" ]; then - sudo apt-get update -y - sudo apt-get install -y dos2unix recode - fi - build_script: - ps: | New-Item -Path . -Name "build" -ItemType "directory" @@ -33,12 +26,6 @@ build_script: cmake --build . --config ${CONFIGURATION} cd ../ -test_script: - - sh: | - if [ "$(uname)" != "Darwin" ]; then - bash ./format.sh - fi - artifacts: # Linux - path: bin/basisu diff --git a/format.sh b/format.sh deleted file mode 100755 index 5760aec5..00000000 --- a/format.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# Loops through all text files tracked by Git. -git grep -zIl '' | -while IFS= read -rd '' f; do - # Exclude some types of files. - if [[ $f == *"proj" ]]; then - continue - elif [[ $f == *"filters" ]]; then - continue - elif [[ $f == *"sln" ]]; then - continue - elif [[ $f == *"json" ]]; then - continue - elif [[ $f == *"min.js" ]]; then - continue - elif [[ $f == *"coder.js" ]]; then - continue - fi - # Ensures that files are UTF-8 formatted. - recode UTF-8 $f 2> /dev/null - # Ensures that files have LF line endings. - dos2unix $f 2> /dev/null - # Ensures that files do not contain a BOM. - sed -i '1s/^\xEF\xBB\xBF//' "$f" - # Ensures that files end with newline characters. - tail -c1 < "$f" | read -r _ || echo >> "$f"; -done - -git diff > patch.patch -FILESIZE=$(stat -c%s patch.patch) -MAXSIZE=5 - -# If no patch has been generated all is OK, clean up, and exit. -if (( FILESIZE < MAXSIZE )); then - printf "Files in this commit comply with the formatting rules.\n" - rm -f patch.patch - exit 0 -fi - -# A patch has been created, notify the user, clean up, and exit. -printf "\n*** The following differences were found between the code " -printf "and the formatting rules:\n\n" -cat patch.patch -printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\n" -rm -f patch.patch -exit 1 From ce03763b6cc2d8ebbdac49a6dfa75616a037057f Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Sat, 15 Mar 2025 02:13:53 -0700 Subject: [PATCH 2/2] Remove trailing space characters with the formatting script --- CMakeLists.txt | 36 +- CppProperties.json | 2 +- LICENSES/Apache-2.0.txt | 20 +- OpenCL/CL/cl_d3d10.h | 1 - OpenCL/CL/cl_d3d11.h | 1 - OpenCL/CL/cl_dx9_media_sharing.h | 5 +- OpenCL/CL/cl_ext.h | 2 +- OpenCL/CL/cl_gl.h | 2 +- OpenCL/CL/cl_va_api_media_sharing_intel.h | 1 - OpenCL/license.txt | 3 +- README.md | 28 +- appveyor.yml | 2 +- basisu.manifest | 1 - basisu.vcxproj | 4 +- basisu.vcxproj.filters | 4 +- basisu_tool.cpp | 217 +++-- bin/ocl_kernels.cl | 121 ++- contrib/previewers/lib/basisu_transcoder.cpp | 820 ++++++++-------- contrib/previewers/win/basisthumbprovider.h | 16 +- contrib/previewers/win/helpers.cpp | 4 +- contrib/previewers/win/helpers.h | 6 +- contrib/previewers/win/previewers.def | 1 - contrib/previewers/win/previewers.vcxproj | 4 +- .../previewers/win/previewers.vcxproj.filters | 4 +- contrib/single_file_transcoder/README.md | 4 +- .../basisu_transcoder-in.cpp | 4 +- contrib/single_file_transcoder/combine.py | 38 +- contrib/single_file_transcoder/combine.sh | 6 +- .../create_transcoder.sh | 2 - .../examples/emscripten.cpp | 34 +- .../examples/simple.cpp | 4 +- encoder/3rdparty/android_astc_decomp.cpp | 72 +- encoder/3rdparty/android_astc_decomp.h | 2 +- encoder/3rdparty/qoi.h | 2 +- encoder/3rdparty/tinydds.h | 2 +- encoder/3rdparty/tinyexr.h | 10 +- encoder/basisu_astc_hdr_6x6_enc.cpp | 316 +++--- encoder/basisu_astc_hdr_6x6_enc.h | 20 +- encoder/basisu_astc_hdr_common.cpp | 131 ++- encoder/basisu_astc_hdr_common.h | 33 +- encoder/basisu_backend.cpp | 50 +- encoder/basisu_backend.h | 19 +- encoder/basisu_basis_file.cpp | 14 +- encoder/basisu_bc7enc.cpp | 116 +-- encoder/basisu_bc7enc.h | 12 +- encoder/basisu_comp.cpp | 297 +++--- encoder/basisu_comp.h | 131 ++- encoder/basisu_enc.cpp | 250 ++--- encoder/basisu_enc.h | 252 ++--- encoder/basisu_etc.cpp | 42 +- encoder/basisu_etc.h | 26 +- encoder/basisu_frontend.cpp | 271 +++--- encoder/basisu_frontend.h | 40 +- encoder/basisu_gpu_texture.cpp | 175 ++-- encoder/basisu_gpu_texture.h | 19 +- encoder/basisu_kernels_imp.h | 18 +- encoder/basisu_kernels_sse.cpp | 1 - encoder/basisu_math.h | 69 +- encoder/basisu_miniz.h | 15 +- encoder/basisu_opencl.cpp | 54 +- encoder/basisu_opencl.h | 4 +- encoder/basisu_pvrtc1_4.cpp | 26 +- encoder/basisu_pvrtc1_4.h | 42 +- encoder/basisu_resample_filters.cpp | 22 +- encoder/basisu_resampler.cpp | 4 +- encoder/basisu_resampler_filters.h | 2 +- encoder/basisu_ssim.cpp | 6 +- encoder/basisu_uastc_enc.cpp | 111 ++- encoder/basisu_uastc_enc.h | 34 +- encoder/basisu_uastc_hdr_4x4_enc.cpp | 87 +- encoder/basisu_uastc_hdr_4x4_enc.h | 35 +- encoder/cppspmd_flow.h | 76 +- encoder/cppspmd_math.h | 204 ++-- encoder/cppspmd_math_declares.h | 3 +- encoder/cppspmd_sse.h | 135 ++- encoder/jpgd.cpp | 12 +- encoder/jpgd.h | 4 +- encoder/pvpngreader.cpp | 152 +-- encoder/pvpngreader.h | 2 +- encoder_lib/encoder_lib.vcxproj | 2 +- encoder_lib/encoder_lib.vcxproj.filters | 4 +- example/example.cpp | 48 +- example/example.manifest | 1 - example/example.vcxproj | 2 +- example/example.vcxproj.filters | 4 +- test_files/license.txt | 1 - transcoder/basisu.h | 81 +- transcoder/basisu_astc_hdr_core.h | 3 +- transcoder/basisu_astc_helpers.h | 296 +++--- transcoder/basisu_containers.h | 60 +- transcoder/basisu_containers_impl.h | 12 +- transcoder/basisu_file_headers.h | 38 +- transcoder/basisu_transcoder.cpp | 770 +++++++-------- transcoder/basisu_transcoder.h | 87 +- transcoder/basisu_transcoder_internal.h | 49 +- transcoder/basisu_transcoder_uastc.h | 20 +- webgl/README.md | 4 +- webgl/encoder/CMakeLists.txt | 52 +- webgl/encoder/build/basis_encoder.js | 900 +++++++++--------- webgl/gltf/BasisTextureLoader.js | 4 +- webgl/gltf/GLTFLoader.js | 2 +- webgl/gltf/index.html | 4 +- webgl/gltf/three.min.js | 2 +- webgl/ktx2_encode_test/index.html | 406 ++++---- webgl/ktx2_encode_test/renderer.js | 11 +- webgl/texture_test/index.html | 12 +- webgl/texture_test/renderer.js | 1 - webgl/transcoder/CMakeLists.txt | 38 +- webgl/transcoder/basis_wrappers.cpp | 84 +- webgl/transcoder/build/basis_transcoder.js | 640 ++++++------- webgl/video_test/renderer.js | 1 - zstd/zstd.c | 12 +- zstd/zstddeclib.c | 8 +- 113 files changed, 4216 insertions(+), 4260 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2c7a1dd..0d80b77c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) # For MSVC builds default to SSE enabled, and determine if it's a 64-bit (-A x64) vs. 32-bit (-A Win32) build. if (MSVC) option(SSE "SSE 4.1 support" TRUE) - if ( CMAKE_GENERATOR_PLATFORM STREQUAL Win32 ) + if ( CMAKE_GENERATOR_PLATFORM STREQUAL Win32 ) set(BUILD_X64 0) else() set(BUILD_X64 1) @@ -68,25 +68,25 @@ endif() if (NOT MSVC) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g") - + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") if (SAN) message("Enabling SAN") - + set(SANITIZE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize=alignment") - + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${SANITIZE_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${SANITIZE_FLAGS}") - + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${SANITIZE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${SANITIZE_FLAGS}") endif() set(CMAKE_CXX_FLAGS -std=c++17) set(GCC_COMPILE_FLAGS "-fvisibility=hidden -fPIC -fno-strict-aliasing -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -Wall -Wextra -Wno-unused-local-typedefs -Wno-unused-value -Wno-unused-parameter -Wno-unused-variable -Wno-reorder -Wno-misleading-indentation -Wno-class-memaccess -Wno-deprecated-copy -Wno-maybe-uninitialized -Wno-unused-function -Wno-stringop-overflow -Wno-unknown-warning-option") - + if (NOT BUILD_X64) set(GCC_COMPILE_FLAGS "${GCC_COMPILE_FLAGS} -m32") endif() @@ -104,7 +104,7 @@ if (NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBASISU_SUPPORT_SSE=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_SSE=0") endif() - + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_LINK_FLAGS} -static-libgcc -static-libstdc++ -static") else() if (SSE) @@ -114,7 +114,7 @@ if (NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBASISU_SUPPORT_SSE=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_SSE=0") endif() - + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_LINK_FLAGS} -Wl,-rpath .") endif() @@ -189,8 +189,8 @@ if (NOT MSVC) # For Non-Windows builds, let cmake try and find the system OpenCL headers/libs for us. if (OPENCL AND OPENCL_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBASISU_SUPPORT_OPENCL=1") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_OPENCL=1") - + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_OPENCL=1") + target_include_directories(basisu PRIVATE ${OpenCL_INCLUDE_DIRS}) target_include_directories(examples PRIVATE ${OpenCL_INCLUDE_DIRS}) target_include_directories(basisu_encoder PRIVATE ${OpenCL_INCLUDE_DIRS}) @@ -200,8 +200,8 @@ else() # For Windows builds, we use our local copies of the OpenCL import lib and Khronos headers. if (OPENCL) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBASISU_SUPPORT_OPENCL=1") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_OPENCL=1") - + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBASISU_SUPPORT_OPENCL=1") + target_include_directories(basisu PRIVATE "OpenCL") target_include_directories(examples PRIVATE "OpenCL") target_include_directories(basisu_encoder PRIVATE "OpenCL") @@ -214,7 +214,7 @@ else() target_link_libraries(examples PRIVATE "${CMAKE_SOURCE_DIR}/OpenCL/lib/OpenCL.lib") endif() endif() -endif() +endif() if (NOT MSVC) target_link_libraries(basisu PRIVATE m pthread ${BASISU_EXTRA_LIBS}) @@ -236,19 +236,19 @@ if (NOT EMSCRIPTEN) endif() if (MSVC) - set_target_properties(basisu PROPERTIES + set_target_properties(basisu PROPERTIES RUNTIME_OUTPUT_NAME "basisu" RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - ) - - set_target_properties(examples PROPERTIES + ) + + set_target_properties(examples PROPERTIES RUNTIME_OUTPUT_NAME "examples" RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - ) + ) endif() diff --git a/CppProperties.json b/CppProperties.json index 6017def8..1a25e52a 100644 --- a/CppProperties.json +++ b/CppProperties.json @@ -18,4 +18,4 @@ "intelliSenseMode": "windows-msvc-x64" } ] -} \ No newline at end of file +} diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt index 4ed90b95..527a83a2 100644 --- a/LICENSES/Apache-2.0.txt +++ b/LICENSES/Apache-2.0.txt @@ -7,17 +7,17 @@ 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. @@ -26,31 +26,31 @@ 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, @@ -59,7 +59,7 @@ 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 @@ -74,7 +74,7 @@ for the purpose of discussing and improving the Work, but excluding communicatio 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 diff --git a/OpenCL/CL/cl_d3d10.h b/OpenCL/CL/cl_d3d10.h index 6adedb06..5fd7609f 100644 --- a/OpenCL/CL/cl_d3d10.h +++ b/OpenCL/CL/cl_d3d10.h @@ -125,4 +125,3 @@ typedef cl_int (CL_API_CALL *clEnqueueReleaseD3D10ObjectsKHR_fn)( #endif #endif /* __OPENCL_CL_D3D10_H */ - diff --git a/OpenCL/CL/cl_d3d11.h b/OpenCL/CL/cl_d3d11.h index 50ed906b..5f3854a5 100644 --- a/OpenCL/CL/cl_d3d11.h +++ b/OpenCL/CL/cl_d3d11.h @@ -125,4 +125,3 @@ typedef cl_int (CL_API_CALL *clEnqueueReleaseD3D11ObjectsKHR_fn)( #endif #endif /* __OPENCL_CL_D3D11_H */ - diff --git a/OpenCL/CL/cl_dx9_media_sharing.h b/OpenCL/CL/cl_dx9_media_sharing.h index b0d2b234..38d17ce6 100644 --- a/OpenCL/CL/cl_dx9_media_sharing.h +++ b/OpenCL/CL/cl_dx9_media_sharing.h @@ -30,7 +30,7 @@ extern "C" { typedef cl_uint cl_dx9_media_adapter_type_khr; typedef cl_uint cl_dx9_media_adapter_set_khr; - + #if defined(_WIN32) #include typedef struct _cl_dx9_surface_info_khr @@ -91,7 +91,7 @@ typedef cl_mem (CL_API_CALL *clCreateFromDX9MediaSurfaceKHR_fn)( cl_mem_flags flags, cl_dx9_media_adapter_type_khr adapter_type, void * surface_info, - cl_uint plane, + cl_uint plane, cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; typedef cl_int (CL_API_CALL *clEnqueueAcquireDX9MediaSurfacesKHR_fn)( @@ -226,4 +226,3 @@ typedef cl_int (CL_API_CALL *clEnqueueReleaseDX9ObjectsINTEL_fn)( #endif #endif /* __OPENCL_CL_DX9_MEDIA_SHARING_H */ - diff --git a/OpenCL/CL/cl_ext.h b/OpenCL/CL/cl_ext.h index 36d02568..aec3db37 100644 --- a/OpenCL/CL/cl_ext.h +++ b/OpenCL/CL/cl_ext.h @@ -524,7 +524,7 @@ clEnqueueGenerateMipmapIMG(cl_command_queue command_queue, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) CL_API_SUFFIX__VERSION_1_2; - + /****************************************** * cl_img_mem_properties extension * ******************************************/ diff --git a/OpenCL/CL/cl_gl.h b/OpenCL/CL/cl_gl.h index 5ea0fd8b..ba421b6b 100644 --- a/OpenCL/CL/cl_gl.h +++ b/OpenCL/CL/cl_gl.h @@ -152,7 +152,7 @@ typedef cl_int (CL_API_CALL *clGetGLContextInfoKHR_fn)( void * param_value, size_t * param_value_size_ret); -/* +/* * cl_khr_gl_event extension */ #define CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR 0x200D diff --git a/OpenCL/CL/cl_va_api_media_sharing_intel.h b/OpenCL/CL/cl_va_api_media_sharing_intel.h index 7ba2ec83..e7ee568b 100644 --- a/OpenCL/CL/cl_va_api_media_sharing_intel.h +++ b/OpenCL/CL/cl_va_api_media_sharing_intel.h @@ -133,4 +133,3 @@ typedef cl_int (CL_API_CALL *clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)( #endif #endif /* __OPENCL_CL_VA_API_MEDIA_SHARING_INTEL_H */ - diff --git a/OpenCL/license.txt b/OpenCL/license.txt index 9d69cfcb..e4584dac 100644 --- a/OpenCL/license.txt +++ b/OpenCL/license.txt @@ -1,4 +1,3 @@ -These optional files (which are only needed when compiling with OpenCL support enabled in the encoder) are from the +These optional files (which are only needed when compiling with OpenCL support enabled in the encoder) are from the Khronos Group OpenCL headers github repo. They are Copyright (c) 2008-2020 The Khronos Group Inc. https://github.com/KhronosGroup/OpenCL-Headers - diff --git a/README.md b/README.md index 8f1e82ea..058c4c37 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ An LDR/HDR portable GPU compressed texture transcoding system. Intro ----- -Basis Universal is an open source [supercompressed](http://gamma.cs.unc.edu/GST/gst.pdf) LDR/HDR GPU compressed texture interchange system from Binomial LLC that supports two intermediate file formats: the [.KTX2 open standard from the Khronos Group](https://registry.khronos.org/KTX/specs/2.0/ktxspec.v2.html), and our own ".basis" file format. These file formats support rapid transcoding to virtually any compressed [GPU texture format](https://en.wikipedia.org/wiki/Texture_compression) released in the past ~25 years. +Basis Universal is an open source [supercompressed](http://gamma.cs.unc.edu/GST/gst.pdf) LDR/HDR GPU compressed texture interchange system from Binomial LLC that supports two intermediate file formats: the [.KTX2 open standard from the Khronos Group](https://registry.khronos.org/KTX/specs/2.0/ktxspec.v2.html), and our own ".basis" file format. These file formats support rapid transcoding to virtually any compressed [GPU texture format](https://en.wikipedia.org/wiki/Texture_compression) released in the past ~25 years. Our overall goal with this project is to simplify the encoding and efficient distribution of *portable* LDR and HDR GPU texture, image, and short texture video content in a way that is compatible with any GPU or rendering/graphics API. @@ -74,7 +74,7 @@ Here is the [UASTC HDR 4x4 specification document](https://github.com/BinomialLL 5. UASTC HDR 6x6 Intermediate ("GPU Photo"): A custom compressed intermediate format that can be rapidly transcoded to ASTC HDR 6x6, BC6H, and various uncompressed HDR formats. The custom compressed file format is [described here](https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-6x6-Intermediate-File-Format-(Basis-GPU-Photo-6x6)). The format supports 75 unique ASTC configurations, weight grid upsampling, 1-3 subsets, single or dual planes, CEM's 7 and 11, and all unique ASTC partition patterns. -Notes: +Notes: - Modes #3 and #4 output 100% standard or plain ASTC texture data (with or without RDO), like any other ASTC encoder. The .KTX2 files are just plain textures. - The other modes (#1, #2, #5) output compressed data in various custom formats, which our transcoder library can convert in real-time to various GPU texture or pixel formats. - Modes #4 and #5 internally use the same unified HDR 6x6 encoder. @@ -156,16 +156,16 @@ Compressing and Unpacking .KTX2/.basis Files - To compress an HDR 6x6 file: ``` -basisu -hdr_6x6 x.exr -basisu -hdr_6x6 -lambda 500 x.exr +basisu -hdr_6x6 x.exr +basisu -hdr_6x6 -lambda 500 x.exr basisu -hdr_6x6_level 5 -lambda 500 x.exr ``` - To compress an HDR 6x6 file using the compressed intermediate format for smaller files: ``` -basisu -hdr_6x6i x.exr -basisu -hdr_6x6i -lambda 500 x.exr +basisu -hdr_6x6i x.exr +basisu -hdr_6x6i -lambda 500 x.exr basisu -hdr_6x6i_level 5 -lambda 500 x.exr ``` @@ -177,7 +177,7 @@ Note: If you're compressing LDR/SDR image files to an HDR format, the codec's de ### Some Useful Command Line Options -- `-fastest` (which is equivalent to `-uastc_level 0`) puts the UASTC LDR/HDR encoders in their fastest (but lower quality) modes. +- `-fastest` (which is equivalent to `-uastc_level 0`) puts the UASTC LDR/HDR encoders in their fastest (but lower quality) modes. - `-slower` puts the UASTC LDR/HDR encoders in higher quality but slower modes (equivalent to `-uastc_level 3`). The default level is 1, and the highest is 4 (which is quite slow). @@ -185,7 +185,7 @@ Note: If you're compressing LDR/SDR image files to an HDR format, the codec's de - `-debug` causes the encoder to print internal and developer-oriented verbose debug information. -- `-stats` to see various quality (PSNR) statistics. +- `-stats` to see various quality (PSNR) statistics. - `-linear`: ETC1S defaults to sRGB colorspace metrics, UASTC LDR currently always uses linear metrics, and UASTC HDR defaults to weighted RGB metrics (with 2,3,1 weights). If the input is a normal map, or some other type of non-sRGB (non-photographic) texture content, be sure to use `-linear` to avoid extra unnecessary artifacts. (Angular normal map metrics for UASTC LDR/HDR are definitely doable and on our TODO list.) @@ -212,7 +212,7 @@ There are several mipmap options to change the filter kernel, the filter colorsp `basisu -comp_level 2 x.png` -On some rare images (ones with blue sky gradients come to bind), you may need to increase the ETC1S `-comp_level` setting, which ranges from 1,6. This controls the amount of overall effort the encoder uses to optimize the ETC1S codebooks and the compressed data stream. Higher comp_level's are *significantly* slower. +On some rare images (ones with blue sky gradients come to bind), you may need to increase the ETC1S `-comp_level` setting, which ranges from 1,6. This controls the amount of overall effort the encoder uses to optimize the ETC1S codebooks and the compressed data stream. Higher comp_level's are *significantly* slower. - To manually set the ETC1S codebook sizes (instead of using -q), with a higher codebook generation level (this is useful with texture video): @@ -239,11 +239,11 @@ You can either use the command line tool or [call the transcoder directly](https `basisu x.ktx2` -Use the `-no_ktx` and `-etc1_only`/`-format_only` options to unpack to less files. +Use the `-no_ktx` and `-etc1_only`/`-format_only` options to unpack to less files. -`-info` and `-validate` will just display file information and not output any files. +`-info` and `-validate` will just display file information and not output any files. -The written mipmapped, cubemap, or texture array .KTX/.DDS files will be in a wide variety of compressed GPU texture formats (PVRTC1 4bpp, ETC1-2, BC1-5, BC7, etc.), and to our knowledge there is unfortunately (as of 2024) still no single .KTX or .DDS viewer tool that correctly and reliably supports every GPU texture format that we support. BC1-5 and BC7 files are viewable using AMD's Compressonator, ETC1/2 using Mali's Texture Compression Tool, and PVRTC1 using Imagination Tech's PVRTexTool. [RenderDoc](https://renderdoc.org/) has a useful texture file viewer for many formats. The Mac OSX Finder supports previewing .EXR and .KTX files in various GPU formats. The Windows 11 Explorer can preview .DDS files. The [online OpenHDR Viewer](https://viewer.openhdr.org/) is useful for viewing .EXR/.HDR image files. +The written mipmapped, cubemap, or texture array .KTX/.DDS files will be in a wide variety of compressed GPU texture formats (PVRTC1 4bpp, ETC1-2, BC1-5, BC7, etc.), and to our knowledge there is unfortunately (as of 2024) still no single .KTX or .DDS viewer tool that correctly and reliably supports every GPU texture format that we support. BC1-5 and BC7 files are viewable using AMD's Compressonator, ETC1/2 using Mali's Texture Compression Tool, and PVRTC1 using Imagination Tech's PVRTexTool. [RenderDoc](https://renderdoc.org/) has a useful texture file viewer for many formats. The Mac OSX Finder supports previewing .EXR and .KTX files in various GPU formats. The Windows 11 Explorer can preview .DDS files. The [online OpenHDR Viewer](https://viewer.openhdr.org/) is useful for viewing .EXR/.HDR image files. WebGL Examples -------------- @@ -254,10 +254,10 @@ The 'WebGL' directory contains several simple WebGL demos that use the transcode ![Screenshot of 'gltf' example running in a browser.](webgl/gltf/preview.png) ![Screenshot of 'encode_test' example running in a browser.](webgl/ktx2_encode_test/preview.png) -Building the WASM Modules with [Emscripten](https://emscripten.org/) +Building the WASM Modules with [Emscripten](https://emscripten.org/) -------------------------------------------------------------------- -Both the transcoder and encoder may be compiled using emscripten to WebAssembly and used on the web. A set of JavaScript wrappers to the codec, written in C++ with emscripten extensions, is located in `webgl/transcoding/basis_wrappers.cpp`. The JavaScript wrapper supports nearly all features and modes, including texture video. See the README.md and CMakeLists.txt files in `webgl/transcoder` and `webgl/encoder`. +Both the transcoder and encoder may be compiled using emscripten to WebAssembly and used on the web. A set of JavaScript wrappers to the codec, written in C++ with emscripten extensions, is located in `webgl/transcoding/basis_wrappers.cpp`. The JavaScript wrapper supports nearly all features and modes, including texture video. See the README.md and CMakeLists.txt files in `webgl/transcoder` and `webgl/encoder`. To build the WASM transcoder, after installing emscripten: diff --git a/appveyor.yml b/appveyor.yml index 7dd4dcb0..9e35a559 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ --- -image: +image: - macos - Ubuntu2004 - Visual Studio 2019 diff --git a/basisu.manifest b/basisu.manifest index b4baf6b9..324aa6d6 100644 --- a/basisu.manifest +++ b/basisu.manifest @@ -7,4 +7,3 @@ - diff --git a/basisu.vcxproj b/basisu.vcxproj index be377966..fce24bde 100644 --- a/basisu.vcxproj +++ b/basisu.vcxproj @@ -1,4 +1,4 @@ - + @@ -269,4 +269,4 @@ - \ No newline at end of file + diff --git a/basisu.vcxproj.filters b/basisu.vcxproj.filters index 0d865e2a..a772c989 100644 --- a/basisu.vcxproj.filters +++ b/basisu.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/basisu_tool.cpp b/basisu_tool.cpp index 12e4ca39..d3a7cc39 100644 --- a/basisu_tool.cpp +++ b/basisu_tool.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #if _MSC_VER -// For sprintf(), strcpy() +// For sprintf(), strcpy() #define _CRT_SECURE_NO_WARNINGS (1) #pragma warning(disable:4505) // unreferenced function with internal linkage has been removed #pragma warning(disable:4189) // local variable is initialized but not referenced @@ -88,7 +88,7 @@ enum tool_mode static void print_usage() { printf("\nUsage: basisu filename [filename ...] \n"); - + puts("\n" "The default processing mode is compression of one or more .PNG/.BMP/.TGA/.JPG/.QOI/.DDS/.EXR/.HDR files to a LDR or HDR .KTX2 file. Alternate modes:\n" " -unpack: Use transcoder to unpack a .basis/.KTX2 file to one or more .KTX/.PNG files\n" @@ -327,7 +327,7 @@ static bool load_listing_file(const std::string &f, basisu::vector { if (read_filename[0] == ' ') read_filename.erase(0, 1); - else + else break; } @@ -336,7 +336,7 @@ static bool load_listing_file(const std::string &f, basisu::vector const char c = read_filename.back(); if ((c == ' ') || (c == '\n') || (c == '\r')) read_filename.erase(read_filename.size() - 1, 1); - else + else break; } @@ -449,7 +449,7 @@ class command_line_params m_comp_params.m_astc_hdr_6x6_options.m_master_comp_level = minimum(lo_level, hi_level); m_comp_params.m_astc_hdr_6x6_options.m_highest_comp_level = maximum(lo_level, hi_level); - + if (strcasecmp(pArg, "-hdr_6x6_comp_levels") == 0) m_comp_params.set_format_mode(basist::basis_tex_format::cASTC_HDR_6x6); else @@ -539,7 +539,7 @@ class command_line_params m_tonemap_dither_flag(false) { m_comp_params.m_compression_level = basisu::maximum(0, BASISU_DEFAULT_COMPRESSION_LEVEL - 1); - + m_comp_params.m_uastc_hdr_4x4_options.set_quality_level(uastc_hdr_4x4_codec_options::cDefaultLevel); m_test_file_dir = "../test_files"; @@ -559,7 +559,7 @@ class command_line_params print_usage(); exit(EXIT_SUCCESS); } - + if (strcasecmp(pArg, "-ktx2") == 0) { m_ktx2_mode = true; @@ -713,15 +713,15 @@ class command_line_params int uastc_level = atoi(arg_v[arg_index + 1]); uastc_level = clamp(uastc_level, 0, TOTAL_PACK_UASTC_LEVELS - 1); - + static_assert(TOTAL_PACK_UASTC_LEVELS == 5, "TOTAL_PACK_UASTC_LEVELS==5"); static const uint32_t s_level_flags[TOTAL_PACK_UASTC_LEVELS] = { cPackUASTCLevelFastest, cPackUASTCLevelFaster, cPackUASTCLevelDefault, cPackUASTCLevelSlower, cPackUASTCLevelVerySlow }; - + m_comp_params.m_pack_uastc_ldr_4x4_flags &= ~cPackUASTCLevelMask; m_comp_params.m_pack_uastc_ldr_4x4_flags |= s_level_flags[uastc_level]; m_comp_params.m_uastc_hdr_4x4_options.set_quality_level(uastc_level); - + arg_count++; } else if (strcasecmp(pArg, "-resample") == 0) @@ -940,7 +940,7 @@ class command_line_params { REMAINING_ARGS_CHECK(1); m_comp_params.m_mip_filter = arg_v[arg_index + 1]; - // TODO: Check filter + // TODO: Check filter arg_count++; } else if (strcasecmp(pArg, "-mip_renorm") == 0) @@ -1068,7 +1068,7 @@ class command_line_params arg_index += arg_count; assert(arg_index <= arg_c); } - + if (m_comp_params.m_etc1s_quality_level != -1) { m_comp_params.m_etc1s_max_endpoint_clusters = 0; @@ -1090,7 +1090,7 @@ class command_line_params else m_comp_params.m_mip_srgb = false; } - + return true; } @@ -1121,12 +1121,12 @@ class command_line_params new_input_alpha_filenames.push_back(m_input_alpha_filenames[i]); } new_input_alpha_filenames.swap(m_input_alpha_filenames); - + return true; } basis_compressor_params m_comp_params; - + tool_mode m_mode; bool m_ktx2_mode; @@ -1135,7 +1135,7 @@ class command_line_params uint32_t m_ktx2_animdata_duration; uint32_t m_ktx2_animdata_timescale; uint32_t m_ktx2_animdata_loopcount; - + basisu::vector m_input_filenames; basisu::vector m_input_alpha_filenames; @@ -1153,9 +1153,9 @@ class command_line_params std::string m_etc1s_use_global_codebooks_file; std::string m_test_file_dir; - + uint32_t m_max_threads; - + bool m_individual; bool m_no_ktx; bool m_ktx_only; @@ -1172,13 +1172,13 @@ static bool expand_multifile(command_line_params &opts) { if (!opts.m_multifile_printf.size()) return true; - + if (!opts.m_multifile_num) { error_printf("-multifile_printf specified, but not -multifile_num\n"); return false; } - + std::string fmt(opts.m_multifile_printf); // Workaround for MSVC debugger issues. Questionable to leave in here. size_t x = fmt.find_first_of('!'); @@ -1190,15 +1190,15 @@ static bool expand_multifile(command_line_params &opts) error_printf("Must include C-style printf() format character '%%' in -multifile_printf string\n"); return false; } - + for (uint32_t i = opts.m_multifile_first; i < opts.m_multifile_first + opts.m_multifile_num; i++) { char buf[1024]; -#ifdef _WIN32 +#ifdef _WIN32 sprintf_s(buf, sizeof(buf), fmt.c_str(), i); #else snprintf(buf, sizeof(buf), fmt.c_str(), i); -#endif +#endif if (buf[0]) opts.m_input_filenames.push_back(buf); @@ -1209,8 +1209,8 @@ static bool expand_multifile(command_line_params &opts) struct basis_data { - basis_data() : - m_transcoder() + basis_data() : + m_transcoder() { } uint8_vec m_file_data; @@ -1275,7 +1275,7 @@ static bool compress_mode(command_line_params &opts) job_pool compressor_jpool(opts.m_parallel_compression ? 1 : num_threads); if (!opts.m_parallel_compression) opts.m_comp_params.m_pJob_pool = &compressor_jpool; - + if (!expand_multifile(opts)) { error_printf("-multifile expansion failed!\n"); @@ -1287,7 +1287,7 @@ static bool compress_mode(command_line_params &opts) error_printf("No input files to process!\n"); return false; } - + basis_data* pGlobal_codebook_data = nullptr; if (opts.m_etc1s_use_global_codebooks_file.size()) { @@ -1297,7 +1297,7 @@ static bool compress_mode(command_line_params &opts) printf("Loaded global codebooks from .basis file \"%s\"\n", opts.m_etc1s_use_global_codebooks_file.c_str()); } - + basis_compressor_params ¶ms = opts.m_comp_params; if (opts.m_ktx2_mode) @@ -1307,7 +1307,7 @@ static bool compress_mode(command_line_params &opts) params.m_ktx2_uastc_supercompression = basist::KTX2_SS_ZSTANDARD; else params.m_ktx2_uastc_supercompression = basist::KTX2_SS_NONE; - + params.m_ktx2_srgb_transfer_func = opts.m_comp_params.m_perceptual; if (params.m_tex_type == basist::basis_texture_type::cBASISTexTypeVideoFrames) @@ -1319,7 +1319,7 @@ static bool compress_mode(command_line_params &opts) const char* pAD = "KTXanimData"; kv.m_key.resize(strlen(pAD) + 1); strcpy((char*)kv.m_key.data(), pAD); - + basist::ktx2_animdata ad; ad.m_duration = opts.m_ktx2_animdata_duration; ad.m_timescale = opts.m_ktx2_animdata_timescale; @@ -1330,15 +1330,15 @@ static bool compress_mode(command_line_params &opts) params.m_ktx2_key_values.push_back(kv); } - + // TODO- expose this to command line. params.m_ktx2_zstd_supercompression_level = opts.m_ktx2_zstandard_level; } params.m_read_source_images = true; params.m_write_output_basis_or_ktx2_files = true; - params.m_pGlobal_codebooks = pGlobal_codebook_data ? &pGlobal_codebook_data->m_transcoder.get_lowlevel_etc1s_decoder() : nullptr; - + params.m_pGlobal_codebooks = pGlobal_codebook_data ? &pGlobal_codebook_data->m_transcoder.get_lowlevel_etc1s_decoder() : nullptr; + FILE *pCSV_file = nullptr; if (opts.m_csv_file.size()) { @@ -1354,7 +1354,7 @@ static bool compress_mode(command_line_params &opts) } printf("Processing %u total file(s)\n", (uint32_t)opts.m_input_filenames.size()); - + interval_timer all_tm; all_tm.start(); @@ -1403,7 +1403,7 @@ static bool compress_mode(command_line_params &opts) params.m_source_filenames = opts.m_input_filenames; params.m_source_alpha_filenames = opts.m_input_alpha_filenames; } - + if (opts.m_output_filename.size()) params.m_out_filename = opts.m_output_filename; else @@ -1591,7 +1591,7 @@ static bool compress_mode(command_line_params &opts) comp_params_vec, results); BASISU_NOTE_UNUSED(any_failed); - + for (uint32_t i = 0; i < comp_params_vec.size(); i++) { if (results[i].m_error_code != basis_compressor::cECSuccess) @@ -1600,8 +1600,8 @@ static bool compress_mode(command_line_params &opts) total_failures++; - error_printf("File %u (first source image: \"%s\", output file: \"%s\") failed with error code %i!\n", i, - comp_params_vec[i].m_source_filenames[0].c_str(), + error_printf("File %u (first source image: \"%s\", output file: \"%s\") failed with error code %i!\n", i, + comp_params_vec[i].m_source_filenames[0].c_str(), comp_params_vec[i].m_out_filename.c_str(), (int)results[i].m_error_code); } @@ -1610,11 +1610,11 @@ static bool compress_mode(command_line_params &opts) total_successes++; } } - + } // if (opts.m_parallel_compression) printf("Total successes: %u failures: %u\n", total_successes, total_failures); - + all_tm.stop(); if (total_files > 1) @@ -1625,7 +1625,7 @@ static bool compress_mode(command_line_params &opts) fclose(pCSV_file); pCSV_file = nullptr; } - delete pGlobal_codebook_data; + delete pGlobal_codebook_data; pGlobal_codebook_data = nullptr; return result; @@ -1666,7 +1666,7 @@ static bool unpack_and_validate_ktx2_file( error_printf("ktx2_transcoder::start_transcoding() failed! File either uses an unsupported feature, is invalid, was corrupted, or this is a bug.\n"); return false; } - + printf("Resolution: %ux%u\n", dec.get_width(), dec.get_height()); fmt_printf("Block size: {}x{}\n", dec.get_block_width(), dec.get_block_height()); printf("Mipmap Levels: %u\n", dec.get_levels()); @@ -1676,9 +1676,9 @@ static bool unpack_and_validate_ktx2_file( if (dec.is_hdr()) fmt_printf("LDR to HDR upconversion nit multiplier: {}\n", dec.get_ldr_hdr_upconversion_nit_multiplier()); - + const bool is_etc1s = (dec.get_basis_tex_format() == basist::basis_tex_format::cETC1S); - + bool is_hdr = false; const char* pFmt_str = nullptr; @@ -1720,7 +1720,7 @@ static bool unpack_and_validate_ktx2_file( } printf("Supercompression Format: %s\n", pFmt_str); - + printf("Supercompression Scheme: "); switch (dec.get_header().m_supercompression_scheme) { @@ -1733,9 +1733,9 @@ static bool unpack_and_validate_ktx2_file( } printf("Has Alpha: %u\n", (uint32_t)dec.get_has_alpha()); - + printf("\nKTX2 header vk_format: 0x%X (decimal %u)\n", (uint32_t)dec.get_header().m_vk_format, (uint32_t)dec.get_header().m_vk_format); - + printf("\nData Format Descriptor (DFD):\n"); printf("DFD length in bytes: %zu\n", dec.get_dfd().size()); printf("DFD color model: %u\n", dec.get_dfd_color_model()); @@ -1752,7 +1752,7 @@ static bool unpack_and_validate_ktx2_file( } else printf("DFD chan0: %s\n", basist::ktx2_get_uastc_df_channel_id_str(dec.get_dfd_channel_id0())); - + printf("DFD hex values:\n"); for (uint32_t i = 0; i < dec.get_dfd().size(); i++) { @@ -1772,13 +1772,13 @@ static bool unpack_and_validate_ktx2_file( if (dec.get_key_values()[i].m_value.size() > 256) continue; - + bool is_ascii = true; for (uint32_t j = 0; j < dec.get_key_values()[i].m_value.size(); j++) { uint8_t c = dec.get_key_values()[i].m_value[j]; - if (!( - ((c >= ' ') && (c < 0x80)) || + if (!( + ((c >= ' ') && (c < 0x80)) || ((j == dec.get_key_values()[i].m_value.size() - 1) && (!c)) )) { @@ -1851,10 +1851,10 @@ static bool unpack_and_validate_ktx2_file( error_printf("Failed retrieving image level information (%u %u %u)!\n", layer_index, level_index, face_index); return false; } - + fmt_printf("--- Level Index: {}, Layer Index: {}, Face Index: {}\n", level_info.m_level_index, level_info.m_layer_index, level_info.m_face_index); - + fmt_printf("Orig width/height: {}x{}\n", level_info.m_orig_width, level_info.m_orig_height); fmt_printf("Width/height: {}x{}\n", level_info.m_width, level_info.m_height); fmt_printf("Block width/height: {}x{}\n", level_info.m_block_width, level_info.m_block_height); @@ -1883,7 +1883,7 @@ static bool unpack_and_validate_ktx2_file( first_format = opts.m_format_only; last_format = first_format + 1; } - + for (int format_iter = first_format; format_iter < last_format; format_iter++) { basist::transcoder_texture_format tex_fmt = static_cast(format_iter); @@ -1966,7 +1966,7 @@ static bool unpack_and_validate_ktx2_file( double total_time = tm.get_elapsed_ms(); - printf("Transcode of layer %u level %u face %u res %ux%u format %s succeeded in %3.3f ms\n", layer_index, level_index, face_index, + printf("Transcode of layer %u level %u face %u res %ux%u format %s succeeded in %3.3f ms\n", layer_index, level_index, face_index, level_info.m_orig_width, level_info.m_orig_height, basist::basis_get_format_name(transcoder_tex_fmt), total_time); } @@ -1987,7 +1987,7 @@ static bool unpack_and_validate_ktx2_file( const bool is_mipmapped = dec.get_levels() > 1; BASISU_NOTE_UNUSED(is_cubemap_array); BASISU_NOTE_UNUSED(is_mipmapped); - + // The maximum Direct3D array size is 2048. const uint32_t MAX_DDS_TEXARRAY_SIZE = 2048; @@ -1995,7 +1995,7 @@ static bool unpack_and_validate_ktx2_file( { const basist::transcoder_texture_format transcoder_tex_fmt = static_cast(format_iter); const basisu::texture_format tex_fmt = basis_get_basisu_texture_format(transcoder_tex_fmt); - + if (basist::basis_transcoder_format_is_uncompressed(transcoder_tex_fmt)) continue; if (!basis_is_format_supported(transcoder_tex_fmt, dec.get_basis_tex_format())) @@ -2004,7 +2004,7 @@ static bool unpack_and_validate_ktx2_file( continue; // TODO: Could write DDS texture arrays. - + // No KTX tool that we know of supports cubemap arrays, so write individual cubemap files for each layer. if ((!opts.m_no_ktx) && (is_cubemap)) { @@ -2025,7 +2025,7 @@ static bool unpack_and_validate_ktx2_file( } printf("Wrote .KTX cubemap file \"%s\"\n", ktx_filename.c_str()); } - + if (does_dds_support_format(cubemap[0][0].get_format())) { std::string dds_filename(base_filename + string_format("_transcoded_cubemap_%s_layer_%u.dds", basist::basis_get_format_name(transcoder_tex_fmt), layer_index)); @@ -2226,7 +2226,7 @@ static bool unpack_and_validate_ktx2_file( } printf("Wrote .PNG file \"%s\"\n", rgba_filename.c_str()); } - + } // is_hdr } // level_index @@ -2275,8 +2275,8 @@ static bool unpack_and_validate_ktx2_file( double total_transcode_time = tm.get_elapsed_ms(); - fmt_printf("Transcode of level {} layer {} face {} res {}x{} format {} succeeded in {} ms\n", - level_index, layer_index, face_index, + fmt_printf("Transcode of level {} layer {} face {} res {}x{} format {} succeeded in {} ms\n", + level_index, layer_index, face_index, level_info.m_orig_width, level_info.m_orig_height, basist::basis_get_format_name(transcoder_tex_fmt), total_transcode_time); if ((!validate_flag) && (!opts.m_ktx_only)) @@ -2299,7 +2299,7 @@ static bool unpack_and_validate_ktx2_file( } } // face_index - } // layer_index + } // layer_index } // level_index // RGB HALF @@ -2360,7 +2360,7 @@ static bool unpack_and_validate_ktx2_file( } } // face_index - } // layer_index + } // layer_index } // level_index // RGB HALF @@ -2420,9 +2420,9 @@ static bool unpack_and_validate_ktx2_file( } } // face_index - } // layer_index + } // layer_index } // level_index - + } else { @@ -2437,7 +2437,7 @@ static bool unpack_and_validate_basis_file( uint32_t file_index, const std::string &base_filename, uint8_vec &basis_file_data, - command_line_params& opts, + command_line_params& opts, FILE *pCSV_file, basis_data* pGlobal_codebook_data, uint32_t &total_unpack_warnings, @@ -2460,7 +2460,7 @@ static bool unpack_and_validate_basis_file( if (!dec.validate_file_checksums(&basis_file_data[0], (uint32_t)basis_file_data.size(), true)) { error_printf("File version is unsupported, or file failed one or more CRC checks!\n"); - + return false; } } @@ -2489,7 +2489,7 @@ static bool unpack_and_validate_basis_file( fmt_printf(" Block Dimensions: {}x{}\n", fileinfo.m_block_width, fileinfo.m_block_height); bool is_hdr = false; - + const char* pFmt_str = nullptr; switch (fileinfo.m_tex_format) { @@ -2529,7 +2529,7 @@ static bool unpack_and_validate_basis_file( } fmt_printf(" Texture format: {}\n", pFmt_str); - + printf(" Texture type: %s\n", basist::basis_get_texture_type_name(fileinfo.m_tex_type)); printf(" us per frame: %u (%f fps)\n", fileinfo.m_us_per_frame, fileinfo.m_us_per_frame ? (1.0f / ((float)fileinfo.m_us_per_frame / 1000000.0f)) : 0.0f); printf(" Total slices: %u\n", (uint32_t)fileinfo.m_slice_info.size()); @@ -2623,7 +2623,7 @@ static bool unpack_and_validate_basis_file( printf("start_transcoding time: %3.3f ms\n", start_transcoding_time_ms); basisu::vector< gpu_image_vec > gpu_images[(int)basist::transcoder_texture_format::cTFTotalTextureFormats]; - + double total_format_transcoding_time_ms[(int)basist::transcoder_texture_format::cTFTotalTextureFormats]; clear_obj(total_format_transcoding_time_ms); @@ -2763,11 +2763,11 @@ static bool unpack_and_validate_basis_file( // Fill the buffer with psuedo-random bytes, to help more visibly detect cases where the transcoder fails to write to part of the output. fill_buffer_with_random_bytes(gi.get_ptr(), gi.get_size_in_bytes()); - + tm.start(); if (!dec.transcode_slice( - &basis_file_data[0], (uint32_t)basis_file_data.size(), + &basis_file_data[0], (uint32_t)basis_file_data.size(), level_info.m_first_slice_index, gi.get_ptr(), gi.get_total_blocks(), basist::block_format::cUASTC_4x4, gi.get_bytes_per_block())) { error_printf("Failed transcoding image level (%u %u) to UASTC!\n", image_index, level_index); @@ -3012,7 +3012,7 @@ static bool unpack_and_validate_basis_file( } printf("Wrote .PNG file \"%s\"\n", rgba_filename.c_str()); } - + } // is_hdr } // level_index @@ -3052,7 +3052,7 @@ static bool unpack_and_validate_basis_file( tm.start(); - if (!dec.transcode_image_level(&basis_file_data[0], (uint32_t)basis_file_data.size(), image_index, level_index, + if (!dec.transcode_image_level(&basis_file_data[0], (uint32_t)basis_file_data.size(), image_index, level_index, half_img.get_ptr(), total_pixels, transcoder_tex_fmt, 0, level_info.m_orig_width, nullptr, level_info.m_orig_height)) { error_printf("Failed transcoding image level (%u %u %u)!\n", image_index, level_index, transcoder_tex_fmt); @@ -3391,7 +3391,7 @@ static bool unpack_and_validate_basis_file( } // level_index } // image_index - + } // is_hdr } // if ((opts.m_format_only == -1) && (!validate_flag)) @@ -3432,7 +3432,7 @@ static bool unpack_and_validate_mode(command_line_params &opts) tm.start(); //const bool validate_flag = (opts.m_mode == cValidate); - + basis_data* pGlobal_codebook_data = nullptr; if (opts.m_etc1s_use_global_codebooks_file.size()) { @@ -3499,7 +3499,7 @@ static bool unpack_and_validate_mode(command_line_params &opts) delete pGlobal_codebook_data; pGlobal_codebook_data = nullptr; return false; } - + bool is_ktx2 = false; if (file_data.size() >= sizeof(basist::g_ktx2_file_identifier)) { @@ -3536,10 +3536,10 @@ static bool unpack_and_validate_mode(command_line_params &opts) if (!status) { - if (pCSV_file) + if (pCSV_file) fclose(pCSV_file); - delete pGlobal_codebook_data; + delete pGlobal_codebook_data; pGlobal_codebook_data = nullptr; return false; @@ -3562,7 +3562,7 @@ static bool unpack_and_validate_mode(command_line_params &opts) fclose(pCSV_file); pCSV_file = nullptr; } - delete pGlobal_codebook_data; + delete pGlobal_codebook_data; pGlobal_codebook_data = nullptr; return true; @@ -3608,7 +3608,7 @@ static bool hdr_compare_mode(command_line_params& opts) printf("Comparison image res: %ux%u\n", a.get_width(), a.get_height()); image_metrics im; - + im.calc_half(a, b, 0, 1, true); im.print("R "); @@ -3700,7 +3700,7 @@ static bool compare_mode(command_line_params &opts) im.calc(a, b, 0, 0, true, true); im.print("Y 601 " ); - + if (opts.m_compare_ssim) { vec4F s_rgb(compute_ssim(a, b, false, false)); @@ -3743,7 +3743,7 @@ static bool compare_mode(command_line_params &opts) save_png("delta_img_rgb.png", delta_img, cImageSaveIgnoreAlpha); printf("Wrote delta_img_rgb.png\n"); - + save_png("delta_img_a.png", delta_img, cImageSaveGrayscale, 3); printf("Wrote delta_img_a.png\n"); @@ -3925,7 +3925,7 @@ static bool compare_mode(command_line_params &opts) } } // display_plot - + return true; } @@ -3964,7 +3964,7 @@ static bool split_image_mode(command_line_params& opts) } printf("Wrote file %s\n", buf); } - + return true; } @@ -4009,7 +4009,7 @@ static bool combine_images_mode(command_line_params& opts) const char* pOutput_filename = "combined.png"; if (opts.m_output_filename.size()) pOutput_filename = opts.m_output_filename.c_str(); - + if (!save_png(pOutput_filename, combined_img)) { fprintf(stderr, "Failed writing file %s\n", pOutput_filename); @@ -4051,7 +4051,7 @@ static bool tonemap_image_mode(command_line_params& opts) string_combine_path(output_filename, opts.m_output_path.c_str(), output_filename.c_str()); const char* pBasename = output_filename.c_str(); - + image srgb_img(width, height); image lin_img(width, height); @@ -4064,7 +4064,7 @@ static bool tonemap_image_mode(command_line_params& opts) p[0] = clamp(p[0], 0.0f, 1.0f); p[1] = clamp(p[1], 0.0f, 1.0f); p[2] = clamp(p[2], 0.0f, 1.0f); - + { int rc = (int)std::round(linear_to_srgb(p[0]) * 255.0f); int gc = (int)std::round(linear_to_srgb(p[1]) * 255.0f); @@ -4116,7 +4116,7 @@ static bool tonemap_image_mode(command_line_params& opts) for (int e = -6; e <= 6; e++) { const float scale = powf(2.0f, (float)e); - + tonemap_image_reinhard(tonemapped_img, hdr_img, scale, opts.m_tonemap_dither_flag); std::string filename(string_format("%s_reinhard_tonemapped_scale_%f.png", pBasename, scale)); @@ -4183,10 +4183,10 @@ const struct test_file uint32_t m_etc1s_size; float m_etc1s_psnr; float m_uastc_psnr; - + uint32_t m_etc1s_128_size; float m_etc1s_128_psnr; -} g_test_files[] = +} g_test_files[] = { { "black_1x1.png", 189, 100.0f, 100.0f, 189, 100.0f }, { "kodim01.png", 30993, 27.40f, 44.14f, 58354, 30.356064f }, @@ -4264,7 +4264,7 @@ static bool test_mode_ldr(command_line_params& opts) // Test ETC1S flags_and_quality = (opts.m_comp_params.m_multithreading ? cFlagThreaded : 0) | cFlagPrintStats | cFlagPrintStatus; - + { printf("**** Testing ETC1S non-OpenCL level 1\n"); @@ -4475,7 +4475,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te fmt_printf("test_mode_hdr: Testing bais_tex_format {}, lambda {}\n", (uint32_t)tex_fmt, lambda); uint32_t total_mismatches = 0; - + #ifdef USE_TIGHTER_TEST_TOLERANCES // The PSNR's above were created with a MSVC compiled executable, x64. Hopefully this is not too low a threshold. const float PSNR_THRESHOLD = .125f; @@ -4483,7 +4483,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te // Minor differences in how floating point code is optimized can result in slightly different generated files. const float PSNR_THRESHOLD = .3f; #endif - + double highest_delta = 0.0f; // TODO: This doesn't test all 6x6 levels, but that's fine for now. @@ -4509,7 +4509,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te } printf("Loaded file \"%s\", dimemsions %ux%u\n", filename.c_str(), source_image.get_width(), source_image.get_height()); - + for (uint32_t uastc_hdr_level = 0; uastc_hdr_level <= MAX_ASTC_HDR_4x4_TEST_LEVEL; uastc_hdr_level++) { image_stats stats; @@ -4523,7 +4523,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te flags_and_quality |= uastc_hdr_level; void* pData = basis_compress(tex_fmt, - source_imagesf, flags_and_quality, lambda, + source_imagesf, flags_and_quality, lambda, &data_size, &stats); if (!pData) { @@ -4534,7 +4534,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te double delta1, delta2; - printf("ASTC PSNR: %f (expected %f, delta %f), BC6H PSNR: %f (expected %f, delta %f)\n", + printf("ASTC PSNR: %f (expected %f, delta %f), BC6H PSNR: %f (expected %f, delta %f)\n", stats.m_basis_rgb_avg_log2_psnr, pTest_files[i].m_level_psnr_astc[uastc_hdr_level], delta1 = fabs(stats.m_basis_rgb_avg_log2_psnr - pTest_files[i].m_level_psnr_astc[uastc_hdr_level]), stats.m_basis_rgb_avg_bc6h_log2_psnr, pTest_files[i].m_level_psnr_bc6h[uastc_hdr_level], delta2 = fabs(stats.m_basis_rgb_avg_bc6h_log2_psnr - pTest_files[i].m_level_psnr_bc6h[uastc_hdr_level])); @@ -4608,7 +4608,7 @@ static bool test_mode_hdr(command_line_params& opts, basist::basis_tex_format te static bool clbench_mode(command_line_params& opts) { BASISU_NOTE_UNUSED(opts); - + bool opencl_failed = false; bool use_cl = basis_benchmark_etc1s_opencl(&opencl_failed); if (use_cl) @@ -4641,7 +4641,7 @@ static void force_san_failure() static int main_internal(int argc, const char **argv) { - printf("Basis Universal LDR/HDR GPU Texture Compression and Transcoding System v" BASISU_TOOL_VERSION + printf("Basis Universal LDR/HDR GPU Texture Compression and Transcoding System v" BASISU_TOOL_VERSION #if defined(_ARM64EC_) || defined(_ARM64_) " (ARM64)" #elif defined(_M_IX86) @@ -4661,7 +4661,7 @@ static int main_internal(int argc, const char **argv) // See if OpenCL support has been disabled. We don't want to parse the command line until the lib is initialized bool use_opencl = false; bool opencl_force_serialization = false; - + for (int i = 1; i < argc; i++) { if ((strcmp(argv[i], "-opencl") == 0) || (strcmp(argv[i], "-clbench") == 0)) @@ -4676,17 +4676,17 @@ static int main_internal(int argc, const char **argv) fprintf(stderr, "WARNING: -opencl specified, but OpenCL support was not enabled at compile time! With cmake, use -D OPENCL=1. Falling back to CPU compression.\n"); } #endif - + basisu_encoder_init(use_opencl, opencl_force_serialization); //printf("Encoder and transcoder libraries initialized in %3.3f ms\n", tm.get_elapsed_ms()); - + if (argc == 1) { print_usage(); return EXIT_FAILURE; } - + command_line_params opts; if (!opts.parse(argc, argv)) { @@ -4699,7 +4699,7 @@ static int main_internal(int argc, const char **argv) #else printf("No SSE, Multithreading: %u, Zstandard support: %u, OpenCL: %u\n", (uint32_t)opts.m_comp_params.m_multithreading, basist::basisu_transcoder_supports_ktx2_zstd(), opencl_is_available()); #endif - + if (!opts.process_listing_files()) return EXIT_FAILURE; @@ -4756,7 +4756,7 @@ static int main_internal(int argc, const char **argv) break; case cTestHDR_6x6i: status = test_mode_hdr(opts, basist::basis_tex_format::cASTC_HDR_6x6_INTERMEDIATE, std::size(g_hdr_6x6i_test_files), g_hdr_6x6i_test_files, 0.0f); - + if (status) { status = test_mode_hdr(opts, basist::basis_tex_format::cASTC_HDR_6x6_INTERMEDIATE, std::size(g_hdr_6x6i_l_test_files), g_hdr_6x6i_l_test_files, 500.0f); @@ -4786,7 +4786,7 @@ static int main_internal(int argc, const char **argv) //----------------------------------------------------------------------------------- #if CLEAR_WIN32_CONSOLE -void clear_console() +void clear_console() { //if (!IsDebuggerPresent()) // return; @@ -4828,7 +4828,7 @@ int main(int argc, const char** argv) #ifdef __SANITIZE_ADDRESS__ printf("Address sanitizer enabled\n"); #endif - + int status = EXIT_FAILURE; #if BASISU_CATCH_EXCEPTIONS @@ -4850,4 +4850,3 @@ int main(int argc, const char** argv) return status; } - diff --git a/bin/ocl_kernels.cl b/bin/ocl_kernels.cl index 6eda24f1..d9fa1feb 100644 --- a/bin/ocl_kernels.cl +++ b/bin/ocl_kernels.cl @@ -112,7 +112,7 @@ uint color_distance(bool perceptual, color_rgba e1, color_rgba e2, bool alpha) int da = (e1.w - e2.w) << 7; id += ((uint)(da * da) >> 7U); } - + return id; #endif } @@ -120,7 +120,7 @@ uint color_distance(bool perceptual, color_rgba e1, color_rgba e2, bool alpha) { int dr = e1.x - e2.x; int dg = e1.y - e2.y; - int db = e1.z - e2.z; + int db = e1.z - e2.z; int da = e1.w - e2.w; return dr * dr + dg * dg + db * db + da * da; } @@ -128,7 +128,7 @@ uint color_distance(bool perceptual, color_rgba e1, color_rgba e2, bool alpha) { int dr = e1.x - e2.x; int dg = e1.y - e2.y; - int db = e1.z - e2.z; + int db = e1.z - e2.z; return dr * dr + dg * dg + db * db; } } @@ -137,7 +137,7 @@ typedef struct __attribute__ ((packed)) etc_block_tag { // big endian uint64: // bit ofs: 56 48 40 32 24 16 8 0 - // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 + // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 union { uint64_t m_uint64; @@ -252,7 +252,7 @@ constant int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] constant uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; constant uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 }; -uint32_t etc_block_get_byte_bits(const etc_block *p, uint32_t ofs, uint32_t num) +uint32_t etc_block_get_byte_bits(const etc_block *p, uint32_t ofs, uint32_t num) { assert((ofs + num) <= 64U); assert(num && (num <= 8U)); @@ -275,7 +275,7 @@ void etc_block_set_byte_bits(etc_block *p, uint32_t ofs, uint32_t num, uint32_t p->m_bytes[byte_ofs] |= (bits << byte_bit_ofs); } -bool etc_block_get_flip_bit(const etc_block *p) +bool etc_block_get_flip_bit(const etc_block *p) { return (p->m_bytes[3] & 1) != 0; } @@ -286,7 +286,7 @@ void etc_block_set_flip_bit(etc_block *p, bool flip) p->m_bytes[3] |= (uint8_t)(flip); } -bool etc_block_get_diff_bit(const etc_block *p) +bool etc_block_get_diff_bit(const etc_block *p) { return (p->m_bytes[3] & 2) != 0; } @@ -299,7 +299,7 @@ void etc_block_set_diff_bit(etc_block *p, bool diff) // Returns intensity modifier table (0-7) used by subblock subblock_id. // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2) -uint32_t etc_block_get_inten_table(const etc_block *p, uint32_t subblock_id) +uint32_t etc_block_get_inten_table(const etc_block *p, uint32_t subblock_id) { assert(subblock_id < 2); const uint32_t ofs = subblock_id ? 2 : 5; @@ -322,7 +322,7 @@ void etc_block_set_inten_tables_etc1s(etc_block *p, uint32_t t) etc_block_set_inten_table(p, 1, t); } -uint32_t etc_block_get_raw_selector(const etc_block *pBlock, uint32_t x, uint32_t y) +uint32_t etc_block_get_raw_selector(const etc_block *pBlock, uint32_t x, uint32_t y) { assert((x | y) < 4); @@ -337,7 +337,7 @@ uint32_t etc_block_get_raw_selector(const etc_block *pBlock, uint32_t x, uint32_ } // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables. -uint32_t etc_block_get_selector(const etc_block *pBlock, uint32_t x, uint32_t y) +uint32_t etc_block_get_selector(const etc_block *pBlock, uint32_t x, uint32_t y) { return g_etc1_to_selector_index[etc_block_get_raw_selector(pBlock, x, y)]; } @@ -354,7 +354,7 @@ void etc_block_set_selector(etc_block *pBlock, uint32_t x, uint32_t y, uint32_t const uint32_t mask = 1 << byte_bit_ofs; const uint32_t etc1_val = g_selector_index_to_etc1[val]; - + const uint32_t lsb = etc1_val & 1; const uint32_t msb = etc1_val >> 1; @@ -381,7 +381,7 @@ void etc_block_set_base4_color(etc_block *pBlock, uint32_t idx, uint16_t c) } } -uint16_t etc_block_get_base4_color(const etc_block *pBlock, uint32_t idx) +uint16_t etc_block_get_base4_color(const etc_block *pBlock, uint32_t idx) { uint32_t r, g, b; if (idx) @@ -421,7 +421,7 @@ void etc_block_set_delta3_color(etc_block *pBlock, uint16_t c) etc_block_set_byte_bits(pBlock, cETC1DeltaColor3BBitOffset, 3, c & 7); } -uint16_t etc_block_get_delta3_color(const etc_block *pBlock) +uint16_t etc_block_get_delta3_color(const etc_block *pBlock) { const uint32_t r = etc_block_get_byte_bits(pBlock, cETC1DeltaColor3RBitOffset, 3); const uint32_t g = etc_block_get_byte_bits(pBlock, cETC1DeltaColor3GBitOffset, 3); @@ -504,7 +504,7 @@ color_rgba etc_block_unpack_color4(uint16_t packed_color4, bool scaled, uint32_t } // false if didn't clamp, true if any component clamped -bool etc_block_get_block_colors(const etc_block *pBlock, color_rgba* pBlock_colors, uint32_t subblock_index) +bool etc_block_get_block_colors(const etc_block *pBlock, color_rgba* pBlock_colors, uint32_t subblock_index) { color_rgba b; @@ -530,7 +530,7 @@ bool etc_block_get_block_colors(const etc_block *pBlock, color_rgba* pBlock_colo return dc; } -void get_block_colors5(color_rgba *pBlock_colors, const color_rgba *pBase_color5, uint32_t inten_table, bool scaled /* false */) +void get_block_colors5(color_rgba *pBlock_colors, const color_rgba *pBase_color5, uint32_t inten_table, bool scaled /* false */) { color_rgba b = *pBase_color5; @@ -695,7 +695,7 @@ void etc_block_set_block_color5(etc_block *pBlock, color_rgba c0_unscaled, color void etc_block_set_block_color5_etc1s(etc_block *pBlock, color_rgba c_unscaled) { etc_block_set_diff_bit(pBlock, true); - + etc_block_set_base5_color(pBlock, etc_block_pack_color5(c_unscaled, false)); etc_block_set_delta3_color(pBlock, etc_block_pack_delta3(0, 0, 0)); } @@ -729,9 +729,9 @@ void etc_block_pack_raw_selectors(etc_block *pBlock, const uint8_t *pSelectors) { const uint32_t bit_index = x * 4 + y; const uint32_t s = pSelectors[x + y * 4]; - + const uint32_t lsb = s & 1, msb = s >> 1; - + word3 |= (lsb << bit_index); word2 |= (msb << bit_index); } @@ -764,14 +764,14 @@ typedef struct etc1s_optimizer_solution_coordinates_tag uint32_t m_inten_table; } etc1s_optimizer_solution_coordinates; -color_rgba get_scaled_color(color_rgba unscaled_color) +color_rgba get_scaled_color(color_rgba unscaled_color) { int br, bg, bb; - + br = (unscaled_color.x >> 2) | (unscaled_color.x << 3); bg = (unscaled_color.y >> 2) | (unscaled_color.y << 3); bb = (unscaled_color.z >> 2) | (unscaled_color.z << 3); - + return (color_rgba)((uint8_t)br, (uint8_t)bg, (uint8_t)bb, 255); } @@ -779,7 +779,7 @@ typedef struct etc1s_optimizer_potential_solution_tag { uint64_t m_error; etc1s_optimizer_solution_coordinates m_coords; - + uint8_t m_selectors[16]; bool m_valid; } etc1s_optimizer_potential_solution; @@ -795,20 +795,20 @@ typedef struct etc1s_optimizer_state_tag bool etc1s_optimizer_evaluate_solution( etc1s_optimizer_state *pState, const global encode_etc1s_param_struct *pParams, - uint64_t num_pixels, const global color_rgba *pPixels, + uint64_t num_pixels, const global color_rgba *pPixels, const global uint32_t *pWeights, - etc1s_optimizer_solution_coordinates coords, - etc1s_optimizer_potential_solution* pTrial_solution, + etc1s_optimizer_solution_coordinates coords, + etc1s_optimizer_potential_solution* pTrial_solution, etc1s_optimizer_potential_solution* pBest_solution) { uint8_t temp_selectors[16]; pTrial_solution->m_valid = false; - + const color_rgba base_color = get_scaled_color(coords.m_unscaled_color); - + pTrial_solution->m_error = INT64_MAX; - + for (uint32_t inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++) { // TODO: This check is equivalent to medium quality in the C++ version. @@ -825,7 +825,7 @@ bool etc1s_optimizer_evaluate_solution( } uint64_t total_error = 0; - + for (uint64_t c = 0; c < num_pixels; c++) { color_rgba src_pixel = pPixels[c]; @@ -858,7 +858,7 @@ bool etc1s_optimizer_evaluate_solution( temp_selectors[c] = (uint8_t)(best_selector_index); total_error += pWeights ? (best_error * (uint64_t)pWeights[c]) : best_error; - + if (total_error >= pTrial_solution->m_error) break; } @@ -886,23 +886,23 @@ bool etc1s_optimizer_evaluate_solution( success = true; } } - + return success; } void etc1s_optimizer_init( etc1s_optimizer_state *pState, const global encode_etc1s_param_struct *pParams, - uint64_t num_pixels, const global color_rgba *pPixels, + uint64_t num_pixels, const global color_rgba *pPixels, const global uint32_t *pWeights) { const int LIMIT = 31; - + color_rgba min_color = 255; color_rgba max_color = 0; uint64_t total_weight = 0; uint64_t sum_r = 0, sum_g = 0, sum_b = 0; - + for (uint64_t i = 0; i < num_pixels; i++) { const color_rgba c = pPixels[i]; @@ -917,7 +917,7 @@ void etc1s_optimizer_init( sum_r += weight * c.x; sum_g += weight * c.y; sum_b += weight * c.z; - + total_weight += weight; } else @@ -929,7 +929,7 @@ void etc1s_optimizer_init( total_weight++; } } - + float3 avg_color; avg_color.x = (float)sum_r / total_weight; avg_color.y = (float)sum_g / total_weight; @@ -937,7 +937,7 @@ void etc1s_optimizer_init( pState->m_avg_color = avg_color; pState->m_max_comp_spread = max(max((int)max_color.x - (int)min_color.x, (int)max_color.y - (int)min_color.y), (int)max_color.z - (int)min_color.z); - + // TODO: The rounding here could be improved, like with DXT1/BC1. pState->m_br = clamp((int)(avg_color.x * (LIMIT / 255.0f) + .5f), 0, LIMIT); pState->m_bg = clamp((int)(avg_color.y * (LIMIT / 255.0f) + .5f), 0, LIMIT); @@ -961,7 +961,7 @@ void etc1s_optimizer_internal_cluster_fit( etc1s_optimizer_solution_coordinates cur_coords; cur_coords.m_unscaled_color = (color_rgba)(pState->m_br, pState->m_bg, pState->m_bb, 255); etc1s_optimizer_evaluate_solution(pState, pParams, num_pixels, pPixels, pWeights, cur_coords, &trial_solution, &pState->m_best_solution); - + if (pState->m_best_solution.m_error == 0) return; @@ -993,11 +993,11 @@ void etc1s_optimizer_internal_cluster_fit( const int br1 = clamp((int)((pState->m_avg_color.x - avg_delta_r_f) * (LIMIT / 255.0f) + .5f), 0, LIMIT); const int bg1 = clamp((int)((pState->m_avg_color.y - avg_delta_g_f) * (LIMIT / 255.0f) + .5f), 0, LIMIT); const int bb1 = clamp((int)((pState->m_avg_color.z - avg_delta_b_f) * (LIMIT / 255.0f) + .5f), 0, LIMIT); - + cur_coords.m_unscaled_color = (color_rgba)(br1, bg1, bb1, 255); etc1s_optimizer_evaluate_solution(pState, pParams, num_pixels, pPixels, pWeights, cur_coords, &trial_solution, &pState->m_best_solution); - + if (pState->m_best_solution.m_error == 0) break; } @@ -1005,24 +1005,24 @@ void etc1s_optimizer_internal_cluster_fit( // Encode an ETC1S block given a 4x4 pixel block. kernel void encode_etc1s_blocks( - const global encode_etc1s_param_struct *pParams, + const global encode_etc1s_param_struct *pParams, const global pixel_block *pInput_blocks, global etc_block *pOutput_blocks) { const uint32_t block_index = get_global_id(0); - + const global pixel_block *pInput_block = &pInput_blocks[block_index]; etc1s_optimizer_state state; etc1s_optimizer_init(&state, pParams, 16, pInput_block->m_pixels, NULL); etc1s_optimizer_internal_cluster_fit(pParams->m_total_perms, &state, pParams, 16, pInput_block->m_pixels, NULL); - + etc_block blk; etc_block_set_flip_bit(&blk, true); etc_block_set_block_color5_etc1s(&blk, state.m_best_solution.m_coords.m_unscaled_color); etc_block_set_inten_tables_etc1s(&blk, state.m_best_solution.m_coords.m_inten_table); etc_block_pack_raw_selectors(&blk, state.m_best_solution.m_selectors); - + pOutput_blocks[block_index] = blk; } @@ -1034,14 +1034,14 @@ typedef struct __attribute__ ((packed)) pixel_cluster_tag // Determine the optimal ETC1S color5/intensity given an arbitrary large array of 4x4 input pixel blocks. kernel void encode_etc1s_from_pixel_cluster( - const global encode_etc1s_param_struct *pParams, + const global encode_etc1s_param_struct *pParams, const global pixel_cluster *pInput_pixel_clusters, const global color_rgba *pInput_pixels, const global uint32_t *pInput_weights, global etc_block *pOutput_blocks) { const uint32_t cluster_index = get_global_id(0); - + const global pixel_cluster *pInput_cluster = &pInput_pixel_clusters[cluster_index]; uint64_t total_pixels = pInput_cluster->m_total_pixels; @@ -1051,12 +1051,12 @@ kernel void encode_etc1s_from_pixel_cluster( etc1s_optimizer_state state; etc1s_optimizer_init(&state, pParams, total_pixels, pPixels, pWeights); etc1s_optimizer_internal_cluster_fit(pParams->m_total_perms, &state, pParams, total_pixels, pPixels, pWeights); - + etc_block blk; etc_block_set_flip_bit(&blk, true); etc_block_set_block_color5_etc1s(&blk, state.m_best_solution.m_coords.m_unscaled_color); etc_block_set_inten_tables_etc1s(&blk, state.m_best_solution.m_coords.m_inten_table); - + pOutput_blocks[cluster_index] = blk; } @@ -1084,7 +1084,7 @@ typedef struct __attribute__ ((packed)) rec_param_struct_tag // For each input block: find the best endpoint cluster that encodes it. kernel void refine_endpoint_clusterization( - const rec_param_struct params, + const rec_param_struct params, const global pixel_block *pInput_blocks, const global rec_block_struct *pInput_block_info, const global rec_endpoint_cluster_struct *pInput_clusters, @@ -1096,7 +1096,7 @@ kernel void refine_endpoint_clusterization( const int perceptual = params.m_perceptual; const global pixel_block *pInput_block = &pInput_blocks[block_index]; - + pixel_block priv_pixel_block; priv_pixel_block = *pInput_block; @@ -1104,7 +1104,7 @@ kernel void refine_endpoint_clusterization( const uint32_t num_clusters = pInput_block_info[block_index].m_num_clusters; const uint32_t cur_block_cluster_index = pInput_block_info[block_index].m_cur_cluster_index; const uint32_t cur_block_cluster_etc_inten = pInput_block_info[block_index].m_cur_cluster_etc_inten; - + uint64_t overall_best_err = UINT64_MAX; uint32_t best_cluster_index = 0; @@ -1122,7 +1122,7 @@ kernel void refine_endpoint_clusterization( get_block_colors5(block_colors, &unscaled_color, etc_inten, false); uint64_t total_error = 0; - + for (uint32_t c = 0; c < 16; c++) { color_rgba src_pixel = priv_pixel_block.m_pixels[c]; @@ -1140,7 +1140,7 @@ kernel void refine_endpoint_clusterization( trial_error = color_distance(perceptual, src_pixel, block_colors[3], false); if (trial_error < best_error) best_error = trial_error; - + total_error += best_error; } @@ -1180,7 +1180,7 @@ typedef struct __attribute__ ((packed)) fosc_param_struct_tag // For each input block: Find the quantized selector which results in the lowest error. kernel void find_optimal_selector_clusters_for_each_block( - const fosc_param_struct params, + const fosc_param_struct params, const global pixel_block *pInput_blocks, const global fosc_block_struct *pInput_block_info, const global fosc_selector_struct *pInput_selectors, @@ -1188,10 +1188,10 @@ kernel void find_optimal_selector_clusters_for_each_block( global uint32_t *pOutput_selector_cluster_indices) { const uint32_t block_index = get_global_id(0); - + const global color_rgba *pBlock_pixels = pInput_blocks[block_index].m_pixels; const global fosc_block_struct *pBlock_info = &pInput_block_info[block_index]; - + const global fosc_selector_struct *pSelectors = &pInput_selectors[pBlock_info->m_first_selector]; const uint32_t num_selectors = pBlock_info->m_num_selectors; @@ -1220,7 +1220,7 @@ kernel void find_optimal_selector_clusters_for_each_block( for (uint32_t sel_index = 0; sel_index < num_selectors; sel_index++) { uint32_t sels = pSelectors[sel_index].m_packed_selectors; - + uint64_t total_err = 0; for (uint32_t i = 0; i < 16; i++, sels >>= 2) total_err += trial_errors[sels & 3][i]; @@ -1246,15 +1246,15 @@ typedef struct __attribute__ ((packed)) ds_param_struct_tag int m_perceptual; } ds_param_struct; -// For each input block: Determine the ETC1S selectors that result in the lowest error, given each block's predetermined ETC1S color5/intensities. +// For each input block: Determine the ETC1S selectors that result in the lowest error, given each block's predetermined ETC1S color5/intensities. kernel void determine_selectors( - const ds_param_struct params, + const ds_param_struct params, const global pixel_block *pInput_blocks, const global color_rgba *pInput_etc_color5_and_inten, global etc_block *pOutput_blocks) { const uint32_t block_index = get_global_id(0); - + const global color_rgba *pBlock_pixels = pInput_blocks[block_index].m_pixels; color_rgba etc_color5_inten = pInput_etc_color5_and_inten[block_index]; @@ -1287,4 +1287,3 @@ kernel void determine_selectors( pOutput_blocks[block_index] = output_block; } - diff --git a/contrib/previewers/lib/basisu_transcoder.cpp b/contrib/previewers/lib/basisu_transcoder.cpp index 37640ee1..49dce75a 100644 --- a/contrib/previewers/lib/basisu_transcoder.cpp +++ b/contrib/previewers/lib/basisu_transcoder.cpp @@ -9,7 +9,7 @@ * Transcoder build options for known platforms (iOS has ETC, ASTC and PVRTC; * Emscripten adds DXT to iOS's options; Android adds PVRTC2 to Emscripten's * options; other platforms build all except FXT1). - * + * * See https://github.com/BinomialLLC/basis_universal#shrinking-the-transcoders-compiled-size */ #ifdef __APPLE__ @@ -73,7 +73,7 @@ #define BASISD_SUPPORT_KTX2 1 #endif -// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support +// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support #ifndef BASISD_SUPPORT_KTX2_ZSTD #define BASISD_SUPPORT_KTX2_ZSTD 1 #endif @@ -539,28 +539,28 @@ namespace basisu // operator[] will assert on out of range indices, but in final builds there is (and will never be) any range checking on this method. //BASISU_FORCE_INLINE const T& operator[] (uint32_t i) const { assert(i < m_size); return m_p[i]; } //BASISU_FORCE_INLINE T& operator[] (uint32_t i) { assert(i < m_size); return m_p[i]; } - + #if !BASISU_VECTOR_FORCE_CHECKING BASISU_FORCE_INLINE const T& operator[] (size_t i) const { assert(i < m_size); return m_p[i]; } BASISU_FORCE_INLINE T& operator[] (size_t i) { assert(i < m_size); return m_p[i]; } #else - BASISU_FORCE_INLINE const T& operator[] (size_t i) const - { + BASISU_FORCE_INLINE const T& operator[] (size_t i) const + { if (i >= m_size) { fprintf(stderr, "operator[] invalid index: %u, max entries %u, type size %u\n", (uint32_t)i, m_size, (uint32_t)sizeof(T)); abort(); } - return m_p[i]; + return m_p[i]; } - BASISU_FORCE_INLINE T& operator[] (size_t i) - { + BASISU_FORCE_INLINE T& operator[] (size_t i) + { if (i >= m_size) { fprintf(stderr, "operator[] invalid index: %u, max entries %u, type size %u\n", (uint32_t)i, m_size, (uint32_t)sizeof(T)); abort(); } - return m_p[i]; + return m_p[i]; } #endif @@ -568,7 +568,7 @@ namespace basisu // The first element is returned if the index is out of range. BASISU_FORCE_INLINE const T& at(size_t i) const { assert(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; } BASISU_FORCE_INLINE T& at(size_t i) { assert(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; } - + #if !BASISU_VECTOR_FORCE_CHECKING BASISU_FORCE_INLINE const T& front() const { assert(m_size); return m_p[0]; } BASISU_FORCE_INLINE T& front() { assert(m_size); return m_p[0]; } @@ -576,42 +576,42 @@ namespace basisu BASISU_FORCE_INLINE const T& back() const { assert(m_size); return m_p[m_size - 1]; } BASISU_FORCE_INLINE T& back() { assert(m_size); return m_p[m_size - 1]; } #else - BASISU_FORCE_INLINE const T& front() const - { + BASISU_FORCE_INLINE const T& front() const + { if (!m_size) { fprintf(stderr, "front: vector is empty, type size %u\n", (uint32_t)sizeof(T)); abort(); } - return m_p[0]; + return m_p[0]; } - BASISU_FORCE_INLINE T& front() - { + BASISU_FORCE_INLINE T& front() + { if (!m_size) { fprintf(stderr, "front: vector is empty, type size %u\n", (uint32_t)sizeof(T)); abort(); } - return m_p[0]; + return m_p[0]; } - BASISU_FORCE_INLINE const T& back() const - { + BASISU_FORCE_INLINE const T& back() const + { if(!m_size) { fprintf(stderr, "back: vector is empty, type size %u\n", (uint32_t)sizeof(T)); abort(); } - return m_p[m_size - 1]; + return m_p[m_size - 1]; } - BASISU_FORCE_INLINE T& back() - { + BASISU_FORCE_INLINE T& back() + { if (!m_size) { fprintf(stderr, "back: vector is empty, type size %u\n", (uint32_t)sizeof(T)); abort(); } - return m_p[m_size - 1]; + return m_p[m_size - 1]; } #endif @@ -902,7 +902,7 @@ namespace basisu insert(m_size, p, n); return *this; } - + inline void erase(uint32_t start, uint32_t n) { assert((start + n) <= m_size); @@ -933,7 +933,7 @@ namespace basisu } else { - // Type is not bitwise copyable or movable. + // Type is not bitwise copyable or movable. // Move them down one at a time by using the equals operator, and destroying anything that's left over at the end. T* pDst_end = pDst + num_to_move; while (pDst != pDst_end) @@ -1153,7 +1153,7 @@ namespace basisu if (!m) break; cmp = -cmp; i += (((m + 1) >> 1) ^ cmp) - cmp; - if (i < 0) + if (i < 0) break; } } @@ -1298,7 +1298,7 @@ namespace basisu public: class iterator; class const_iterator; - + private: friend class iterator; friend class const_iterator; @@ -1486,7 +1486,7 @@ namespace basisu if (new_hash_size > m_values.size()) rehash((uint32_t)new_hash_size); } - + class iterator { friend class hash_map; @@ -1921,7 +1921,7 @@ namespace basisu inline void grow() { uint64_t n = m_values.size() * 3ULL; // was * 2 - + if (!helpers::is_power_of_2(n)) n = helpers::next_pow2(n); @@ -2138,11 +2138,11 @@ namespace basisu template struct bitwise_movable< hash_map > { enum { cFlag = true }; }; - + #if BASISU_HASHMAP_TEST extern void hash_map_test(); #endif - + } // namespace basisu namespace std @@ -2213,7 +2213,7 @@ namespace basisu void enable_debug_printf(bool enabled); void debug_printf(const char *pFmt, ...); - + template inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); } @@ -2222,7 +2222,7 @@ namespace basisu template inline S maximum(S a, S b) { return (a > b) ? a : b; } template inline S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); } template inline S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); } - + template inline S minimum(S a, S b) { return (a < b) ? a : b; } template inline S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); } template inline S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); } @@ -2246,7 +2246,7 @@ namespace basisu inline uint32_t iabs(int32_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } inline uint64_t iabs64(int64_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } - template inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); } + template inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); } template inline typename T::value_type *enlarge_vector(T &vec, size_t n) { size_t cs = vec.size(); vec.resize(cs + n); return &vec[cs]; } inline bool is_pow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); } @@ -2259,8 +2259,8 @@ namespace basisu template inline T saturate(T val) { return clamp(val, 0.0f, 1.0f); } - template inline void append_vector(T &vec, const R *pObjs, size_t n) - { + template inline void append_vector(T &vec, const R *pObjs, size_t n) + { if (n) { if (vec.size()) @@ -2311,7 +2311,7 @@ namespace basisu for (size_t i = 0; i < vec.size(); i++) vec[i] = obj; } - + inline uint64_t read_be64(const void *p) { uint64_t val = 0; @@ -2372,7 +2372,7 @@ namespace basisu pBytes[2] = (uint8_t)(val >> 16U); pBytes[3] = (uint8_t)(val >> 24U); } - + // Always little endian 1-8 byte unsigned int template struct packed_uint @@ -2382,17 +2382,17 @@ namespace basisu inline packed_uint() { static_assert(NumBytes <= sizeof(uint64_t), "Invalid NumBytes"); } inline packed_uint(uint64_t v) { *this = v; } inline packed_uint(const packed_uint& other) { *this = other; } - - inline packed_uint& operator= (uint64_t v) - { - for (uint32_t i = 0; i < NumBytes; i++) - m_bytes[i] = static_cast(v >> (i * 8)); - return *this; + + inline packed_uint& operator= (uint64_t v) + { + for (uint32_t i = 0; i < NumBytes; i++) + m_bytes[i] = static_cast(v >> (i * 8)); + return *this; } - inline packed_uint& operator= (const packed_uint& rhs) - { - memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes)); + inline packed_uint& operator= (const packed_uint& rhs) + { + memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes)); return *this; } @@ -2400,19 +2400,19 @@ namespace basisu { switch (NumBytes) { - case 1: + case 1: { return m_bytes[0]; } - case 2: + case 2: { return (m_bytes[1] << 8U) | m_bytes[0]; } - case 3: + case 3: { return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0]; } - case 4: + case 4: { return read_le_dword(m_bytes); } @@ -2434,13 +2434,13 @@ namespace basisu uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4]; return static_cast(l) | (static_cast(h) << 32U); } - case 8: + case 8: { uint32_t l = read_le_dword(m_bytes); uint32_t h = read_le_dword(m_bytes + 4); return static_cast(l) | (static_cast(h) << 32U); } - default: + default: { assert(0); return 0; @@ -2451,14 +2451,14 @@ namespace basisu enum eZero { cZero }; enum eNoClamp { cNoClamp }; - + // Rice/Huffman entropy coding - + // This is basically Deflate-style canonical Huffman, except we allow for a lot more symbols. enum { - cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31, - cHuffmanFastLookupBits = 10, + cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31, + cHuffmanFastLookupBits = 10, cHuffmanMaxSymsLog2 = 14, cHuffmanMaxSyms = 1 << cHuffmanMaxSymsLog2, // Small zero runs @@ -2484,13 +2484,13 @@ namespace basisu enum class texture_format { cInvalidTextureFormat = -1, - + // Block-based formats cETC1, // ETC1 cETC1S, // ETC1 (subset: diff colors only, no subblocks) cETC2_RGB, // ETC2 color block (basisu doesn't support ETC2 planar/T/H modes - just basic ETC1) cETC2_RGBA, // ETC2 EAC alpha block followed by ETC2 color block - cETC2_ALPHA, // ETC2 EAC alpha block + cETC2_ALPHA, // ETC2 EAC alpha block cBC1, // DXT1 cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block) cBC4, // DXT5A @@ -2505,10 +2505,10 @@ namespace basisu cPVRTC2_4_RGBA, cETC2_R11_EAC, cETC2_RG11_EAC, - cUASTC4x4, + cUASTC4x4, cBC1_NV, cBC1_AMD, - + // Uncompressed/raw pixels cRGBA32, cRGB565, @@ -2566,7 +2566,7 @@ namespace basisu BASISU_NOTE_UNUSED(fmt); return 4; } - + } // namespace basisu /**** ended inlining basisu.h ****/ @@ -2584,9 +2584,9 @@ namespace basist // You probably don't care about these enum's unless you are going pretty low-level and calling the transcoder to decode individual slices. enum class block_format { - cETC1, // ETC1S RGB + cETC1, // ETC1S RGB cETC2_RGBA, // full ETC2 EAC RGBA8 block - cBC1, // DXT1 RGB + cBC1, // DXT1 RGB cBC3, // BC4 block followed by a four color BC1 block cBC4, // DXT5A (alpha block only) cBC5, // two BC4 blocks @@ -2596,9 +2596,9 @@ namespace basist cBC7_M5_COLOR, // RGB BC7 mode 5 color (writes an opaque mode 5 block) cBC7_M5_ALPHA, // alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.) cETC2_EAC_A8, // alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format) - cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC + cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC // data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking. - + cATC_RGB, cATC_RGBA_INTERPOLATED_ALPHA, cFXT1_RGB, // Opaque-only, has oddball 8x4 pixel block size @@ -2608,21 +2608,21 @@ namespace basist cETC2_EAC_R11, cETC2_EAC_RG11, - + cIndices, // Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits) cRGB32, // Writes RGB components to 32bpp output pixels cRGBA32, // Writes RGB255 components to 32bpp output pixels cA32, // Writes alpha component to 32bpp output pixels - + cRGB565, cBGR565, - + cRGBA4444_COLOR, cRGBA4444_ALPHA, cRGBA4444_COLOR_OPAQUE, cRGBA4444, - + cTotalBlockFormats }; @@ -2643,9 +2643,9 @@ namespace basist const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_THRESH = 3; const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_BITS = 6; const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_TOTAL = (1 << SELECTOR_HISTORY_BUF_RLE_COUNT_BITS); - + uint16_t crc16(const void *r, size_t size, uint16_t crc); - + class huffman_decoding_table { friend class bitwise_decoder; @@ -2763,7 +2763,7 @@ namespace basist return false; else if (idx >= (int)m_tree.size()) m_tree.resize(idx + 1); - + if (!m_tree[idx]) { m_tree[idx] = (int16_t)tree_next; @@ -2932,14 +2932,14 @@ namespace basist for (;;) { uint32_t k = peek_bits(16); - + uint32_t l = 0; while (k & 1) { l++; k >>= 1; } - + q += l; remove_bits(l); @@ -2957,7 +2957,7 @@ namespace basist const uint32_t chunk_size = 1 << chunk_bits; const uint32_t chunk_mask = chunk_size - 1; - + uint32_t v = 0; uint32_t ofs = 0; @@ -2969,7 +2969,7 @@ namespace basist if ((s & chunk_size) == 0) break; - + if (ofs >= 32) { assert(0); @@ -2985,7 +2985,7 @@ namespace basist assert(ct.m_code_sizes.size()); const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits; - + while (m_bit_buf_size < 16) { uint32_t c = 0; @@ -2996,7 +2996,7 @@ namespace basist m_bit_buf_size += 8; assert(m_bit_buf_size <= 32); } - + int code_len; int sym; @@ -3181,7 +3181,7 @@ namespace basist }; struct decoder_etc_block; - + inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); @@ -3205,7 +3205,7 @@ namespace basist }; uint8_t c[4]; - + uint32_t m; }; @@ -3327,7 +3327,7 @@ namespace basist }; bool basis_block_format_is_uncompressed(block_format tex_type); - + } // namespace basist @@ -3340,8 +3340,8 @@ namespace basist namespace basist { struct color_quad_u8 - { - uint8_t m_c[4]; + { + uint8_t m_c[4]; }; const uint32_t TOTAL_UASTC_MODES = 19; @@ -3436,9 +3436,9 @@ namespace basist int m_ccs; // color component selector (dual plane only) bool m_dual_plane; // true if dual plane - // Weight and endpoint BISE values. + // Weight and endpoint BISE values. // Note these values are NOT linear, they must be BISE encoded. See Table 97 and Table 107. - uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order + uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order uint8_t m_weights[64]; // weight index values, raster order, in P0 P1, P0 P1, etc. or P0, P0, P0, P0, etc. order }; @@ -3533,7 +3533,7 @@ namespace basist #ifdef _DEBUG int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block); #endif - + struct uastc_block { union @@ -3573,10 +3573,10 @@ namespace basist }; color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock); - + struct decoder_etc_block; struct eac_block; - + bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb); bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb); @@ -3598,7 +3598,7 @@ namespace basist // Packs 16 scalar values to BC4. Same PSNR as stb_dxt's BC4 encoder, around 13% faster. void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride); - + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb); enum @@ -3608,7 +3608,7 @@ namespace basist cEncodeBC1UseSelectors = 4, }; void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags); - + // Alternate PCA-free encoder, around 15% faster, same (or slightly higher) avg. PSNR void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags); @@ -3625,7 +3625,7 @@ namespace basist bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha); bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality); - + // uastc_init() MUST be called before using this module. void uastc_init(); @@ -3654,10 +3654,10 @@ namespace basist enum basis_slice_desc_flags { cSliceDescFlagsHasAlpha = 1, - + // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols) // Currently the first frame is always an I-Frame, all subsequent frames are P-Frames. This will eventually be changed to periodic I-Frames. - cSliceDescFlagsFrameIsIFrame = 2 + cSliceDescFlagsFrameIsIFrame = 2 }; #pragma pack(push) @@ -3672,7 +3672,7 @@ namespace basist basisu::packed_uint<2> m_orig_height; // The original image height (may not be a multiple of 4 pixels) basisu::packed_uint<2> m_num_blocks_x; // The slice's block X dimensions. Each block is 4x4 pixels. The slice's pixel resolution may or may not be a power of 2. - basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions. + basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions. basisu::packed_uint<4> m_file_ofs; // Offset from the start of the file to the start of the slice's data basisu::packed_uint<4> m_file_size; // The size of the compressed slice data in bytes @@ -3684,24 +3684,24 @@ namespace basist enum basis_header_flags { // Always set for ETC1S files. Not set for UASTC files. - cBASISHeaderFlagETC1S = 1, - + cBASISHeaderFlagETC1S = 1, + // Set if the texture had to be Y flipped before encoding. The actual interpretation of this (is Y up or down?) is up to the user. - cBASISHeaderFlagYFlipped = 2, - + cBASISHeaderFlagYFlipped = 2, + // Set if any slices contain alpha (for ETC1S, if the odd slices contain alpha data) - cBASISHeaderFlagHasAlphaSlices = 4, - - // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file. - cBASISHeaderFlagUsesGlobalCodebook = 8, - - // Set if the texture data is sRGB, otherwise it's linear. + cBASISHeaderFlagHasAlphaSlices = 4, + + // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file. + cBASISHeaderFlagUsesGlobalCodebook = 8, + + // Set if the texture data is sRGB, otherwise it's linear. // In reality, we have no idea if the texture data is actually linear or sRGB. This is the m_perceptual parameter passed to the compressor. - cBASISHeaderFlagSRGB = 16, + cBASISHeaderFlagSRGB = 16, }; // The image type field attempts to describe how to interpret the image data in a Basis file. - // The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user. + // The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user. // We do make sure the various constraints are followed (2DArray/cubemap/videoframes/volume implies that each image has the same resolution and # of mipmap levels, etc., cubemap implies that the # of image slices is a multiple of 6) enum basis_texture_type { @@ -3744,7 +3744,7 @@ namespace basist basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha .basis files) basisu::packed_uint<3> m_total_images; // The total # of images - + basisu::packed_uint<1> m_tex_format; // enum basis_tex_format basisu::packed_uint<2> m_flags; // enum basist::header_flags basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type @@ -3754,11 +3754,11 @@ namespace basist basisu::packed_uint<4> m_userdata0; // For client use basisu::packed_uint<4> m_userdata1; // For client use - basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook + basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the start of the file basisu::packed_uint<3> m_endpoint_cb_file_size; // The compressed endpoint codebook's size in bytes - basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook + basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the start of the file basisu::packed_uint<3> m_selector_cb_file_size; // The compressed selector codebook's size in bytes @@ -3766,7 +3766,7 @@ namespace basist basisu::packed_uint<4> m_tables_file_size; // The file size in bytes of the compressed huffman codelength tables basisu::packed_uint<4> m_slice_desc_file_ofs; // The file offset to the slice description array, usually follows the header - + basisu::packed_uint<4> m_extended_file_ofs; // The file offset of the "extended" header and compressed data, for future use basisu::packed_uint<4> m_extended_file_size; // The file size in bytes of the "extended" header and compressed data, for future use }; @@ -3780,7 +3780,7 @@ namespace basist // High-level composite texture formats supported by the transcoder. // Each of these texture formats directly correspond to OpenGL/D3D/Vulkan etc. texture formats. // Notes: - // - If you specify a texture format that supports alpha, but the .basis file doesn't have alpha, the transcoder will automatically output a + // - If you specify a texture format that supports alpha, but the .basis file doesn't have alpha, the transcoder will automatically output a // fully opaque (255) alpha channel. // - The PVRTC1 texture formats only support power of 2 dimension .basis files, but this may be relaxed in a future version. // - The PVRTC1 transcoders are real-time encoders, so don't expect the highest quality. We may add a slower encoder with improved quality. @@ -3809,7 +3809,7 @@ namespace basist // ATC (mobile, Adreno devices, this is a niche format) cTFATC_RGB = 11, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD) - cTFATC_RGBA = 12, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD) + cTFATC_RGBA = 12, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD) // FXT1 (desktop, Intel devices, this is a super obscure format) cTFFXT1_RGB = 17, // Opaque only, uses exclusively CC_MIXED blocks. Notable for having a 8x4 block size. GL_3DFX_texture_compression_FXT1 is supported on Intel integrated GPU's (such as HD 630). @@ -3908,7 +3908,7 @@ namespace basist basisu::vector m_block_endpoint_preds[2]; enum { cMaxPrevFrameLevels = 16 }; - basisu::vector m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index] + basisu::vector m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index] void clear() { @@ -3986,13 +3986,13 @@ namespace basist typedef basisu::vector selector_vec; const selector_vec& get_selectors() const { return m_local_selectors; } - + private: const basisu_lowlevel_etc1s_transcoder* m_pGlobal_codebook; endpoint_vec m_local_endpoints; selector_vec m_local_selectors; - + huffman_decoding_table m_endpoint_pred_model, m_delta_endpoint_model, m_selector_model, m_selector_history_buf_rle_model; uint32_t m_selector_history_buf_size; @@ -4013,7 +4013,7 @@ namespace basist // This flag is used internally when decoding to BC3. cDecodeFlagsBC1ForbidThreeColorBlocks = 8, - // The output buffer contains alpha endpoint/selector indices. + // The output buffer contains alpha endpoint/selector indices. // Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format. cDecodeFlagsOutputHasAlphaIndices = 16, @@ -4220,11 +4220,11 @@ namespace basist // transcode_image_level() decodes a single mipmap level from the .basis file to any of the supported output texture formats. // It'll first find the slice(s) to transcode, then call transcode_slice() one or two times to decode both the color and alpha texture data (or RG texture data from two slices for BC5). // If the .basis file doesn't have alpha slices, the output alpha blocks will be set to fully opaque (all 255's). - // Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements. + // Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements. // output_blocks_buf_size_in_blocks_or_pixels should be at least the image level's total_blocks (num_blocks_x * num_blocks_y), or the total number of output pixels if fmt==cTFRGBA32. // output_row_pitch_in_blocks_or_pixels: Number of blocks or pixels per row. If 0, the transcoder uses the slice's num_blocks_x or orig_width (NOT num_blocks_x * 4). Ignored for PVRTC1 (due to texture swizzling). // output_rows_in_pixels: Ignored unless fmt is uncompressed (cRGBA32, etc.). The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4). - // Notes: + // Notes: // - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function. // - This method assumes the output texture buffer is readable. In some cases to handle alpha, the transcoder will write temporary data to the output texture in // a first pass, which will be read in a second pass. @@ -4279,7 +4279,7 @@ namespace basist // basisu_transcoder_init() MUST be called before a .basis file can be transcoded. void basisu_transcoder_init(); - + enum debug_flags_t { cDebugFlagVisCRs = 1, @@ -4289,10 +4289,10 @@ namespace basist uint32_t get_debug_flags(); void set_debug_flags(uint32_t f); - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ // Optional .KTX2 file format support // KTX2 reading optionally requires miniz or Zstd decompressors for supercompressed UASTC files. - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_KTX2 #pragma pack(push) #pragma pack(1) @@ -4435,12 +4435,12 @@ namespace basist { case KTX2_DF_PRIMARIES_UNSPECIFIED: return "UNSPECIFIED"; case KTX2_DF_PRIMARIES_BT709: return "BT709"; - case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU"; + case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU"; case KTX2_DF_PRIMARIES_BT601_SMPTE: return "SMPTE"; case KTX2_DF_PRIMARIES_BT2020: return "BT2020"; case KTX2_DF_PRIMARIES_CIEXYZ: return "CIEXYZ"; case KTX2_DF_PRIMARIES_ACES: return "ACES"; - case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC"; + case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC"; case KTX2_DF_PRIMARIES_NTSC1953: return "NTSC1953"; case KTX2_DF_PRIMARIES_PAL525: return "PAL525"; case KTX2_DF_PRIMARIES_DISPLAYP3: return "DISPLAYP3"; @@ -4448,7 +4448,7 @@ namespace basist default: break; } return "?"; - } + } // Information about a single 2D texture "image" in a KTX2 file. struct ktx2_image_level_info @@ -4479,7 +4479,7 @@ namespace basist // true if the image is an I-Frame. Currently, for ETC1S textures, the first frame will always be an I-Frame, and subsequent frames will always be P-Frames. bool m_iframe_flag; }; - + // Thread-specific ETC1S/supercompressed UASTC transcoder state. (If you're not doing multithreading transcoding you can ignore this.) struct ktx2_transcoder_state { @@ -4497,9 +4497,9 @@ namespace basist // This class is quite similar to basisu_transcoder. It treats KTX2 files as a simple container for ETC1S/UASTC texture data. // It does not support 1D or 3D textures. - // It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files. + // It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files. // It only supports raw non-supercompressed UASTC, ETC1S, UASTC+Zstd, or UASTC+zlib compressed files. - // DFD (Data Format Descriptor) parsing is purposely as simple as possible. + // DFD (Data Format Descriptor) parsing is purposely as simple as possible. // If you need to know how to interpret the texture channels you'll need to parse the DFD yourself after calling get_dfd(). class ktx2_transcoder { @@ -4540,7 +4540,7 @@ namespace basist uint32_t get_layers() const { return m_header.m_layer_count; } // Returns cETC1S or cUASTC4x4. Valid after init(). - basist::basis_tex_format get_format() const { return m_format; } + basist::basis_tex_format get_format() const { return m_format; } bool is_etc1s() const { return get_format() == basist::basis_tex_format::cETC1S; } @@ -4559,7 +4559,7 @@ namespace basist // Returns the DFD color primary. // We do not validate the color primaries, so the returned value may not be in the ktx2_df_color_primaries enum. ktx2_df_color_primaries get_dfd_color_primaries() const { return m_dfd_color_prims; } - + // Returns KTX2_KHR_DF_TRANSFER_LINEAR or KTX2_KHR_DF_TRANSFER_SRGB. uint32_t get_dfd_transfer_func() const { return m_dfd_transfer_func; } @@ -4567,9 +4567,9 @@ namespace basist // Returns 1 (ETC1S/UASTC) or 2 (ETC1S with an internal alpha channel). uint32_t get_dfd_total_samples() const { return m_dfd_samples; } - - // Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two. - // Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that. + + // Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two. + // Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that. // It's up to the caller to decide what to do if the value isn't in the enum. ktx2_df_channel_id get_dfd_channel_id0() const { return m_dfd_chan0; } ktx2_df_channel_id get_dfd_channel_id1() const { return m_dfd_chan1; } @@ -4607,18 +4607,18 @@ namespace basist // is_video() is only valid after start_transcoding() is called. // For ETC1S data, if this returns true you must currently transcode the file from first to last frame, in order, without skipping any frames. bool is_video() const { return m_is_video; } - + // start_transcoding() MUST be called before calling transcode_image(). // This method decompresses the ETC1S global endpoint/selector codebooks, which is not free, so try to avoid calling it excessively. bool start_transcoding(); - + // get_image_level_info() be called after init(), but the m_iframe_flag's won't be valid until start_transcoding() is called. // You can call this method before calling transcode_image_level() to retrieve basic information about the mipmap level's dimensions, etc. bool get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const; // transcode_image_level() transcodes a single 2D texture or cubemap face from the KTX2 file. // Internally it uses the same low-level transcode API's as basisu_transcoder::transcode_image_level(). - // If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is + // If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is // completely transcoded before switching to another level. Every time the mipmap level is changed all supercompressed level data must be decompressed using Zstandard as a single unit. // Currently ETC1S videos must always be transcoded from first to last frame (or KTX2 "layer"), in order, with no skipping of frames. // By default this method is not thread safe unless you specify a pointer to a user allocated thread-specific transcoder_state struct. @@ -4628,7 +4628,7 @@ namespace basist basist::transcoder_texture_format fmt, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, ktx2_transcoder_state *pState = nullptr); - + private: const uint8_t* m_pData; uint32_t m_data_size; @@ -4637,22 +4637,22 @@ namespace basist basisu::vector m_levels; basisu::uint8_vec m_dfd; key_value_vec m_key_values; - + ktx2_etc1s_global_data_header m_etc1s_header; basisu::vector m_etc1s_image_descs; basist::basis_tex_format m_format; - + uint32_t m_dfd_color_model; ktx2_df_color_primaries m_dfd_color_prims; uint32_t m_dfd_transfer_func; uint32_t m_dfd_flags; uint32_t m_dfd_samples; ktx2_df_channel_id m_dfd_chan0, m_dfd_chan1; - + basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder; basist::basisu_lowlevel_uastc_transcoder m_uastc_transcoder; - + ktx2_transcoder_state m_def_transcoder_state; bool m_has_alpha; @@ -4712,7 +4712,7 @@ namespace basisu abort(); } } - + const size_t desired_size = element_size * new_capacity; size_t actual_size = 0; if (!pMover) @@ -4776,7 +4776,7 @@ namespace basisu if (m_p) free(m_p); - + m_p = new_p; } @@ -5140,7 +5140,7 @@ namespace basisu void debug_printf(const char* pFmt, ...) { -#if BASISU_FORCE_DEVEL_MESSAGES +#if BASISU_FORCE_DEVEL_MESSAGES g_debug_printf = true; #endif if (g_debug_printf) @@ -5202,7 +5202,7 @@ namespace basist return static_cast(~crc); } - + enum etc_constants { cETC1BytesPerBlock = 8U, @@ -5275,14 +5275,14 @@ namespace basist //const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 }; - + static const uint8_t g_etc_5_to_8[32] = { 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255 }; struct decoder_etc_block { // big endian uint64: // bit ofs: 56 48 40 32 24 16 8 0 - // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 + // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 union { uint64_t m_uint64; @@ -5550,7 +5550,7 @@ namespace basist { return (m_bytes[3] & 2) != 0; } - + inline uint32_t get_inten_table(uint32_t subblock_id) const { assert(subblock_id < 2); @@ -5565,7 +5565,7 @@ namespace basist const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3); return static_cast(b | (g << 3U) | (r << 6U)); } - + void get_block_colors(color32* pBlock_colors, uint32_t subblock_index) const { color32 b; @@ -5683,7 +5683,7 @@ namespace basist g = c.g; b = c.b; } - + static void unpack_color5(color32& result, uint16_t packed_color5, bool scaled) { result = unpack_color5(packed_color5, scaled, 255); @@ -5812,7 +5812,7 @@ namespace basist static void get_block_color5_r(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t &r) { assert(index < 4); - + uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2); const int* pInten_table = g_etc1_inten_tables[inten_table]; @@ -5988,7 +5988,7 @@ namespace basist { 1, 2, 2, 2 }, { 1, 2, 3, 3 }, }; - + static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; @@ -7370,9 +7370,9 @@ namespace basist return best_err; } #endif // BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES - + static -#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES +#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES const #endif etc1_g_to_eac_conversion s_etc1_g_to_etc2_a8[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] = @@ -7862,18 +7862,18 @@ namespace basist #endif static bool g_transcoder_initialized; - + // Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz. // If this is too slow, these computed tables can easilky be moved to be compiled in. void basisu_transcoder_init() { if (g_transcoder_initialized) { - BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n"); + BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n"); return; } - - BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n"); + + BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n"); #if BASISD_SUPPORT_UASTC uastc_init(); @@ -7882,7 +7882,7 @@ namespace basist #if BASISD_SUPPORT_ASTC transcoder_init_astc(); #endif - + #if BASISD_WRITE_NEW_ASTC_TABLES create_etc1_to_astc_conversion_table_0_47(); create_etc1_to_astc_conversion_table_0_255(); @@ -8138,7 +8138,7 @@ namespace basist std::swap(l, h); pSelectors_xlat_256 = &g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[best_mapping][0]; } - + pDst_block->set_low_color(static_cast(l)); pDst_block->set_high_color(static_cast(h)); @@ -8298,7 +8298,7 @@ namespace basist fxt1_block* pBlock = static_cast(pDst); // CC_MIXED is basically DXT1 with different encoding tricks. - // So transcode ETC1S to DXT1, then transcode that to FXT1 which is easy and nearly lossless. + // So transcode ETC1S to DXT1, then transcode that to FXT1 which is easy and nearly lossless. // (It's not completely lossless because FXT1 rounds in its color lerps while DXT1 doesn't, but it should be good enough.) dxt1_block blk; convert_etc1s_to_dxt1(&blk, pEndpoints, pSelectors, false); @@ -8311,7 +8311,7 @@ namespace basist uint32_t g0 = color0.g & 1; uint32_t g1 = color1.g & 1; - + color0.g >>= 1; color1.g >>= 1; @@ -8319,7 +8319,7 @@ namespace basist blk.m_selectors[1] = conv_dxt1_to_fxt1_sels(blk.m_selectors[1]); blk.m_selectors[2] = conv_dxt1_to_fxt1_sels(blk.m_selectors[2]); blk.m_selectors[3] = conv_dxt1_to_fxt1_sels(blk.m_selectors[3]); - + if ((blk.get_selector(0, 0) >> 1) != (g0 ^ g1)) { std::swap(color0, color1); @@ -8333,7 +8333,7 @@ namespace basist if (fxt1_subblock == 0) { - pBlock->m_hi.m_mode = 1; + pBlock->m_hi.m_mode = 1; pBlock->m_hi.m_alpha = 0; pBlock->m_hi.m_glsb = g1 | (g1 << 1); pBlock->m_hi.m_r0 = color0.r; @@ -8654,7 +8654,7 @@ namespace basist { uint32_t r; decoder_etc_block::get_block_color5_r(base_color, inten_table, low_selector, r); - + pDst_block->set_low_alpha(r); pDst_block->set_high_alpha(r); pDst_block->m_selectors[0] = 0; @@ -8737,7 +8737,7 @@ namespace basist static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 }; static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 }; static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 }; - + static const uint8_t g_pvrtc_5_floor[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,3,3,3,3,3,3,3,3, @@ -8761,7 +8761,7 @@ namespace basist 24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28, 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31 }; - + static const uint8_t g_pvrtc_4_floor[256] = { 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, @@ -8785,7 +8785,7 @@ namespace basist 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,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 }; - + static const uint8_t g_pvrtc_3_floor[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, @@ -8809,7 +8809,7 @@ namespace basist 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 }; - + static const uint8_t g_pvrtc_alpha_floor[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, @@ -8916,10 +8916,10 @@ namespace basist } assert((r < 32) && (g < 32) && (b < 32) && (a < 16)); - + return color32(r, g, b, a); } - + inline color32 get_endpoint_8888(uint32_t endpoint_index) const { assert(endpoint_index < 2); @@ -8966,7 +8966,7 @@ namespace basist a = g_pvrtc_alpha[a]; } - + return color32(r, g, b, a); } @@ -8975,7 +8975,7 @@ namespace basist color32 c(get_endpoint_8888(endpoint_index)); return c.r + c.g + c.b + c.a; } - + inline uint32_t get_opaque_endpoint_l0() const { uint32_t packed = m_endpoints & 0xFFFE; @@ -9090,7 +9090,7 @@ namespace basist else m_endpoints = (m_endpoints & 0xFFFF0000U) | packed; } - + // opaque endpoints: 554 or 555 // transparent endpoints: 3443 or 3444 inline void set_endpoint_raw(uint32_t endpoint_index, const color32& c, bool opaque_endpoint) @@ -9143,7 +9143,7 @@ namespace basist else m_endpoints = (m_endpoints & 0xFFFF0000U) | packed; } - + inline void set_endpoint_floor(uint32_t endpoint_index, const color32& c) { assert(endpoint_index < 2); @@ -9368,7 +9368,7 @@ namespace basist for (int ey = 0; ey < 3; ey++) { - int by = y + ey - 1; + int by = y + ey - 1; const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x]; @@ -9376,7 +9376,7 @@ namespace basist for (int ex = 0; ex < 3; ex++) { - int bx = 0 + ex - 1; + int bx = 0 + ex - 1; const uint32_t e = pE[bx & x_mask]; @@ -9525,8 +9525,8 @@ namespace basist } static void fixup_pvrtc1_4_modulation_rgba( - const decoder_etc_block* pETC_Blocks, - const uint32_t* pPVRTC_endpoints, + const decoder_etc_block* pETC_Blocks, + const uint32_t* pPVRTC_endpoints, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, void *pAlpha_blocks, const endpoint* pEndpoints, const selector* pSelectors) { @@ -9549,7 +9549,7 @@ namespace basist for (int ey = 0; ey < 3; ey++) { - int by = y + ey - 1; + int by = y + ey - 1; const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x]; @@ -9557,7 +9557,7 @@ namespace basist for (int ex = 0; ex < 3; ex++) { - int bx = 0 + ex - 1; + int bx = 0 + ex - 1; const uint32_t e = pE[bx & x_mask]; @@ -9571,13 +9571,13 @@ namespace basist for (int x = 0; x < static_cast(num_blocks_x); x++, block_index++) { const decoder_etc_block& src_block = pETC_Blocks[block_index]; - + const uint16_t* pSrc_alpha_block = reinterpret_cast(static_cast(pAlpha_blocks) + x + (y * num_blocks_x)); const endpoint* pAlpha_endpoints = &pEndpoints[pSrc_alpha_block[0]]; const selector* pAlpha_selectors = &pSelectors[pSrc_alpha_block[1]]; - + const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1); - + uint32_t swizzled = x_swizzle | y_swizzle; if (num_blocks_x != num_blocks_y) { @@ -9720,7 +9720,7 @@ namespace basist const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES = sizeof(g_etc1_to_bc7_m5_selector_ranges) / sizeof(g_etc1_to_bc7_m5_selector_ranges[0]); static uint32_t g_etc1_to_bc7_m5_selector_range_index[4][4]; - + const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS = 10; static const uint8_t g_etc1_to_bc7_m5_selector_mappings[NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS][4] = { @@ -9742,7 +9742,7 @@ namespace basist uint8_t m_hi; uint16_t m_err; }; - + static const etc1_to_bc7_m5_solution g_etc1_to_bc7_m5_color[32 * 8 * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS * NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES] = { /**** start inlining basisu_transcoder_tables_bc7_m5_color.inc ****/ {0,7,18},{0,5,2},{0,4,1},{0,3,8},{0,4,35},{0,3,24},{0,3,12},{0,2,29},{0,2,36},{0,2,30},{0,7,18},{0,5,2},{0,4,1},{0,3,8},{2,0,35},{0,3,24},{0,3,12},{0,2,29},{4,0,35},{0,2,29},{0,3,0},{0,3,0},{0,3,0},{0,1,1},{0,1,2},{0,1,2},{0,1,2},{0,1,1},{1,0,3},{0,1,2},{0,3,0}, @@ -10228,7 +10228,7 @@ namespace basist {5,127,1413}, /**** ended inlining basisu_transcoder_tables_bc7_m5_color.inc ****/ }; - + static dxt_selector_range g_etc1_to_bc7_m5a_selector_ranges[] = { { 0, 3 }, @@ -10303,7 +10303,7 @@ namespace basist {208,5,2}, /**** ended inlining basisu_transcoder_tables_bc7_m5_alpha.inc ****/ }; - + static inline uint32_t set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t cur_ofs) { assert(num_bits < 32); @@ -10450,7 +10450,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1_to_bc7_m5_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -10529,7 +10529,7 @@ namespace basist int mapping_err = block_colors[s].g - colors[k]; mapping_err *= mapping_err; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) mapping_err *= 5; @@ -10540,7 +10540,7 @@ namespace basist best_k = k; } } // k - + total_err += best_mapping_err; output_selectors |= (best_k << (s * 2)); } // s @@ -10555,7 +10555,7 @@ namespace basist } // lo } // hi - + fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, best_output_selectors); n++; if ((n & 31) == 31) @@ -10594,7 +10594,7 @@ namespace basist {127,104},{126,105},{126,106},{127,106},{127,107},{126,108},{125,109},{127,109},{126,110},{126,111},{127,111},{127,112},{126,113},{126,114},{127,114},{127,115}, {126,116},{126,117},{127,117},{127,118},{126,119},{126,120},{127,120},{127,121},{126,122},{126,123},{127,123},{127,124},{126,125},{126,126},{127,126},{127,127} }; - + static void transcoder_init_bc7_mode5() { #if 0 @@ -10622,9 +10622,9 @@ namespace basist } } // hi - + } // lo - + printf("{%u,%u},", g_bc7_m5_equals_1[i].m_hi, g_bc7_m5_equals_1[i].m_lo); if ((i & 15) == 15) printf("\n"); } @@ -10648,7 +10648,7 @@ namespace basist static void convert_etc1s_to_bc7_m5_color(void* pDst, const endpoint* pEndpoints, const selector* pSelector) { bc7_mode_5* pDst_block = static_cast(pDst); - + // First ensure the block is cleared to all 0's static_cast(pDst)[0] = 0; static_cast(pDst)[1] = 0; @@ -10774,7 +10774,7 @@ namespace basist pDst_block->m_lo.m_r1 = pTable_r[best_mapping].m_lo; pDst_block->m_lo.m_g1 = pTable_g[best_mapping].m_lo; pDst_block->m_lo.m_b1 = pTable_b[best_mapping].m_lo; - + s_inv = 3; } else @@ -10795,7 +10795,7 @@ namespace basist for (uint32_t x = 0; x < 4; x++) { const uint32_t s = pSelector->get_selector(x, y); - + const uint32_t os = pSelectors_xlat[s] ^ s_inv; output_bits |= (os << output_bit_ofs); @@ -10825,7 +10825,7 @@ namespace basist pDst_block->m_lo.m_a0 = r; pDst_block->m_lo.m_a1_0 = r & 63; pDst_block->m_hi.m_a1_1 = r >> 6; - + return; } else if (pSelector->m_num_unique_selectors == 2) @@ -10875,7 +10875,7 @@ namespace basist } const uint32_t selector_range_table = g_etc1_to_bc7_m5a_selector_range_index[low_selector][high_selector]; - + const etc1_g_to_bc7_m5a_conversion* pTable = &g_etc1_g_to_bc7_m5a[inten_table * (32 * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES) + base_color_r * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES + selector_range_table]; pDst_block->m_lo.m_a0 = pTable->m_lo; @@ -11827,7 +11827,7 @@ namespace basist // The best selector mapping to use given a base base+inten table and used selector range for converting grayscale data. static uint8_t g_etc1_to_astc_best_grayscale_mapping[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES]; - + #if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY static const etc1_to_astc_solution g_etc1_to_astc_0_255[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] = { /**** start inlining basisu_transcoder_tables_astc_0_255.inc ****/ @@ -12374,7 +12374,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 8; @@ -12395,7 +12395,7 @@ namespace basist mapping_best_high[m] = best_hi; mapping_best_err[m] = best_err; highest_best_err = basisu::maximum(highest_best_err, best_err); - + } // m for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++) @@ -12471,7 +12471,7 @@ namespace basist { int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]]; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. int err_scale = 1; if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) @@ -12500,9 +12500,9 @@ namespace basist uint64_t err = mapping_best_err[m]; err = basisu::minimum(err, 0xFFFF); - + fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err); - + n++; if ((n & 31) == 31) fprintf(pFile, "\n"); @@ -12585,14 +12585,14 @@ namespace basist struct astc_block_params { // 2 groups of 5, but only a max of 8 are used (RRGGBBAA00) - uint8_t m_endpoints[10]; + uint8_t m_endpoints[10]; uint8_t m_weights[32]; }; - - // Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2). + + // Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2). // We're always going to output blocks containing alpha, even if the input doesn't have alpha, for simplicity. // Each block always has 4x4 weights, uses range 13 BISE encoding on the endpoints (0-47), and each weight ranges from 0-3. This encoding should be roughly equal in quality vs. BC1 for color. - // 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47. + // 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47. // Note the input [0,47] endpoint values are not linear - they are encoded as outlined in the ASTC spec: // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-endpoint-unquantization // 32 total weights, stored as 16 CA CA, each ranging from 0-3. @@ -12614,7 +12614,7 @@ namespace basist astc_encode_trits(pOutput, pBlock->m_endpoints + 5, bit_pos, 4); // Pack 32 2-bit weights, which are stored from the top down into the block in opposite bit order. - + for (uint32_t i = 0; i < 32; i++) { static const uint8_t s_reverse_bits[4] = { 0, 2, 1, 3 }; @@ -12623,7 +12623,7 @@ namespace basist } } - // CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights + // CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights // This ASTC mode is basically block truncation coding (BTC) using 1-bit weights and 8-bit/component endpoints - very convenient. static void astc_pack_block_cem_12_weight_range0(uint32_t* pOutput, const astc_block_params* pBlock) { @@ -12661,7 +12661,7 @@ namespace basist // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode pBytes[0] = 0x42; pBytes[1] = 0x84; pBytes[2] = 0x00; pBytes[3] = 0x00; pBytes[4] = 0x00; pBytes[5] = 0x00; pBytes[6] = 0x00; pBytes[7] = 0xc0; - + pOutput[2] = 0; pOutput[3] = 0; @@ -12687,7 +12687,7 @@ namespace basist // Write constant block mode, color component selector, number of partitions, color endpoint mode // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode pBytes[0] = 0x42; pBytes[1] = 0x00; pBytes[2] = 0x01; pBytes[3] = 0x00; - + pOutput[1] = 0; pOutput[2] = 0; pOutput[3] = 0; @@ -12715,7 +12715,7 @@ namespace basist { uint8_t m_lo, m_hi; } g_astc_single_color_encoding_1[256]; - + static void transcoder_init_astc() { for (uint32_t base_color = 0; base_color < 32; base_color++) @@ -12793,7 +12793,7 @@ namespace basist g_ise_to_unquant[bit | (trit << 4)] = unq; } } - + // Compute table used for optimal single color encoding. for (int i = 0; i < 256; i++) { @@ -12808,9 +12808,9 @@ namespace basist int l = lo_v | (lo_v << 8); int h = hi_v | (hi_v << 8); - + int v = ((l * (64 - 21) + (h * 21) + 32) / 64) >> 8; - + int e = abs(v - i); if (e < lowest_e) @@ -12832,7 +12832,7 @@ namespace basist for (int lo = 0; lo < 48; lo++) { const int lo_v = g_ise_to_unquant[lo]; - + int e = abs(lo_v - i); if (e < lowest_e) @@ -12847,7 +12847,7 @@ namespace basist // Converts opaque or color+alpha ETC1S block to ASTC 4x4. // This function tries to use the best ASTC mode given the block's actual contents. - static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector, + static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector, bool transcode_alpha, const endpoint *pEndpoint_codebook, const selector *pSelector_codebook) { astc_block_params blk; @@ -12891,7 +12891,7 @@ namespace basist // See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-void-extent-blocks uint32_t r, g, b; decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b); - + uint32_t* pOutput = static_cast(pDst_block); uint8_t* pBytes = reinterpret_cast(pDst_block); @@ -12911,7 +12911,7 @@ namespace basist } else if ((pSelector->m_num_unique_selectors <= 2) && (num_unique_alpha_selectors <= 2)) { - // Both color and alpha use <= 2 unique selectors each. + // Both color and alpha use <= 2 unique selectors each. // Use block truncation coding, which is lossless with ASTC (8-bit endpoints, 1-bit weights). color32 block_colors[4]; decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table); @@ -12958,7 +12958,7 @@ namespace basist { uint32_t s = alpha_selectors.get_selector(x, y); s = (s == alpha_high_selector) ? 1 : 0; - + blk.m_weights[(x + y * 4) * 2 + 1] = static_cast(s); } // x } // y @@ -12991,12 +12991,12 @@ namespace basist return; } - + // Either alpha and/or color use > 2 unique selectors each, so we must do something more complex. - + #if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY // The optional higher quality modes use 8-bits endpoints vs. [0,47] endpoints. - + // If the block's base color is grayscale, all pixels are grayscale, so encode the block as Luminance+Alpha. if ((base_color.r == base_color.g) && (base_color.r == base_color.b)) { @@ -13030,7 +13030,7 @@ namespace basist { // Convert ETC1S alpha const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; @@ -13038,7 +13038,7 @@ namespace basist blk.m_endpoints[2] = pTable_g[best_mapping].m_lo; blk.m_endpoints[3] = pTable_g[best_mapping].m_hi; - + const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0]; for (uint32_t y = 0; y < 4; y++) @@ -13082,10 +13082,10 @@ namespace basist { // Convert ETC1S alpha const uint32_t selector_range_table = g_etc1_to_astc_selector_range_index[low_selector][high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; - + const uint32_t best_mapping = g_etc1_to_astc_best_grayscale_mapping_0_255[base_color.g][inten_table][selector_range_table]; blk.m_endpoints[0] = pTable_g[best_mapping].m_lo; @@ -13227,7 +13227,7 @@ namespace basist { // Convert ETC1S alpha const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; @@ -13271,7 +13271,7 @@ namespace basist const uint32_t r = block_colors[low_selector].r; const uint32_t g = block_colors[low_selector].g; const uint32_t b = block_colors[low_selector].b; - + blk.m_endpoints[0] = g_astc_single_color_encoding_1[r].m_lo; blk.m_endpoints[1] = g_astc_single_color_encoding_1[r].m_hi; @@ -13373,7 +13373,7 @@ namespace basist blk.m_endpoints[4] = pTable_b[best_mapping].m_lo; blk.m_endpoints[5] = pTable_b[best_mapping].m_hi; - + int s0 = g_ise_to_unquant[blk.m_endpoints[0]] + g_ise_to_unquant[blk.m_endpoints[2]] + g_ise_to_unquant[blk.m_endpoints[4]]; int s1 = g_ise_to_unquant[blk.m_endpoints[1]] + g_ise_to_unquant[blk.m_endpoints[3]] + g_ise_to_unquant[blk.m_endpoints[5]]; bool invert = false; @@ -15466,8 +15466,8 @@ namespace basist static void transcoder_init_atc() { prepare_atc_single_color_table(g_pvrtc2_match45_equals_1, 16, 32, 1); - prepare_atc_single_color_table(g_atc_match55_equals_1, 32, 32, 1); - prepare_atc_single_color_table(g_atc_match56_equals_1, 32, 64, 1); + prepare_atc_single_color_table(g_atc_match55_equals_1, 32, 32, 1); + prepare_atc_single_color_table(g_atc_match56_equals_1, 32, 64, 1); prepare_atc_single_color_table(g_pvrtc2_match4, 1, 16, 3); prepare_atc_single_color_table(g_atc_match5, 1, 32, 3); @@ -15521,7 +15521,7 @@ namespace basist pBlock->set_low_color(g_atc_match55_equals_1[r].m_lo, g_atc_match56_equals_1[g].m_lo, g_atc_match55_equals_1[b].m_lo); pBlock->set_high_color(g_atc_match55_equals_1[r].m_hi, g_atc_match56_equals_1[g].m_hi, g_atc_match55_equals_1[b].m_hi); - + pBlock->m_sels[0] = 0x55; pBlock->m_sels[1] = 0x55; pBlock->m_sels[2] = 0x55; @@ -15656,7 +15656,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -15730,7 +15730,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -15760,7 +15760,7 @@ namespace basist } // inten fclose(pFile); - + // PVRTC2 45 fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_45.inc", "w"); @@ -15805,7 +15805,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -15882,7 +15882,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -15959,7 +15959,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -16036,7 +16036,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -16164,12 +16164,12 @@ namespace basist { uint8_t m_l, m_h; } g_pvrtc2_trans_match44[256]; - + static struct { uint8_t m_l, m_h; } g_pvrtc2_alpha_match33[256]; - + static struct { uint8_t m_l, m_h; @@ -16179,7 +16179,7 @@ namespace basist { uint8_t m_l, m_h; } g_pvrtc2_alpha_match33_3[256]; - + // PVRTC2 can be forced to look like a slightly weaker variant of ATC/BC1, so that's what we do here for simplicity. static void convert_etc1s_to_pvrtc2_rgb(void* pDst, const endpoint* pEndpoints, const selector* pSelector) { @@ -16293,7 +16293,7 @@ namespace basist } typedef struct { float c[4]; } vec4F; - + static inline vec4F* vec4F_set_scalar(vec4F* pV, float x) { pV->c[0] = x; pV->c[1] = x; pV->c[2] = x; pV->c[3] = x; return pV; } static inline vec4F* vec4F_set(vec4F* pV, float x, float y, float z, float w) { pV->c[0] = x; pV->c[1] = y; pV->c[2] = z; pV->c[3] = w; return pV; } static inline vec4F* vec4F_saturate_in_place(vec4F* pV) { pV->c[0] = saturate(pV->c[0]); pV->c[1] = saturate(pV->c[1]); pV->c[2] = saturate(pV->c[2]); pV->c[3] = saturate(pV->c[3]); return pV; } @@ -16311,9 +16311,9 @@ namespace basist } static inline int sq(int x) { return x * x; } - - // PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is exanded from 4 to 8 bits means it can never be 0. - // This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha! + + // PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is exanded from 4 to 8 bits means it can never be 0. + // This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha! // And there's nothing straightforward we can do because using the other modes is too expensive/complex. I can see why Apple didn't adopt it. static void convert_etc1s_to_pvrtc2_rgba(void* pDst, const endpoint* pEndpoints, const selector* pSelector, const endpoint* pEndpoint_codebook, const selector* pSelector_codebook) { @@ -16368,13 +16368,13 @@ namespace basist const uint32_t high_selector = pSelector->m_hi_selector; const int num_unique_color_selectors = pSelector->m_num_unique_selectors; - + // We need to reencode the block at the pixel level, unfortunately, from two ETC1S planes. // Do 4D incremental PCA, project all pixels to this hyperline, then quantize to packed endpoints and compute the modulation values. const int br = (base_color.r << 3) | (base_color.r >> 2); const int bg = (base_color.g << 3) | (base_color.g >> 2); const int bb = (base_color.b << 3) | (base_color.b >> 2); - + color32 block_cols[4]; for (uint32_t i = 0; i < 4; i++) { @@ -16403,14 +16403,14 @@ namespace basist decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b); // Mod 0 - uint32_t lr0 = (r * 15 + 128) / 255, lg0 = (g * 15 + 128) / 255, lb0 = (b * 7 + 128) / 255; + uint32_t lr0 = (r * 15 + 128) / 255, lg0 = (g * 15 + 128) / 255, lb0 = (b * 7 + 128) / 255; uint32_t la0 = g_pvrtc2_alpha_match33_0[constant_alpha_val].m_l; uint32_t cr0 = (lr0 << 1) | (lr0 >> 3); uint32_t cg0 = (lg0 << 1) | (lg0 >> 3); uint32_t cb0 = (lb0 << 2) | (lb0 >> 1); uint32_t ca0 = (la0 << 1); - + cr0 = (cr0 << 3) | (cr0 >> 2); cg0 = (cg0 << 3) | (cg0 >> 2); cb0 = (cb0 << 3) | (cb0 >> 2); @@ -16439,14 +16439,14 @@ namespace basist uint32_t cg3 = (lg3 << 1) | (lg3 >> 3); uint32_t cb3 = (lb3 << 1) | (lb3 >> 3); uint32_t ca3 = (la3 << 1) | 1; - + cr3 = (cr3 << 3) | (cr3 >> 2); cg3 = (cg3 << 3) | (cg3 >> 2); cb3 = (cb3 << 3) | (cb3 >> 2); ca3 = (ca3 << 4) | ca3; uint32_t err3 = sq(cr3 - r) + sq(cg3 - g) + sq(cb3 - b) + sq(ca3 - constant_alpha_val) * 2; - + // Mod 1 uint32_t lr1 = g_pvrtc2_trans_match44[r].m_l, lg1 = g_pvrtc2_trans_match44[g].m_l, lb1 = g_pvrtc2_trans_match34[b].m_l; uint32_t hr1 = g_pvrtc2_trans_match44[r].m_h, hg1 = g_pvrtc2_trans_match44[g].m_h, hb1 = g_pvrtc2_trans_match34[b].m_h; @@ -16521,7 +16521,7 @@ namespace basist // It's a solid color block. uint32_t low_a = block_cols[alpha_selectors.m_lo_selector].a; uint32_t high_a = block_cols[alpha_selectors.m_hi_selector].a; - + const float S = 1.0f / 255.0f; vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, low_a * S); vec4F_set(&maxColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, high_a * S); @@ -16533,7 +16533,7 @@ namespace basist vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, constant_alpha_val * S); vec4F_set(&maxColor, block_cols[high_selector].r * S, block_cols[high_selector].g * S, block_cols[high_selector].b * S, constant_alpha_val * S); } - // See if any of the block colors got clamped - if so the principle axis got distorted (it's no longer just the ETC1S luma axis). + // See if any of the block colors got clamped - if so the principle axis got distorted (it's no longer just the ETC1S luma axis). // To keep quality up we need to use full 4D PCA in this case. else if ((block_cols[low_selector].c[0] == 0) || (block_cols[high_selector].c[0] == 255) || (block_cols[low_selector].c[1] == 0) || (block_cols[high_selector].c[1] == 255) || @@ -16584,7 +16584,7 @@ namespace basist } vec4F_normalize_in_place(&axis); - + if (vec4F_dot(&axis, &axis) < .5f) vec4F_set_scalar(&axis, .5f); @@ -16684,10 +16684,10 @@ namespace basist // 4433 4443 color32 trialMinColor, trialMaxColor; - + trialMinColor.set_clamped((int)(minColor.c[0] * 15.0f + .5f), (int)(minColor.c[1] * 15.0f + .5f), (int)(minColor.c[2] * 7.0f + .5f), (int)(minColor.c[3] * 7.0f + .5f)); trialMaxColor.set_clamped((int)(maxColor.c[0] * 15.0f + .5f), (int)(maxColor.c[1] * 15.0f + .5f), (int)(maxColor.c[2] * 15.0f + .5f), (int)(maxColor.c[3] * 7.0f + .5f)); - + pBlock->set_trans_low_color(trialMinColor.r, trialMinColor.g, trialMinColor.b, trialMinColor.a); pBlock->set_trans_high_color(trialMaxColor.r, trialMaxColor.g, trialMaxColor.b, trialMaxColor.a); @@ -16760,7 +16760,7 @@ namespace basist } } } - + static void transcoder_init_pvrtc2() { for (uint32_t v = 0; v < 256; v++) @@ -16866,7 +16866,7 @@ namespace basist g_pvrtc2_trans_match34[v].m_l = (uint8_t)best_l; g_pvrtc2_trans_match34[v].m_h = (uint8_t)best_h; } - + for (uint32_t v = 0; v < 256; v++) { int best_l = 0, best_h = 0, lowest_err = INT_MAX; @@ -16994,7 +16994,7 @@ namespace basist sym_codec.stop(); m_local_selectors.resize(num_selectors); - + if (!sym_codec.init(pSelectors_data, selectors_data_size)) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 5\n"); @@ -17019,7 +17019,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: hybrid global selector codebooks are unsupported\n"); return false; } - + const bool used_raw_encoding = (sym_codec.get_bits(1) == 1); if (used_raw_encoding) @@ -17200,7 +17200,7 @@ namespace basist if (!output_rows_in_pixels) output_rows_in_pixels = orig_height; } - + basisu::vector* pPrev_frame_indices = nullptr; if (is_video) { @@ -17228,12 +17228,12 @@ namespace basist } approx_move_to_front selector_history_buf(m_selector_history_buf_size); - + uint32_t cur_selector_rle_count = 0; decoder_etc_block block; memset(&block, 0, sizeof(block)); - + //block.set_flip_bit(true); // Setting the flip bit to false to be compatible with the Khronos KDFS. block.set_flip_bit(false); @@ -17481,7 +17481,7 @@ namespace basist case block_format::cETC1: { decoder_etc_block* pDst_block = reinterpret_cast(static_cast(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes); - + block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false)); block.set_inten_table(0, pEndpoints->m_inten5); block.set_inten_table(1, pEndpoints->m_inten5); @@ -17532,7 +17532,7 @@ namespace basist const uint32_t low_selector = pSelector->m_lo_selector; const uint32_t high_selector = pSelector->m_hi_selector; - // Get block's RGB bounding box + // Get block's RGB bounding box color32 block_colors[2]; decoder_etc_block::get_block_colors5_bounds(block_colors, base_color, inten_table, low_selector, high_selector); @@ -17548,7 +17548,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -17556,7 +17556,7 @@ namespace basist { #if BASISD_SUPPORT_PVRTC1 assert(pAlpha_blocks); - + block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false)); block.set_inten_table(0, pEndpoints->m_inten5); block.set_inten_table(1, pEndpoints->m_inten5); @@ -17564,7 +17564,7 @@ namespace basist ((decoder_etc_block*)pPVRTC_work_mem)[block_x + block_y * num_blocks_x] = block; - // Get block's RGBA bounding box + // Get block's RGBA bounding box const color32& base_color = pEndpoints->m_color5; const uint32_t inten_table = pEndpoints->m_inten5; const uint32_t low_selector = pSelector->m_lo_selector; @@ -17599,7 +17599,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -17683,7 +17683,7 @@ namespace basist assert(transcode_alpha); void* pDst_block = static_cast(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes; - + convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &endpoints[0], &selectors[0]); #endif break; @@ -17699,10 +17699,10 @@ namespace basist { assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes); uint8_t* pDst_pixels = static_cast(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t); - + const uint32_t max_x = basisu::minimum(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4); const uint32_t max_y = basisu::minimum(4, (int)output_rows_in_pixels - (int)block_y * 4); - + int colors[4]; decoder_etc_block::get_block_colors5_g(colors, pEndpoints->m_color5, pEndpoints->m_inten5); @@ -17716,7 +17716,7 @@ namespace basist pDst_pixels[3+4] = static_cast(colors[(s >> 2) & 3]); pDst_pixels[3+8] = static_cast(colors[(s >> 4) & 3]); pDst_pixels[3+12] = static_cast(colors[(s >> 6) & 3]); - + pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t); } } @@ -17745,7 +17745,7 @@ namespace basist color32 colors[4]; decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5); - + for (uint32_t y = 0; y < max_y; y++) { const uint32_t s = pSelector->m_selectors[y]; @@ -17866,7 +17866,7 @@ namespace basist cur = byteswap_uint16(cur); cur = (cur & 0xF) | packed_colors[(s >> (x * 2)) & 3]; - + if (BASISD_IS_BIG_ENDIAN) cur = byteswap_uint16(cur); @@ -17998,7 +17998,7 @@ namespace basist if (!output_row_pitch_in_blocks_or_pixels) output_row_pitch_in_blocks_or_pixels = orig_width; - if (!output_rows_in_pixels) + if (!output_rows_in_pixels) output_rows_in_pixels = orig_height; // Now make sure the output buffer is large enough, or we'll overwrite memory. @@ -18078,7 +18078,7 @@ namespace basist // Switch to PVRTC1 RGB if the input doesn't have alpha. target_format = transcoder_texture_format::cTFPVRTC1_4_RGB; } - + const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0; const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format); const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y; @@ -18109,7 +18109,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels); - + if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC1 failed\n"); @@ -18234,7 +18234,7 @@ namespace basist if (basis_file_has_alpha_slices) { - // First decode the alpha data + // First decode the alpha data //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_A8, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels); } @@ -18272,8 +18272,8 @@ namespace basist return false; #else assert(bytes_per_block_or_pixel == 16); - - // First decode the alpha data + + // First decode the alpha data if (basis_file_has_alpha_slices) { //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); @@ -18402,7 +18402,7 @@ namespace basist #else assert(bytes_per_block_or_pixel == 16); - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) { //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); @@ -18462,7 +18462,7 @@ namespace basist } else { - // Now decode the color data and transcode to PVRTC2 RGBA. + // Now decode the color data and transcode to PVRTC2 RGBA. //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels); } @@ -18483,7 +18483,7 @@ namespace basist { // Raw 32bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory. - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cA32, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels); @@ -18524,7 +18524,7 @@ namespace basist { // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory. - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels); @@ -18626,7 +18626,7 @@ namespace basist return status; } - + basisu_lowlevel_uastc_transcoder::basisu_lowlevel_uastc_transcoder() { } @@ -18692,7 +18692,7 @@ namespace basist for (uint32_t block_y = 0; block_y < num_blocks_y; ++block_y) { void* pDst_block = (uint8_t*)pDst_blocks + block_y * output_row_pitch_in_blocks_or_pixels * output_block_or_pixel_stride_in_bytes; - + for (uint32_t block_x = 0; block_x < num_blocks_x; ++block_x, ++pSource_block, pDst_block = (uint8_t *)pDst_block + output_block_or_pixel_stride_in_bytes) { switch (fmt) @@ -18722,7 +18722,7 @@ namespace basist } case block_format::cBC4: { - if (channel0 < 0) + if (channel0 < 0) channel0 = 0; status = transcode_uastc_to_bc4(*pSource_block, pDst_block, high_quality, channel0); break; @@ -18885,7 +18885,7 @@ namespace basist return false; #endif } - + bool basisu_lowlevel_uastc_transcoder::transcode_image( transcoder_texture_format target_format, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, @@ -18907,7 +18907,7 @@ namespace basist { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: source data buffer too small\n"); return false; - } + } if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA)) { @@ -18934,7 +18934,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: output buffer size too small\n"); return false; } - + bool status = false; // UASTC4x4 @@ -18945,7 +18945,7 @@ namespace basist //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC1, bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); - + if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC1 failed\n"); @@ -19162,7 +19162,7 @@ namespace basist return status; } - + basisu_transcoder::basisu_transcoder() : m_ready_to_transcode(false) { @@ -19190,7 +19190,7 @@ namespace basist return false; } } -#endif +#endif return true; } @@ -19277,7 +19277,7 @@ namespace basist return false; } } - + // This flag dates back to pre-Basis Universal, when .basis supported full ETC1 too. if ((pHeader->m_flags & cBASISHeaderFlagETC1S) == 0) { @@ -19293,7 +19293,7 @@ namespace basist return false; } } - + if ((pHeader->m_slice_desc_file_ofs >= data_size) || ((data_size - pHeader->m_slice_desc_file_ofs) < (sizeof(basis_slice_desc) * pHeader->m_total_slices)) ) @@ -19409,12 +19409,12 @@ namespace basist image_info.m_image_index = image_index; image_info.m_total_levels = total_levels; - + image_info.m_alpha_flag = false; // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha. if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) - image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; + image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; else image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0; @@ -19537,13 +19537,13 @@ namespace basist image_info.m_image_index = image_index; image_info.m_level_index = level_index; - + // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha. if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; else image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0; - + image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0; image_info.m_width = slice_desc.m_num_blocks_x * 4; image_info.m_height = slice_desc.m_num_blocks_y * 4; @@ -19601,7 +19601,7 @@ namespace basist file_info.m_tex_format = static_cast(static_cast(pHeader->m_tex_format)); file_info.m_etc1s = (pHeader->m_tex_format == (int)basis_tex_format::cETC1S); - + file_info.m_y_flipped = (pHeader->m_flags & cBASISHeaderFlagYFlipped) != 0; file_info.m_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; @@ -19666,7 +19666,7 @@ namespace basist return true; } - + bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size) { if (!validate_header_quick(pData, data_size)) @@ -19774,7 +19774,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); } } - + m_ready_to_transcode = true; return true; @@ -19785,7 +19785,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); m_ready_to_transcode = false; - + return true; } @@ -19824,7 +19824,7 @@ namespace basist const basis_slice_desc& slice_desc = reinterpret_cast(pDataU8 + pHeader->m_slice_desc_file_ofs)[slice_index]; uint32_t total_4x4_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y; - + if (basis_block_format_is_uncompressed(fmt)) { // Assume the output buffer is orig_width by orig_height @@ -19887,7 +19887,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid slice_desc.m_file_size, or passed in buffer too small\n"); return false; } - + if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4) { return m_lowlevel_uastc_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y, @@ -19975,7 +19975,7 @@ namespace basist if (!output_row_pitch_in_blocks_or_pixels) output_row_pitch_in_blocks_or_pixels = num_blocks_x; - + if ((fmt == block_format::cETC2_EAC_A8) || (fmt == block_format::cETC2_EAC_R11)) { #if BASISD_SUPPORT_ETC2_EAC_A8 @@ -20061,7 +20061,7 @@ namespace basist if (slice_index < 0) { BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: failed finding slice index\n"); - // Unable to find the requested image/level + // Unable to find the requested image/level return false; } @@ -20070,7 +20070,7 @@ namespace basist // Switch to PVRTC1 RGB if the input doesn't have alpha. fmt = transcoder_texture_format::cTFPVRTC1_4_RGB; } - + if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) { if (pSlice_descs[slice_index].m_flags & cSliceDescFlagsHasAlpha) @@ -20107,7 +20107,7 @@ namespace basist } } } - + bool status = false; const uint32_t total_slice_blocks = pSlice_descs[slice_index].m_num_blocks_x * pSlice_descs[slice_index].m_num_blocks_y; @@ -20115,11 +20115,11 @@ namespace basist if (((fmt == transcoder_texture_format::cTFPVRTC1_4_RGB) || (fmt == transcoder_texture_format::cTFPVRTC1_4_RGBA)) && (output_blocks_buf_size_in_blocks_or_pixels > total_slice_blocks)) { // The transcoder doesn't write beyond total_slice_blocks, so we need to clear the rest ourselves. - // For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8. + // For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8. // However, for KTX and internally in Basis this formula isn't used, it's just ((width+3)/4) * ((height+3)/4) * bytes_per_block_or_pixel. This is all the transcoder actually writes to memory. memset(static_cast(pOutput_blocks) + total_slice_blocks * bytes_per_block_or_pixel, 0, (output_blocks_buf_size_in_blocks_or_pixels - total_slice_blocks) * bytes_per_block_or_pixel); } - + if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4) { const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index]; @@ -20131,7 +20131,7 @@ namespace basist pSlice_desc->m_file_ofs, pSlice_desc->m_file_size, decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); } - else + else { // ETC1S const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index]; @@ -20157,14 +20157,14 @@ namespace basist decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); } // if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4) - + if (!status) { BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning false\n"); } else { - //BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n"); + //BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n"); } return status; @@ -20378,13 +20378,13 @@ namespace basist } return false; } - + uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt) { switch (fmt) { case transcoder_texture_format::cTFRGBA32: - return sizeof(uint32_t); + return sizeof(uint32_t); case transcoder_texture_format::cTFRGB565: case transcoder_texture_format::cTFBGR565: case transcoder_texture_format::cTFRGBA4444: @@ -20394,7 +20394,7 @@ namespace basist } return 0; } - + uint32_t basis_get_block_width(transcoder_texture_format tex_type) { switch (tex_type) @@ -20412,7 +20412,7 @@ namespace basist BASISU_NOTE_UNUSED(tex_type); return 4; } - + bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt) { if (fmt == basis_tex_format::cUASTC4x4) @@ -20470,7 +20470,7 @@ namespace basist case transcoder_texture_format::cTFETC2_RGBA: return true; #endif -#if BASISD_SUPPORT_ASTC +#if BASISD_SUPPORT_ASTC case transcoder_texture_format::cTFASTC_4x4_RGBA: return true; #endif @@ -20501,9 +20501,9 @@ namespace basist return false; } - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ // UASTC - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_UASTC const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2] = @@ -21228,7 +21228,7 @@ namespace basist if (group_size) { - // Range has trits or quints - pack each group of 5 or 3 values + // Range has trits or quints - pack each group of 5 or 3 values const int total_groups = (group_size == 5) ? ((num_vals + 4) / 5) : ((num_vals + 2) / 3); for (int group_index = 0; group_index < total_groups; group_index++) @@ -21518,7 +21518,7 @@ namespace basist bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool blue_contract_check, bool read_hints) { //memset(&unpacked, 0, sizeof(unpacked)); - + #if 0 uint8_t table[128]; memset(table, 0xFF, sizeof(table)); @@ -21573,7 +21573,7 @@ namespace basist return true; } - + if (read_hints) { if (g_uastc_mode_has_bc1_hint0[mode]) @@ -21606,7 +21606,7 @@ namespace basist } else bit_ofs += g_uastc_mode_total_hint_bits[mode]; - + uint32_t subsets = 1; switch (mode) { @@ -21819,7 +21819,7 @@ namespace basist { // All other modes have <= 64 weight bits. uint64_t bits; - + // Read the weight bits if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS)) bits = read_bits64(blk.m_bytes, bit_ofs, basisu::minimum(64, 128 - (int)bit_ofs)); @@ -21831,31 +21831,31 @@ namespace basist #else bits = blk.m_qwords[1]; #endif - + if (bit_ofs >= 64U) bits >>= (bit_ofs - 64U); else { assert(bit_ofs >= 56U); - + uint32_t bits_needed = 64U - bit_ofs; bits <<= bits_needed; bits |= (blk.m_bytes[7] >> (8U - bits_needed)); } } - + bit_ofs = 0; const uint32_t mask = (1U << weight_bits) - 1U; const uint32_t anchor_mask = (1U << (weight_bits - 1U)) - 1U; - + if (total_planes == 2) { // Dual plane modes always have a single subset, and the first 2 weights are anchors. unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask); bit_ofs += (weight_bits - 1); - + unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask); bit_ofs += (weight_bits - 1); @@ -21873,7 +21873,7 @@ namespace basist if (weight_bits == 4) { assert(bit_ofs == 0); - + // Specialize the most common case: 4-bit weights. unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits) & 7); unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> 3) & 15); @@ -22419,7 +22419,7 @@ namespace basist } case 2: { - // 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE1 + // 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE1 dst_blk.m_mode = 1; dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7; @@ -23358,7 +23358,7 @@ namespace basist bool flip = pack_etc1_y_estimate_flipped(&block_y[0][0], upper_avg, lower_avg, left_avg, right_avg); // non-flipped: | | - // vs. + // vs. // flipped: -- // -- @@ -23969,7 +23969,7 @@ namespace basist static const uint8_t s_uastc2_to_bc1[4] = { 0, 2, 3, 1 }; static const uint8_t s_uastc1_to_bc1[2] = { 0, 1 }; const uint8_t* s_uastc_to_bc1_weights[6] = { nullptr, s_uastc1_to_bc1, s_uastc2_to_bc1, s_uastc3_to_bc1, s_uastc4_to_bc1, s_uastc5_to_bc1 }; - + void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride) { uint32_t min0_v, max0_v, min1_v, max1_v,min2_v, max2_v, min3_v, max3_v; @@ -24057,7 +24057,7 @@ namespace basist a2 |= (s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)] << 12U); a3 |= (s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)] << 12U); } - + { const int v0 = pPixels[8 * stride] * 14 + bias; const int v1 = pPixels[9 * stride] * 14 + bias; @@ -24081,7 +24081,7 @@ namespace basist } const uint64_t f = a0 | a1 | a2 | a3; - + pDst_bytes[2] = (uint8_t)f; pDst_bytes[3] = (uint8_t)(f >> 8U); pDst_bytes[4] = (uint8_t)(f >> 16U); @@ -24104,7 +24104,7 @@ namespace basist int dots[4]; for (uint32_t i = 0; i < 4; i++) dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab; - + int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3]; ar *= 2; ag *= 2; ab *= 2; @@ -24113,7 +24113,7 @@ namespace basist { const int d = pSrc_pixels[i].r * ar + pSrc_pixels[i].g * ag + pSrc_pixels[i].b * ab; static const uint8_t s_sels[4] = { 3, 2, 1, 0 }; - + // Rounding matters here! // d <= t0: <=, not <, to the later LS step "sees" a wider range of selectors. It matters for quality. sels[i] = s_sels[(d <= t0) + (d < t1) + (d < t2)]; @@ -24156,11 +24156,11 @@ namespace basist } struct vec3F { float c[3]; }; - + static bool compute_least_squares_endpoints_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh) { // Derived from bc7enc16's LS function. - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. uint32_t uq00_r = 0, uq10_r = 0, ut_r = 0, uq00_g = 0, uq10_g = 0, ut_g = 0, uq00_b = 0, uq10_b = 0, ut_b = 0; @@ -24234,7 +24234,7 @@ namespace basist return true; } - void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb) + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb) { dxt1_block* pDst_block = static_cast(pDst); @@ -24286,19 +24286,19 @@ namespace basist { const color32* pSrc_pixels = (const color32*)pPixels; dxt1_block* pDst_block = static_cast(pDst); - + int avg_r = -1, avg_g = 0, avg_b = 0; int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0; uint8_t sels[16]; - + const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0; if (use_sels) { // Caller is jamming in their own selectors for us to try. const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24); - + static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 }; - + for (uint32_t i = 0; i < 16; i++) sels[i] = s_sel_tran[(s >> (i * 2)) & 3]; } @@ -24310,13 +24310,13 @@ namespace basist for (j = 1; j < 16; j++) if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb)) break; - + if (j == 16) { encode_bc1_solid_block(pDst, fr, fg, fb); return; } - + // Select 2 colors along the principle axis. (There must be a faster/simpler way.) int total_r = fr, total_g = fg, total_b = fb; int max_r = fr, max_g = fg, max_b = fb; @@ -24350,7 +24350,7 @@ namespace basist float cov[6]; for (uint32_t i = 0; i < 6; i++) cov[i] = static_cast(icov[i])* (1.0f / 255.0f); - + #if 0 // Seems silly to use full PCA to choose 2 colors. The diff in avg. PSNR between using PCA vs. not is small (~.025 difference). // TODO: Try 2 or 3 different normalized diagonal vectors, choose the one that results in the largest dot delta @@ -24382,7 +24382,7 @@ namespace basist saxis_b = (int)(xb * m); } #endif - + int low_dot = INT_MAX, high_dot = INT_MIN, low_c = 0, high_c = 0; for (uint32_t i = 0; i < 16; i++) { @@ -24406,7 +24406,7 @@ namespace basist hr = to_5(pSrc_pixels[high_c].r); hg = to_6(pSrc_pixels[high_c].g); hb = to_5(pSrc_pixels[high_c].b); - + bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels); } // if (use_sels) @@ -24453,13 +24453,13 @@ namespace basist hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63); hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31); } - + bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels); } uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb); uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb); - + // Always forbid 3 color blocks if (lc16 == hc16) { @@ -24511,7 +24511,7 @@ namespace basist pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask; } } - + void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags) { const color32* pSrc_pixels = (const color32*)pPixels; @@ -24560,8 +24560,8 @@ namespace basist min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b); total_r += r; total_g += g; total_b += b; } - - if (grayscale_flag) + + if (grayscale_flag) { // Grayscale blocks are a common enough case to specialize. if ((max_r - min_r) < 2) @@ -24878,7 +24878,7 @@ namespace basist // Always forbid 3 color blocks uint16_t lc16 = (uint16_t)b.get_low_color(); uint16_t hc16 = (uint16_t)b.get_high_color(); - + uint8_t mask = 0; // Make l > h @@ -25108,7 +25108,7 @@ namespace basist blk.m_base = static_cast(a); blk.m_table = 13; blk.m_multiplier = 0; - + memcpy(blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4)); return; @@ -25798,7 +25798,7 @@ namespace basist if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false)) return false; - // Get block's RGB bounding box + // Get block's RGB bounding box color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0); if (from_alpha) @@ -25857,7 +25857,7 @@ namespace basist if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false)) return false; - // Get block's RGBA bounding box + // Get block's RGBA bounding box color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0); for (uint32_t i = 0; i < 16; i++) @@ -25973,9 +25973,9 @@ namespace basist #endif // #if BASISD_SUPPORT_UASTC -// ------------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------------ // KTX2 -// ------------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_KTX2 const uint8_t g_ktx2_file_identifier[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; @@ -25997,7 +25997,7 @@ namespace basist m_key_values.clear(); memset(&m_etc1s_header, 0, sizeof(m_etc1s_header)); m_etc1s_image_descs.clear(); - + m_format = basist::basis_tex_format::cETC1S; m_dfd_color_model = 0; @@ -26009,9 +26009,9 @@ namespace basist m_dfd_chan1 = KTX2_DF_CHANNEL_UASTC_RGB; m_etc1s_transcoder.clear(); - + m_def_transcoder_state.clear(); - + m_has_alpha = false; m_is_video = false; } @@ -26082,7 +26082,7 @@ namespace basist return false; } } - + // 3.7 levelCount: "levelCount=0 is allowed, except for block-compressed formats" if (m_header.m_level_count < 1) { @@ -26139,7 +26139,7 @@ namespace basist } memcpy(&m_levels[0], m_pData + sizeof(ktx2_header), level_index_size_in_bytes); - + // Sanity check the level offsets and byte sizes for (uint32_t i = 0; i < m_levels.size(); i++) { @@ -26159,9 +26159,9 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset and/or length\n"); return false; } - + const uint64_t MAX_SANE_LEVEL_UNCOMP_SIZE = 2048ULL * 1024ULL * 1024ULL; - + if (m_levels[i].m_uncompressed_byte_length >= MAX_SANE_LEVEL_UNCOMP_SIZE) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too large)\n"); @@ -26198,7 +26198,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD offset and/or length\n"); return false; } - + const uint8_t* pDFD = m_pData + m_header.m_dfd_byte_offset; if (!m_dfd.try_resize(m_header.m_dfd_byte_length)) @@ -26208,17 +26208,17 @@ namespace basist } memcpy(m_dfd.data(), pDFD, m_header.m_dfd_byte_length); - + // This is all hard coded for only ETC1S and UASTC. uint32_t dfd_total_size = basisu::read_le_dword(pDFD); - + // 3.10.3: Sanity check if (dfd_total_size != m_header.m_dfd_byte_length) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (1)\n"); return false; } - + // 3.10.3: More sanity checking if (m_header.m_kvd_byte_length) { @@ -26231,7 +26231,7 @@ namespace basist const uint32_t dfd_bits = basisu::read_le_dword(pDFD + 3 * sizeof(uint32_t)); const uint32_t sample_channel0 = basisu::read_le_dword(pDFD + 7 * sizeof(uint32_t)); - + m_dfd_color_model = dfd_bits & 255; m_dfd_color_prims = (ktx2_df_color_primaries)((dfd_bits >> 8) & 255); m_dfd_transfer_func = (dfd_bits >> 16) & 255; @@ -26247,11 +26247,11 @@ namespace basist if (m_dfd_color_model == KTX2_KDF_DF_MODEL_ETC1S) { m_format = basist::basis_tex_format::cETC1S; - - // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD’s sample count." + + // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD�s sample count." // If m_has_alpha is true it may be 2-channel RRRG or 4-channel RGBA, but we let the caller deal with that. m_has_alpha = (m_header.m_dfd_byte_length == 60); - + m_dfd_samples = m_has_alpha ? 2 : 1; m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15); @@ -26267,7 +26267,7 @@ namespace basist m_dfd_samples = 1; m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15); - + // We're assuming "DATA" means RGBA so it has alpha. m_has_alpha = (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RGBA) || (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RRRG); } @@ -26277,7 +26277,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD color model\n"); return false; } - + if (!read_key_values()) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: read_key_values() failed\n"); @@ -26321,7 +26321,7 @@ namespace basist return nullptr; } - + bool ktx2_transcoder::start_transcoding() { if (!m_pData) @@ -26330,7 +26330,7 @@ namespace basist return false; } - if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ) + if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ) { // Check if we've already decompressed the ETC1S global data. If so don't unpack it again. if (!m_etc1s_transcoder.get_endpoints().empty()) @@ -26341,7 +26341,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: decompress_etc1s_global_data() failed\n"); return false; } - + if (!m_is_video) { // See if there are any P-frames. If so it must be a video, even if there wasn't a KTXanimData key. @@ -26397,7 +26397,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: layer_index >= maximum(m_header.m_layer_count, 1)\n"); return false; } - + const uint32_t level_width = basisu::maximum(m_header.m_pixel_width >> level_index, 1); const uint32_t level_height = basisu::maximum(m_header.m_pixel_height >> level_index, 1); const uint32_t num_blocks_x = (level_width + 3) >> 2; @@ -26427,9 +26427,9 @@ namespace basist return true; } - + bool ktx2_transcoder::transcode_image_level( - uint32_t level_index, uint32_t layer_index, uint32_t face_index, + uint32_t level_index, uint32_t layer_index, uint32_t face_index, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, basist::transcoder_texture_format fmt, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, uint32_t output_rows_in_pixels, int channel0, int channel1, @@ -26443,7 +26443,7 @@ namespace basist if (!pState) pState = &m_def_transcoder_state; - + if (level_index >= m_levels.size()) { BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: level_index >= m_levels.size()\n"); @@ -26472,7 +26472,7 @@ namespace basist const uint8_t* pComp_level_data = m_pData + m_levels[level_index].m_byte_offset; uint64_t comp_level_data_size = m_levels[level_index].m_byte_length; - + const uint8_t* pUncomp_level_data = pComp_level_data; uint64_t uncomp_level_data_size = comp_level_data_size; @@ -26481,7 +26481,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_level_data_size > UINT32_MAX\n"); return false; } - + if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD) { // Check if we've already decompressed this level's supercompressed data. @@ -26499,12 +26499,12 @@ namespace basist pUncomp_level_data = pState->m_level_uncomp_data.data(); uncomp_level_data_size = pState->m_level_uncomp_data.size(); } - + const uint32_t level_width = basisu::maximum(m_header.m_pixel_width >> level_index, 1); const uint32_t level_height = basisu::maximum(m_header.m_pixel_height >> level_index, 1); const uint32_t num_blocks_x = (level_width + 3) >> 2; const uint32_t num_blocks_y = (level_height + 3) >> 2; - + if (m_format == basist::basis_tex_format::cETC1S) { // Ensure start_transcoding() was called. @@ -26518,7 +26518,7 @@ namespace basist (level_index * basisu::maximum(m_header.m_layer_count, 1) * m_header.m_face_count) + layer_index * m_header.m_face_count + face_index; - + // Sanity check if (etc1s_image_index >= m_etc1s_image_descs.size()) { @@ -26553,7 +26553,7 @@ namespace basist // Compute length and offset to uncompressed 2D UASTC texture data, given the face/layer indices. assert(uncomp_level_data_size == m_levels[level_index].m_uncompressed_byte_length); const uint32_t total_2D_image_size = num_blocks_x * num_blocks_y * KTX2_UASTC_BLOCK_SIZE; - + const uint32_t uncomp_ofs = (layer_index * m_header.m_face_count + face_index) * total_2D_image_size; // Sanity checks @@ -26589,12 +26589,12 @@ namespace basist return true; } - + bool ktx2_transcoder::decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data) { const uint8_t* pComp_data = m_levels[level_index].m_byte_offset + m_pData; const uint64_t comp_size = m_levels[level_index].m_byte_length; - + const uint64_t uncomp_size = m_levels[level_index].m_uncompressed_byte_length; if (((size_t)comp_size) != comp_size) @@ -26613,7 +26613,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Out of memory\n"); return false; } - + if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD) { #if BASISD_SUPPORT_KTX2_ZSTD @@ -26636,7 +26636,7 @@ namespace basist return true; } - + bool ktx2_transcoder::decompress_etc1s_global_data() { // Note: we don't actually support 3D textures in here yet @@ -26675,13 +26675,13 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: SGD byte length is too small, file is invalid or corrupted\n"); return false; } - + if (!m_etc1s_image_descs.try_resize(image_count)) { BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Out of memory\n"); return false; } - + memcpy(m_etc1s_image_descs.data(), pSrc, sizeof(ktx2_etc1s_image_desc) * image_count); pSrc += sizeof(ktx2_etc1s_image_desc) * image_count; @@ -26715,7 +26715,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_tables() failed, file is invalid or corrupted\n"); return false; } - + if (!m_etc1s_transcoder.decode_palettes( m_etc1s_header.m_endpoint_count, pEndpoint_data, m_etc1s_header.m_endpoints_byte_length, m_etc1s_header.m_selector_count, pSelector_data, m_etc1s_header.m_selectors_byte_length)) @@ -26723,7 +26723,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_palettes() failed, file is likely corrupted\n"); return false; } - + return true; } @@ -26764,7 +26764,7 @@ namespace basist while (src_left > sizeof(uint32_t)) { uint32_t l = basisu::read_le_dword(pSrc); - + pSrc += sizeof(uint32_t); src_left -= sizeof(uint32_t); @@ -26785,7 +26785,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n"); return false; } - + basisu::uint8_vec& key_data = m_key_values.back().m_key; basisu::uint8_vec& value_data = m_key_values.back().m_value; @@ -26807,7 +26807,7 @@ namespace basist l--; } while (key_data.back()); - + if (!value_data.try_resize(l)) { BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n"); @@ -26836,7 +26836,7 @@ namespace basist return true; } - + #endif // BASISD_SUPPORT_KTX2 bool basisu_transcoder_supports_ktx2() @@ -26863,7 +26863,7 @@ namespace basist /** * Collection of unused functions and const variables to work around \c * -Wunused-function and \c -Wunused-const-variable warnings. - * + * * \todo LTO does its thing so any unused are removed but is there a better way? */ void _basisu_translib_dummy() { diff --git a/contrib/previewers/win/basisthumbprovider.h b/contrib/previewers/win/basisthumbprovider.h index e73747cb..cca93a8f 100644 --- a/contrib/previewers/win/basisthumbprovider.h +++ b/contrib/previewers/win/basisthumbprovider.h @@ -4,7 +4,7 @@ #include /** - * + * */ class BasisThumbProvider : public IInitializeWithStream, public IThumbnailProvider { @@ -16,23 +16,23 @@ class BasisThumbProvider : public IInitializeWithStream, public IThumbnailProvid IFACEMETHODIMP_(ULONG) AddRef() override; // IUnknown::Release() IFACEMETHODIMP_(ULONG) Release() override; - + // IInitializeWithStream::Initialize() IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode) override; - + // IThumbnailProvider::GetThumbnail() IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha) override; protected: virtual ~BasisThumbProvider(); - + private: LONG count; IStream* stream; }; /** - * + * */ class BasisThumbProviderFactory : public IClassFactory { @@ -44,15 +44,15 @@ class BasisThumbProviderFactory : public IClassFactory IFACEMETHODIMP_(ULONG) AddRef() override; // IUnknown::Release() IFACEMETHODIMP_(ULONG) Release() override; - + // IClassFactory::CreateInstance() IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) override; // IClassFactory::LockServer() IFACEMETHODIMP LockServer(BOOL fLock) override; - + protected: virtual ~BasisThumbProviderFactory(); - + private: LONG count; }; diff --git a/contrib/previewers/win/helpers.cpp b/contrib/previewers/win/helpers.cpp index d4fab038..82100940 100644 --- a/contrib/previewers/win/helpers.cpp +++ b/contrib/previewers/win/helpers.cpp @@ -22,7 +22,7 @@ HBITMAP rgbToBitmap(const uint32_t* src, uint32_t const imgW, uint32_t const img * Creates a bitmap (a DIB) for the passed-in pixel size. Note that * negation of the height means top-down, origin upper-left, which is the * regular case. - * + * * TODO: 16-bit variant instead? */ assert(src && imgW && imgH); @@ -38,7 +38,7 @@ HBITMAP rgbToBitmap(const uint32_t* src, uint32_t const imgW, uint32_t const img HBITMAP hbmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &pixels, NULL, 0); /* * RGBA to BGRA conversion. - * + * * Note: we keep the alpha. */ if (hbmp && pixels) { diff --git a/contrib/previewers/win/helpers.h b/contrib/previewers/win/helpers.h index 691d5610..4fd23722 100644 --- a/contrib/previewers/win/helpers.h +++ b/contrib/previewers/win/helpers.h @@ -6,15 +6,15 @@ /** * Write a formatted string to the connected debugger (e.g. DebugView). - * + * * \param[in] fmt content to write in \c printf format (followed by optional arguments) */ void dprintf(char* const fmt, ...); /** * Converts raw RGBA data to a Windows BGRA bitmap. - * - * \param[in] src raw RGBA data + * + * \param[in] src raw RGBA data * \param[in] imgW width of the decoded image * \param[in] imgH height of the decoded image * \return handle to a bitmap (ownership passed to the caller) diff --git a/contrib/previewers/win/previewers.def b/contrib/previewers/win/previewers.def index 112ba882..87df6059 100644 --- a/contrib/previewers/win/previewers.def +++ b/contrib/previewers/win/previewers.def @@ -3,4 +3,3 @@ EXPORTS DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE - diff --git a/contrib/previewers/win/previewers.vcxproj b/contrib/previewers/win/previewers.vcxproj index ffeff961..162f0a2d 100644 --- a/contrib/previewers/win/previewers.vcxproj +++ b/contrib/previewers/win/previewers.vcxproj @@ -1,4 +1,4 @@ - + @@ -184,4 +184,4 @@ - \ No newline at end of file + diff --git a/contrib/previewers/win/previewers.vcxproj.filters b/contrib/previewers/win/previewers.vcxproj.filters index 90f70176..896eea2f 100644 --- a/contrib/previewers/win/previewers.vcxproj.filters +++ b/contrib/previewers/win/previewers.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -35,4 +35,4 @@ src - \ No newline at end of file + diff --git a/contrib/single_file_transcoder/README.md b/contrib/single_file_transcoder/README.md index 80c7fe17..73ae7b79 100644 --- a/contrib/single_file_transcoder/README.md +++ b/contrib/single_file_transcoder/README.md @@ -20,7 +20,7 @@ The combiner script can also generate separate amalgamated header and source fil ``` python3 combine.py -r ../../transcoder -o basisu_transcoder.h -p ../../transcoder/basisu_transcoder.h -python3 combine.py -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -k basisu_transcoder.h -o basisu_transcoder.cpp basisu_transcoder-in.cpp +python3 combine.py -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -k basisu_transcoder.h -o basisu_transcoder.cpp basisu_transcoder-in.cpp ``` @@ -29,6 +29,6 @@ Note: the amalgamation script was tested on Windows and Mac, requiring Python 3. Why? ---- -Because all it now takes to support Basis Universal is the addition of a single file, two if using the header, with no configuration or further build steps (the out-of-the-box defaults tailor the included formats for various platforms). +Because all it now takes to support Basis Universal is the addition of a single file, two if using the header, with no configuration or further build steps (the out-of-the-box defaults tailor the included formats for various platforms). The library is small, adding, for example, around 250kB to an Emscripten compiled WebAssembly project (with transcoding disabled for BC7 and ATC; disabling ASTC will remove a further 64kB, and `gzip` will approximately half the `wasm` file). diff --git a/contrib/single_file_transcoder/basisu_transcoder-in.cpp b/contrib/single_file_transcoder/basisu_transcoder-in.cpp index 27bc278b..b073a378 100644 --- a/contrib/single_file_transcoder/basisu_transcoder-in.cpp +++ b/contrib/single_file_transcoder/basisu_transcoder-in.cpp @@ -9,7 +9,7 @@ * Transcoder build options for known platforms (iOS has ETC, ASTC and PVRTC; * Emscripten adds DXT to iOS's options; Android adds PVRTC2 to Emscripten's * options; other platforms build all except FXT1). - * + * * See https://github.com/BinomialLLC/basis_universal#shrinking-the-transcoders-compiled-size */ #ifdef __APPLE__ @@ -38,7 +38,7 @@ /** * Collection of unused functions and const variables to work around \c * -Wunused-function and \c -Wunused-const-variable warnings. - * + * * \todo LTO does its thing so any unused are removed but is there a better way? */ void _basisu_translib_dummy() { diff --git a/contrib/single_file_transcoder/combine.py b/contrib/single_file_transcoder/combine.py index 3d1018d5..829d4331 100755 --- a/contrib/single_file_transcoder/combine.py +++ b/contrib/single_file_transcoder/combine.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Tool to bundle multiple C/C++ source files, inlining any includes. -# +# # Note: there are two types of exclusion options: the '-x' flag, which besides # excluding a file also adds an #error directive in place of the #include, and # the '-k' flag, which keeps the #include and doesn't inline the file. The @@ -10,10 +10,10 @@ # occurrence adds the error, and '-k' for headers that we wish to manually # include, such as a project's public API, for which occurrences after the first # are removed. -# +# # Todo: the error handling could be better, which currently throws and halts # (which is functional just not very friendly). -# +# # Author: Carl Woffenden, Numfum GmbH (this script is released under a CC0 license/Public Domain) import argparse, re, sys @@ -42,29 +42,29 @@ found: Set[Path] = set() # Compiled regex Patern to handle the following type of file includes: -# +# # #include "file" # #include "file" # # include "file" # #include "file" # #include "file" // comment # #include "file" // comment with quote " -# +# # And all combinations of, as well as ignoring the following: -# +# # #include # //#include "file" # /*#include "file"*/ -# +# # We don't try to catch errors since the compiler will do this (and the code is # expected to be valid before processing) and we don't care what follows the # file (whether it's a valid comment or not, since anything after the quoted # string is ignored) -# +# include_regex: Pattern = re.compile(r'^\s*#\s*include\s*"(.+?)"') # Simple tests to prove include_regex's cases. -# +# def test_match_include() -> bool: if (include_regex.match('#include "file"') and include_regex.match(' #include "file"') and @@ -81,19 +81,19 @@ def test_match_include() -> bool: return False # Compiled regex Patern to handle "#pragma once" in various formats: -# +# # #pragma once # #pragma once # # pragma once # #pragma once # #pragma once // comment -# +# # Ignoring commented versions, same as include_regex. -# +# pragma_regex: Pattern = re.compile(r'^\s*#\s*pragma\s*once\s*') # Simple tests to prove pragma_regex's cases. -# +# def text_match_pragma() -> bool: if (pragma_regex.match('#pragma once') and pragma_regex.match(' #pragma once') and @@ -109,7 +109,7 @@ def text_match_pragma() -> bool: # Finds 'file'. First the list of 'root' paths are searched, followed by the # the currently processing file's 'parent' path, returning a valid Path in # canonical form. If no match is found None is returned. -# +# def resolve_include(file: str, parent: Optional[Path] = None) -> Optional[Path]: for root in roots: found = root.joinpath(file).resolve() @@ -127,7 +127,7 @@ def resolve_include(file: str, parent: Optional[Path] = None) -> Optional[Path]: # and each entry resolved to its canonical path (like any include entry, either # from the list of root paths or the owning file's 'parent', which in this case # is case is the input file). The results are stored in 'resolved'. -# +# def resolve_excluded_files(file_list: Optional[List[str]], resolved: Set[Path], parent: Optional[Path] = None) -> None: if (file_list): for filename in file_list: @@ -138,23 +138,23 @@ def resolve_excluded_files(file_list: Optional[List[str]], resolved: Set[Path], error_line(f'Warning: excluded file not found: {filename}') # Writes 'line' to the open 'destn' (or stdout). -# +# def write_line(line: str) -> None: print(line, file=destn) # Logs 'line' to stderr. This is also used for general notifications that we # don't want to go to stdout (so the source can be piped). -# +# def error_line(line: Any) -> None: print(line, file=sys.stderr) # Inline the contents of 'file' (with any of its includes also inlined, etc.). -# +# # Note: text encoding errors are ignored and replaced with ? when reading the # input files. This isn't ideal, but it's more than likely in the comments than # code and a) the text editor has probably also failed to read the same content, # and b) the compiler probably did too. -# +# def add_file(file: Path, file_name: str = None) -> None: if (file.is_file()): if (not file_name): diff --git a/contrib/single_file_transcoder/combine.sh b/contrib/single_file_transcoder/combine.sh index aedae922..2b9ab2c5 100755 --- a/contrib/single_file_transcoder/combine.sh +++ b/contrib/single_file_transcoder/combine.sh @@ -1,13 +1,13 @@ #!/bin/sh -e # Tool to bundle multiple C/C++ source files, inlining any includes. -# +# # Note: this POSIX-compliant script is many times slower than the original bash # implementation (due to the grep calls) but it runs and works everywhere. -# +# # TODO: ROOTS, FOUND, etc., as arrays (since they fail on paths with spaces) # TODO: revert to Bash-only regex (the grep ones being too slow) -# +# # Script released under a CC0 license. # Common file roots diff --git a/contrib/single_file_transcoder/create_transcoder.sh b/contrib/single_file_transcoder/create_transcoder.sh index 7fe226d7..0c7a435b 100755 --- a/contrib/single_file_transcoder/create_transcoder.sh +++ b/contrib/single_file_transcoder/create_transcoder.sh @@ -39,5 +39,3 @@ else fi echo "Running simple.cpp: PASSED" fi - - diff --git a/contrib/single_file_transcoder/examples/emscripten.cpp b/contrib/single_file_transcoder/examples/emscripten.cpp index e56ae6af..ebdf9975 100644 --- a/contrib/single_file_transcoder/examples/emscripten.cpp +++ b/contrib/single_file_transcoder/examples/emscripten.cpp @@ -131,7 +131,7 @@ static GLchar const fragShader2D[] = /** * Helper to compile a shader. - * + * * \param type shader type * \param text shader source * \return the shader ID (or zero if compilation failed) @@ -199,7 +199,7 @@ struct posTex2d { /* * Possibly missing GL enums. - * + * * Note: GL_COMPRESSED_RGB_ETC1_WEBGL is the same as GL_ETC1_RGB8_OES */ #ifndef GL_ETC1_RGB8_OES @@ -233,7 +233,7 @@ static etc1_global_selector_codebook* globalCodebook = NULL; /** * Returns a supported compressed texture format for a given context. - * + * * \param[in] ctx WebGL context * \param[in] alpha \c true if the texture has an alpha channel * \return corresponding Basis format @@ -243,7 +243,7 @@ static transcoder_texture_format supports(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE const /* * Test for both prefixed and non-prefixed versions. This should grab iOS * and other ImgTec GPUs first as a preference. - * + * * TODO: do older iOS expose ASTC to the browser and does it transcode to RGBA? */ static bool const pvr = GL_HAS_EXT(ctx, "WEBKIT_WEBGL_compressed_texture_pvrtc") @@ -291,7 +291,7 @@ static transcoder_texture_format supports(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE const #endif /* * Finally ETC1, falling back on RGBA. - * + * * TODO: we might just prefer to transcode to dithered 565 once available */ static bool const etc1 = GL_HAS_EXT(ctx, "WEBGL_compressed_texture_etc1"); @@ -306,10 +306,10 @@ static transcoder_texture_format supports(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE const /** * Returns the equivalent GL type given a BasisU type. - * + * * \note This relies on \c #supports() returning the supported formats, and so * only converts to the GL equivalents (without further testing for support). - * + * * \param[in] type BasisU transcode target * \return equivalent GL type */ @@ -340,13 +340,13 @@ static GLenum toGlType(transcoder_texture_format const type) { /** * Uploads the texture. - * + * * \param[in] ctx ctx WebGL context * \param[in] name texture \e name * \param[in] data \c .basis file content * \param[in] size number of bytes in \a data * \return \c true if the texture was decoded and created - * + * * \todo reuse the decode buffer (the first mips level should be able to contain the rest) */ bool upload(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE const ctx, GLuint const name, const uint8_t* const data, size_t const size) { @@ -477,7 +477,7 @@ static EM_BOOL initContext() { static void tick() { glClearColor(1.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + if (uRotId >= 0) { glUniform1f(uRotId, rotDeg); rotDeg += 0.1f; @@ -486,7 +486,7 @@ static void tick() { } glBindTexture(GL_TEXTURE_2D, txName[(lround(rotDeg / 45) & 1) != 0]); } - + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); glFlush(); } @@ -501,10 +501,10 @@ int main() { if ((progId = glCreateProgram())) { vertId = compileShader(GL_VERTEX_SHADER, vertShader2D); fragId = compileShader(GL_FRAGMENT_SHADER, fragShader2D); - + glBindAttribLocation(progId, GL_VERT_POSXY_ID, "aPos"); glBindAttribLocation(progId, GL_VERT_TXUV0_ID, "aUV0"); - + glAttachShader(progId, vertId); glAttachShader(progId, fragId); glLinkProgram (progId); @@ -514,7 +514,7 @@ int main() { if (uTx0Id >= 0) { glUniform1i(uTx0Id, 0); } - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glDisable(GL_DITHER); @@ -522,7 +522,7 @@ int main() { glCullFace(GL_BACK); glEnable(GL_CULL_FACE); } - + GLuint vertsBuf = 0; GLuint indexBuf = 0; // Create the textured quad (vert positions then UVs) @@ -551,14 +551,14 @@ int main() { sizeof(index2d), index2d, GL_STATIC_DRAW); glEnableVertexAttribArray(GL_VERT_POSXY_ID); glEnableVertexAttribArray(GL_VERT_TXUV0_ID); - + glGenTextures(2, txName); if (upload(glCtx, txName[0], srcRgb, sizeof srcRgb) && upload(glCtx, txName[1], srcRgba, sizeof srcRgba)) { printf("Decoded!\n"); } - + emscripten_set_main_loop(tick, 0, EM_FALSE); emscripten_exit_with_live_runtime(); } else { diff --git a/contrib/single_file_transcoder/examples/simple.cpp b/contrib/single_file_transcoder/examples/simple.cpp index 538b8ec6..b64a5345 100644 --- a/contrib/single_file_transcoder/examples/simple.cpp +++ b/contrib/single_file_transcoder/examples/simple.cpp @@ -8,7 +8,7 @@ * \code * cc -std=c++11 -lstdc++ -fno-strict-aliasing simple.cpp * \endcode - * + * * Example code released under a CC0 license. */ #include "../basisu_transcoder.cpp" @@ -37,7 +37,7 @@ static uint8_t const srcRgb[] = { */ int main() { basisu_transcoder_init(); - + basisu_transcoder transcoder; if (transcoder.validate_header(srcRgb, sizeof srcRgb)) { basisu_file_info fileInfo; diff --git a/encoder/3rdparty/android_astc_decomp.cpp b/encoder/3rdparty/android_astc_decomp.cpp index a667d0d6..75f4024b 100644 --- a/encoder/3rdparty/android_astc_decomp.cpp +++ b/encoder/3rdparty/android_astc_decomp.cpp @@ -21,7 +21,7 @@ * rg: Removed external dependencies, minor fix to decompress() so it converts non-sRGB * output to 8-bits correctly. I've compared this decoder's output * vs. astc-codec with random inputs. - * + * *//*! * \file * \brief ASTC Utilities. @@ -204,7 +204,7 @@ namespace basisu_astc return (v >= l) && (v < h); } -namespace astc +namespace astc { using std::vector; @@ -244,7 +244,7 @@ inline bool isBitSet (deUint32 src, int ndx) inline deUint32 reverseBits (deUint32 src, int numBits) { DE_ASSERT(basisu_astc::inRange(numBits, 0, 32)); - + deUint32 result = 0; for (int i = 0; i < numBits; i++) result |= ((src >> i) & 1) << (numBits-1-i); @@ -516,7 +516,7 @@ class BitAccessStream const int high = m_ndx + numBitsFromSrc - 1; m_ndx += num; - + return m_forward ? m_src.getBits(m_startNdxInSrc + low, m_startNdxInSrc + high) : reverseBits(m_src.getBits(m_startNdxInSrc - high, m_startNdxInSrc - low), numBitsFromSrc); } @@ -593,7 +593,7 @@ ASTCBlockMode getASTCBlockMode (deUint32 blockModeData) const deUint32 r1 = getBit(blockModeData, 2); const deUint32 r2 = getBit(blockModeData, 3); const deUint32 i78 = getBits(blockModeData, 7, 8); - + r = (r2 << 2) | (r1 << 1) | (r0 << 0); if (i78 == 3) @@ -720,13 +720,13 @@ DecompressResult decodeVoidExtentBlock (void* dst, const Block128& blockData, in const deUint32 maxTExtent = blockData.getBits(51, 63); const bool allExtentsAllOnes = (minSExtent == 0x1fff) && (maxSExtent == 0x1fff) && (minTExtent == 0x1fff) && (maxTExtent == 0x1fff); const bool isHDRBlock = blockData.isBitSet(9); - + if ((isLDRMode && isHDRBlock) || (!allExtentsAllOnes && (minSExtent >= maxSExtent || minTExtent >= maxTExtent))) { setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); return DECOMPRESS_RESULT_ERROR; } - + const deUint32 rgba[4] = { blockData.getBits(64, 79), @@ -839,8 +839,8 @@ void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" -#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" +#endif #endif switch (numValues) { @@ -856,7 +856,7 @@ void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif const deUint32 T = (T7 << 7) | (T56 << 5) | (T4 << 4) | (T23 << 2) | (T01 << 0); @@ -905,8 +905,8 @@ void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" -#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" +#endif #endif switch (numValues) { @@ -920,7 +920,7 @@ void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif const deUint32 Q = (Q56 << 5) | (Q34 << 3) | (Q012 << 0); @@ -1066,7 +1066,7 @@ void decodeHDREndpointMode7 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deU const deUint32 majComp = (m10 != 3) ? m10 : (m23 != 3) ? m23 : 0; - + const deUint32 mode = (m10 != 3) ? m23 : (m23 != 3) ? 4 : 5; @@ -1189,7 +1189,7 @@ void decodeHDREndpointMode11 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, de DE_ASSERT(mode < DE_LENGTH_OF_ARRAY(numDBits)); d0 = signExtend(d0, numDBits[mode]); d1 = signExtend(d1, numDBits[mode]); - + const int shiftAmount = (mode >> 1) ^ 3; a = (uint32_t)a << shiftAmount; c = (uint32_t)c << shiftAmount; @@ -1217,7 +1217,7 @@ void decodeHDREndpointMode11 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, de void decodeHDREndpointMode15(UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3, deUint32 v4, deUint32 v5, deUint32 v6In, deUint32 v7In) { decodeHDREndpointMode11(e0, e1, v0, v1, v2, v3, v4, v5); - + const deUint32 mode = (getBit(v7In, 7) << 1) | getBit(v6In, 7); deInt32 v6 = (deInt32)getBits(v6In, 0, 6); deInt32 v7 = (deInt32)getBits(v7In, 0, 6); @@ -1425,7 +1425,7 @@ void computeColorEndpoints (ColorEndpointPair* dst, const Block128& blockData, c { const int colorEndpointDataStart = (numPartitions == 1) ? 17 : 29; ISEDecodedResult colorEndpointData[18]; - + { BitAccessStream dataStream(blockData, colorEndpointDataStart, numBitsAvailable, true); decodeISE(&colorEndpointData[0], numColorEndpointValues, dataStream, iseParams); @@ -1470,7 +1470,7 @@ void unquantizeWeights (deUint32 dst[64], const ISEDecodedResult* weightGrid, co const deUint32 a = getBit(weightGrid[weightNdx].m, 0); const deUint32 b = getBit(weightGrid[weightNdx].m, 1); const deUint32 c = getBit(weightGrid[weightNdx].m, 2); - + const deUint32 A = (a == 0) ? 0 : (1<<7)-1; const deUint32 B = (rangeCase == 2) ? 0 : (rangeCase == 3) ? 0 @@ -1523,7 +1523,7 @@ void interpolateWeights (TexelWeightPair* dst, const deUint32 (&unquantizedWeigh const deUint32 i01 = i00 + 1; const deUint32 i10 = i00 + blockMode.weightGridWidth; const deUint32 i11 = i00 + blockMode.weightGridWidth + 1; - + // These addresses can be out of bounds, but respective weights will be 0 then. DE_ASSERT(deInBounds32(i00, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w00 == 0); DE_ASSERT(deInBounds32(i01, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w01 == 0); @@ -1537,7 +1537,7 @@ void interpolateWeights (TexelWeightPair* dst, const deUint32 (&unquantizedWeigh const deUint32 p01 = unquantizedWeights[(i01 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; const deUint32 p10 = unquantizedWeights[(i10 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; const deUint32 p11 = unquantizedWeights[(i11 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; - + dst[texelY*blockWidth + texelX].w[texelWeightNdx] = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4; } } @@ -1713,7 +1713,7 @@ DecompressResult setTexelColors (void* dst, ColorEndpointPair* colorEndpoints, T ((float*)dst)[texelNdx * 4 + channelNdx] = deFloat16To32(isFloat16InfOrNan(cf) ? 0x7bff : cf); } - + } // channelNdx } } // texelX @@ -1725,26 +1725,26 @@ DecompressResult setTexelColors (void* dst, ColorEndpointPair* colorEndpoints, T DecompressResult decompressBlock (void* dst, const Block128& blockData, int blockWidth, int blockHeight, bool isSRGB, bool isLDR) { DE_ASSERT(isLDR || !isSRGB); - + // Decode block mode. const ASTCBlockMode blockMode = getASTCBlockMode(blockData.getBits(0, 10)); - + // Check for block mode errors. if (blockMode.isError) { setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); return DECOMPRESS_RESULT_ERROR; } - + // Separate path for void-extent. if (blockMode.isVoidExtent) return decodeVoidExtentBlock(dst, blockData, blockWidth, blockHeight, isSRGB, isLDR); - + // Compute weight grid values. const int numWeights = computeNumWeights(blockMode); const int numWeightDataBits = computeNumRequiredBits(blockMode.weightISEParams, numWeights); const int numPartitions = (int)blockData.getBits(11, 12) + 1; - + // Check for errors in weight grid, partition and dual-plane parameters. if ((numWeights > 64) || (numWeightDataBits > 96) || @@ -1756,7 +1756,7 @@ DecompressResult decompressBlock (void* dst, const Block128& blockData, int bloc setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); return DECOMPRESS_RESULT_ERROR; } - + // Compute number of bits available for color endpoint data. const bool isSingleUniqueCem = (numPartitions == 1) || (blockData.getBits(23, 24) == 0); @@ -1770,28 +1770,28 @@ DecompressResult decompressBlock (void* dst, const Block128& blockData, int bloc : (numPartitions == 3) ? 4 : (numPartitions == 2) ? 1 : 0); - + // Decode color endpoint modes. deUint32 colorEndpointModes[4]; decodeColorEndpointModes(&colorEndpointModes[0], blockData, numPartitions, extraCemBitsStart); const int numColorEndpointValues = computeNumColorEndpointValues(colorEndpointModes, numPartitions); - + // Check for errors in color endpoint value count. if ((numColorEndpointValues > 18) || (numBitsForColorEndpoints < (int)deDivRoundUp32(13*numColorEndpointValues, 5))) { setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); return DECOMPRESS_RESULT_ERROR; } - + // Compute color endpoints. ColorEndpointPair colorEndpoints[4]; computeColorEndpoints(&colorEndpoints[0], blockData, &colorEndpointModes[0], numPartitions, numColorEndpointValues, computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues), numBitsForColorEndpoints); - + // Compute texel weights. TexelWeightPair texelWeights[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT]; computeTexelWeights(&texelWeights[0], blockData, blockWidth, blockHeight, blockMode); - + // Set texel colors. const int ccs = blockMode.isDualPlane ? (int)blockData.getBits(extraCemBitsStart-2, extraCemBitsStart-1) : -1; const deUint32 partitionIndexSeed = (numPartitions > 1) ? blockData.getBits(13, 22) : (deUint32)-1; @@ -1844,7 +1844,7 @@ int isHDR(const Block128& blockData, int blockWidth, int blockHeight) // Decode color endpoint modes. deUint32 colorEndpointModes[4]; decodeColorEndpointModes(&colorEndpointModes[0], blockData, numPartitions, extraCemBitsStart); - + for (int i = 0; i < numPartitions; i++) { if (isColorEndpointModeHDR(colorEndpointModes[i])) @@ -1994,7 +1994,7 @@ bool decompress_ldr(uint8_t *pDst, const uint8_t * data, bool isSRGB, int blockW float linear[MAX_BLOCK_WIDTH * MAX_BLOCK_HEIGHT * 4]; const Block128 blockData(data); - + // isSRGB is true, this writes uint8_t's. Otherwise it writes floats. if (decompressBlock(isSRGB ? (void*)pDst : (void*)&linear[0], blockData, blockWidth, blockHeight, isSRGB, true) != DECOMPRESS_RESULT_VALID_BLOCK) { @@ -2030,7 +2030,7 @@ bool decompress_hdr(float* pDstRGBA, const uint8_t* data, int blockWidth, int bl } convert_to_half_prec(blockWidth * blockHeight * 4, pDstRGBA); - + return true; } @@ -2039,7 +2039,7 @@ bool is_hdr(const uint8_t* data, int blockWidth, int blockHeight, bool &is_hdr) is_hdr = false; const Block128 blockData(data); - + int status = isHDR(blockData, blockWidth, blockHeight); if (status < 0) { diff --git a/encoder/3rdparty/android_astc_decomp.h b/encoder/3rdparty/android_astc_decomp.h index ad13093a..07bcd4e4 100644 --- a/encoder/3rdparty/android_astc_decomp.h +++ b/encoder/3rdparty/android_astc_decomp.h @@ -33,7 +33,7 @@ namespace astc { // Unpacks a single ASTC block to pDst -// If isSRGB is true, the spec requires the decoder to scale the LDR 8-bit endpoints to 16-bit before interpolation slightly differently, +// If isSRGB is true, the spec requires the decoder to scale the LDR 8-bit endpoints to 16-bit before interpolation slightly differently, // which will lead to different outputs. So be sure to set it correctly (ideally it should match whatever the encoder did). bool decompress_ldr(uint8_t* pDst, const uint8_t* data, bool isSRGB, int blockWidth, int blockHeight); bool decompress_hdr(float* pDstRGBA, const uint8_t* data, int blockWidth, int blockHeight); diff --git a/encoder/3rdparty/qoi.h b/encoder/3rdparty/qoi.h index be8a2d53..2c29b39d 100644 --- a/encoder/3rdparty/qoi.h +++ b/encoder/3rdparty/qoi.h @@ -580,7 +580,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) { pixels[px_pos + 0] = px.rgba.r; pixels[px_pos + 1] = px.rgba.g; pixels[px_pos + 2] = px.rgba.b; - + if (channels == 4) { pixels[px_pos + 3] = px.rgba.a; } diff --git a/encoder/3rdparty/tinydds.h b/encoder/3rdparty/tinydds.h index d8bc17e6..41e1d6f1 100644 --- a/encoder/3rdparty/tinydds.h +++ b/encoder/3rdparty/tinydds.h @@ -2040,7 +2040,7 @@ bool TinyDDS_WriteImage(TinyDDS_WriteCallbacks const *callbacks, // rg 8/27/2024: The original tinydds.h code is wrong for mipmapped cubemaps. // I'm going to work around this by having the caller compose the top mip data correctly. // https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-file-layout-for-cubic-environment-maps - for (uint32_t mipMapLevel = 0; mipMapLevel < header.mipMapCount; mipMapLevel++) + for (uint32_t mipMapLevel = 0; mipMapLevel < header.mipMapCount; mipMapLevel++) { // rg: Adding this check, in case the caller wants to compose all the data themselves. if (mipmapsizes[mipMapLevel]) diff --git a/encoder/3rdparty/tinyexr.h b/encoder/3rdparty/tinyexr.h index a2a065a0..8a6ae0ae 100644 --- a/encoder/3rdparty/tinyexr.h +++ b/encoder/3rdparty/tinyexr.h @@ -1396,7 +1396,7 @@ static bool CompressZip(unsigned char *dst, memcpy(dst, ret, outSize); free(ret); - + compressedSize = outSize; #else uLong outSize = compressBound(static_cast(src_size)); @@ -5860,7 +5860,7 @@ static bool ReconstructTileOffsets(OffsetData& offset_data, if (size_t(tileX) >= offset_data.offsets[size_t(level_idx)][size_t(tileY)].size()) { return false; } - + offset_data.offsets[size_t(level_idx)][size_t(tileY)][size_t(tileX)] = tileOffset; } } @@ -6871,7 +6871,7 @@ struct MemoryMappedFile { if (read_bytes != size) { // TODO: Try to read data until reading `size` bytes. fclose(fp); - size = 0; + size = 0; data = nullptr; return; } @@ -7717,7 +7717,7 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images, SetErrorMessage("Failed to compute Tile offsets", err); return (size_t)TINYEXR_ERROR_INVALID_DATA; - + } total_chunk_count += chunk_count[i]; } @@ -8585,7 +8585,7 @@ int EXRNumLevels(const EXRImage* exr_image) { const EXRImage* level_image = exr_image; #if 0 - while ((level_image = level_image->next_level)) + while ((level_image = level_image->next_level)) ++levels; #else for (; ;) diff --git a/encoder/basisu_astc_hdr_6x6_enc.cpp b/encoder/basisu_astc_hdr_6x6_enc.cpp index 6d586326..cff41358 100644 --- a/encoder/basisu_astc_hdr_6x6_enc.cpp +++ b/encoder/basisu_astc_hdr_6x6_enc.cpp @@ -21,13 +21,13 @@ using namespace basist::astc_6x6_hdr; namespace astc_6x6_hdr { -static void atomic_max(std::atomic& atomic_var, uint32_t new_value) +static void atomic_max(std::atomic& atomic_var, uint32_t new_value) { uint32_t current = atomic_var.load(std::memory_order_relaxed); for ( ; ; ) { uint32_t new_max = std::max(current, new_value); - if (atomic_var.compare_exchange_weak(current, new_max, std::memory_order_relaxed, std::memory_order_relaxed)) + if (atomic_var.compare_exchange_weak(current, new_max, std::memory_order_relaxed, std::memory_order_relaxed)) break; } } @@ -163,7 +163,7 @@ static float inversePQ(float E) // Highest error is for values less than SMALLEST_PQ_VAL_IN. // // Approximation is round trip lossless for 10-12 bits at [0,10000] nits: -// for x [0,1024] (SCALE=1023) or for x [0,4095] (SCALE=4096): +// for x [0,1024] (SCALE=1023) or for x [0,4095] (SCALE=4096): // round(forwardPQTab(inversePQ(x / SCALE)) * SCALE) == x // // bfloat16 has enough precision to handle 8-bit sRGB to linear conversions: @@ -175,7 +175,7 @@ const int PQ_APPROX_EXP_RANGE = (PQ_APPROX_MAX_EXP - PQ_APPROX_MIN_EXP + 1); const float SMALLEST_PQ_VAL_IN = 0.000015258829080f; const float SMALLEST_PQ_VAL = 0.000551903737f; // forwardPQ(SMALLEST_PQ_VAL_IN) -const float LARGEST_PQ_VAL = 1.251312f; +const float LARGEST_PQ_VAL = 1.251312f; float g_pq_approx_tabs[PQ_APPROX_EXP_RANGE][128]; @@ -247,7 +247,7 @@ static inline float forwardPQTab(float v) } // 100 nits = ~.5 i -// This converts absolute linear RGB light in either REC 709 or REC2020/BT2100 color gamut to ICtCp, a coding space where Ct is scaled by 2. +// This converts absolute linear RGB light in either REC 709 or REC2020/BT2100 color gamut to ICtCp, a coding space where Ct is scaled by 2. // To convert to perceptual ITP for error/distance calculations, multiply the result Ct by .5 (or set itp_flag to true). // Assumes REC 709 input, or REC 2020/BT.2100 RGB input if rec2020_bt2100_color_gamut is true. // @@ -267,7 +267,7 @@ static inline float forwardPQTab(float v) static void linear_rgb_to_ictcp(const vec3F& rgb_in, vec3F& ictcp, bool itp_flag = false, bool rec2020_bt2100_color_gamut = false) { vec3F rgb_2100(rgb_in); - + float l, m, s; if (!rec2020_bt2100_color_gamut) { @@ -661,7 +661,7 @@ class vp_tree m_nodes[0].m_outer_node = -1; uint_vec inner_list, outer_list; - + inner_list.reserve(n / 2); outer_list.reserve(n / 2); @@ -710,8 +710,8 @@ class vp_tree enum { MaxSupportedSize = 256 + 1 }; public: - result_queue() : - m_cur_size(0) + result_queue() : + m_cur_size(0) { } @@ -764,14 +764,14 @@ class vp_tree bool pop() { - if (m_cur_size == 0) + if (m_cur_size == 0) return false; m_elements[1] = m_elements[m_cur_size--]; down_heap(1); return true; } - + float get_highest_dist() const { if (!m_cur_size) @@ -779,7 +779,7 @@ class vp_tree return top().m_dist; } - + private: result_array_type m_elements; size_t m_cur_size; @@ -813,7 +813,7 @@ class vp_tree } } }; - + void find_nearest(uint32_t num_subsets, const partition_pattern_vec& desired_pat, result_queue& results, uint32_t max_results) { assert((num_subsets >= 2) && (num_subsets <= 3)); @@ -878,7 +878,7 @@ class vp_tree if (m_nodes[node_index].m_outer_node >= 0) { - if ( (results.get_size() < max_results) || + if ( (results.get_size() < max_results) || ((m_nodes[node_index].m_dist - best_dist_to_vantage) <= results.get_highest_dist()) ) { @@ -894,7 +894,7 @@ class vp_tree if (m_nodes[node_index].m_inner_node >= 0) { - if ( (results.get_size() < max_results) || + if ( (results.get_size() < max_results) || ((best_dist_to_vantage - m_nodes[node_index].m_dist) <= results.get_highest_dist()) ) { @@ -903,13 +903,13 @@ class vp_tree } } } - + void find_nearest_at_node_non_recursive(int init_node_index, uint32_t num_desired_pats, const partition_pattern_vec* pDesired_pats, result_queue& results, uint32_t max_results) { uint_vec node_stack; node_stack.reserve(16); node_stack.push_back(init_node_index); - + do { const uint32_t node_index = node_stack.back(); @@ -984,7 +984,7 @@ class vp_tree m_nodes.resize(m_nodes.size() + 1); const uint32_t new_node_index = m_nodes.size_u32() - 1; - + m_nodes[new_node_index].m_vantage_point = pUnique_pats[root_idx.first]; m_nodes[new_node_index].m_point_index = root_idx.first; m_nodes[new_node_index].m_dist = root_idx.second; @@ -1038,17 +1038,17 @@ class vp_tree basisu::vector< std::pair > dists; dists.reserve(n); - + float_vec float_dists; float_dists.reserve(n); - + for (uint32_t pat_indices_iter = 0; pat_indices_iter < n; pat_indices_iter++) { const uint32_t split_pat_index = pat_indices[pat_indices_iter]; assert(split_pat_index < num_unique_pats); const partition_pattern_vec& trial_vantage = pUnique_pats[split_pat_index]; - + dists.resize(0); float_dists.resize(0); @@ -1059,7 +1059,7 @@ class vp_tree if (pat_index == split_pat_index) continue; - + float dist = trial_vantage.get_distance(pUnique_pats[pat_index]); dists.emplace_back(std::pair(dist, pat_index)); @@ -1079,13 +1079,13 @@ class vp_tree split_dist = (split_dist + dists[(num_dists / 2) - 1].first) * .5f; uint32_t total_inner = 0, total_outer = 0; - + for (uint32_t j = 0; j < n; j++) { const uint32_t pat_index = pat_indices[j]; if (pat_index == split_pat_index) continue; - + float dist = trial_vantage.get_distance(pUnique_pats[pat_index]); if (dist <= split_dist) @@ -1095,7 +1095,7 @@ class vp_tree } float split_metric = (float)minimum(total_inner, total_outer) / (float)maximum(total_inner, total_outer); - + if ( (split_metric > best_split_metric) || ((split_metric == best_split_metric) && (s.m_var > best_split_var)) ) { @@ -1114,7 +1114,7 @@ struct partition { uint64_t m_p; - inline partition() : + inline partition() : m_p(0) { } @@ -1171,19 +1171,19 @@ static void init_partitions2_6x6() { uint64_t p_bits = 0; uint64_t p_bits_inv = 0; - + for (uint32_t y = 0; y < 6; y++) { for (uint32_t x = 0; x < 6; x++) { uint64_t p = astc_helpers::compute_texel_partition(i, x, y, 0, 2, false); assert(p < 2); - + p_bits |= (p << (x + y * 6)); p_bits_inv |= ((1 - p) << (x + y * 6)); } } - + if (!p_bits) continue; if (p_bits == ((1ULL << 36) - 1)) @@ -1205,13 +1205,13 @@ static void init_partitions2_6x6() BASISU_NOTE_UNUSED(res); } } - + uint32_t num_unique_partitions2 = 0; - + for (const auto& r : phash) { assert(r.second < 1024); - + const uint32_t unique_index = num_unique_partitions2; assert(unique_index < NUM_UNIQUE_PARTITIONS2); @@ -1220,7 +1220,7 @@ static void init_partitions2_6x6() pat_vec[i] = (uint8_t)((r.first >> i) & 1); g_partitions2[unique_index] = pat_vec; - + assert(g_part2_unique_index_to_seed[unique_index] == r.second); g_part2_seed_to_unique_index[r.second] = unique_index; @@ -1259,7 +1259,7 @@ static bool estimate_partition2_6x6( int* pBest_parts, uint32_t num_best_parts) { const uint32_t BLOCK_W = 6, BLOCK_H = 6, BLOCK_T = BLOCK_W * BLOCK_H; - + vec3F training_vecs[BLOCK_T], mean(0.0f); for (uint32_t i = 0; i < BLOCK_T; i++) @@ -1320,10 +1320,10 @@ static bool estimate_partition2_6x6( desired_part.m_parts[i] = proj < 0.0f; } #endif - + //interval_timer tm; //tm.start(); - + #if BRUTE_FORCE_PART_SEARCH uint32_t part_similarity[NUM_UNIQUE_PARTITIONS2]; @@ -1431,7 +1431,7 @@ static bool encode_block_2_subsets( part_pixel_index[part_index][l] = (uint8_t)(x + y * BLOCK_W); part_total_pixels[part_index] = l + 1; - } // x + } // x } // y uint8_t blk_endpoints[2][basist::NUM_MODE11_ENDPOINTS]; @@ -1528,7 +1528,7 @@ static bool encode_block_2_subsets( grid_w, grid_h, // dest/to dimension (grid size) desired_weights, // these are dequantized weights, NOT ISE symbols, [by][bx] downsampled_weights); // [wy][wx] - + best_log_blk.m_partition_id = (uint16_t)p_seed; memcpy(best_log_blk.m_endpoints, blk_endpoints[0], num_endpoint_vals); memcpy(best_log_blk.m_endpoints + num_endpoint_vals, blk_endpoints[1], num_endpoint_vals); @@ -1588,7 +1588,7 @@ static void init_partitions3_6x6() partition3_hash_map part3_hash; part3_hash.reserve(512); - + for (uint32_t seed_index = 0; seed_index < 1024; seed_index++) { partition_pattern_vec p3; @@ -1691,13 +1691,13 @@ static bool estimate_partition3_6x6( if ((cluster_centroids[0] == cluster_centroids[2]) || (cluster_centroids[1] == cluster_centroids[2])) return false; - + uint32_t cluster_pixels[NUM_SUBSETS][BLOCK_T]; uint32_t num_cluster_pixels[NUM_SUBSETS]; vec3F new_cluster_means[NUM_SUBSETS]; const uint32_t NUM_ITERS = 4; - + for (uint32_t s = 0; s < NUM_ITERS; s++) { memset(num_cluster_pixels, 0, sizeof(num_cluster_pixels)); @@ -1705,9 +1705,9 @@ static bool estimate_partition3_6x6( for (uint32_t i = 0; i < BLOCK_T; i++) { - float d[NUM_SUBSETS] = { - training_vecs[i].squared_distance(cluster_centroids[0]), - training_vecs[i].squared_distance(cluster_centroids[1]), + float d[NUM_SUBSETS] = { + training_vecs[i].squared_distance(cluster_centroids[0]), + training_vecs[i].squared_distance(cluster_centroids[1]), training_vecs[i].squared_distance(cluster_centroids[2]) }; float min_d = d[0]; @@ -1734,7 +1734,7 @@ static bool estimate_partition3_6x6( cluster_centroids[j] = new_cluster_means[j] / (float)num_cluster_pixels[j]; } } // s - + partition_pattern_vec desired_part; for (uint32_t p = 0; p < NUM_SUBSETS; p++) { @@ -1769,7 +1769,7 @@ static bool estimate_partition3_6x6( } // part_index; std::sort(part_similarity, part_similarity + NUM_UNIQUE_PARTITIONS3); - + for (uint32_t i = 0; i < num_best_parts; i++) pBest_parts[i] = part_similarity[i] & 0xFFFF; #else @@ -1797,15 +1797,15 @@ static bool encode_block_3_subsets( astc_hdr_codec_base_options& coptions, bool uber_mode_flag, const int* pEst_patterns, int num_est_patterns, - uint32_t comp_level, + uint32_t comp_level, opt_mode_t mode11_opt_mode) { BASISU_NOTE_UNUSED(uber_mode_flag); const uint32_t BLOCK_W = 6, BLOCK_H = 6, NUM_SUBSETS = 3; const uint32_t num_endpoint_vals = astc_helpers::get_num_cem_values(cem); - + res.m_valid = false; - + double best_e = BIG_FLOAT_VAL; astc_helpers::log_astc_block best_log_blk; @@ -1847,7 +1847,7 @@ static bool encode_block_3_subsets( part_pixel_index[part_index][l] = (uint8_t)(x + y * BLOCK_W); part_total_pixels[part_index] = l + 1; - } // x + } // x } // y uint8_t blk_endpoints[NUM_SUBSETS][basist::NUM_MODE11_ENDPOINTS]; @@ -1885,7 +1885,7 @@ static bool encode_block_3_subsets( blk_endpoints[part_iter], blk_weights[part_iter], coptions, - false, best_log_blk.m_endpoint_ise_range, uber_mode_flag, false, + false, best_log_blk.m_endpoint_ise_range, uber_mode_flag, false, FIRST_MODE11_SUBMODE_INDEX, MAX_MODE11_SUBMODE_INDEX, false, mode11_opt_mode); } @@ -1914,7 +1914,7 @@ static bool encode_block_3_subsets( for (uint32_t p = 0; p < NUM_SUBSETS; p++) memcpy(best_log_blk.m_endpoints + num_endpoint_vals * p, blk_endpoints[p], num_endpoint_vals); - + memcpy(best_log_blk.m_weights, ise_weights, BLOCK_W * BLOCK_H); } } @@ -1947,7 +1947,7 @@ static bool encode_block_3_subsets( astc_helpers::log_astc_block trial_blk(best_log_blk); trial_blk.m_partition_id = (uint16_t)g_part3_unique_index_to_seed[unique_part_index]; - + for (uint32_t p = 0; p < NUM_SUBSETS; p++) memcpy(trial_blk.m_endpoints + num_endpoint_vals * p, blk_endpoints[p], num_endpoint_vals); @@ -2017,7 +2017,7 @@ static uint32_t encode_values(bitwise_coder &coder, uint32_t total_values, const uint32_t total_tq_values = 0, tq_accum = 0, tq_mul = 1; assert((total_values) && (total_values <= MAX_VALS)); - + const uint32_t ep_bits = astc_helpers::g_ise_range_table[endpoint_range][0]; const uint32_t ep_trits = astc_helpers::g_ise_range_table[endpoint_range][1]; const uint32_t ep_quints = astc_helpers::g_ise_range_table[endpoint_range][2]; @@ -2060,7 +2060,7 @@ static uint32_t encode_values(bitwise_coder &coder, uint32_t total_values, const } uint32_t total_bits_output = 0; - + for (uint32_t i = 0; i < total_tq_values; i++) { const uint32_t num_bits = ep_trits ? 8 : 7; @@ -2131,7 +2131,7 @@ static void code_block(bitwise_coder& coder, { const int unique_partition_index = g_part2_seed_to_unique_index[log_blk.m_partition_id]; assert(unique_partition_index != -1); - + coder.put_truncated_binary(unique_partition_index, NUM_UNIQUE_PARTITIONS2); } else if (log_blk.m_num_partitions == 3) @@ -2141,7 +2141,7 @@ static void code_block(bitwise_coder& coder, coder.put_truncated_binary(unique_partition_index, NUM_UNIQUE_PARTITIONS3); } - + encode_values(coder, num_endpoint_vals * log_blk.m_num_partitions, log_blk.m_endpoints, log_blk.m_endpoint_ise_range); } @@ -2175,7 +2175,7 @@ struct smooth_map_params // 3x3 region m_max_smooth_std_dev = 100.0f; m_smooth_max_mse_scale = 13000.0f; - + // 7x7 region m_max_med_smooth_std_dev = 9.0f; m_med_smooth_max_mse_scale = 15000.0f; @@ -2243,7 +2243,7 @@ static void filter_block(uint32_t grid_x, uint32_t grid_y, const vec3F* pSrc_blo for (uint32_t c = 0; c < 3; c++) { const basist::half_float h = basist::float_to_half(temp_block[y][x][c]); - + pDst_block_half3[x + y * 6][c] = h; pDst_block_q16[x + y * 6][c] = (float)half_to_qlog16(h); } @@ -2264,9 +2264,9 @@ static void filter_block(uint32_t grid_x, uint32_t grid_y, const vec3F* pSrc_blo for (uint32_t i = 0; i < pCol_lists[y].n; i++) p += temp_block[pCol_lists[y].p[i].pixel][x] * pCol_lists[y].p[i].weight; - + p.clamp(0.0f, basist::ASTC_HDR_MAX_VAL); - + for (uint32_t c = 0; c < 3; c++) { const basist::half_float h = basist::float_to_half(p[c]); @@ -2276,7 +2276,7 @@ static void filter_block(uint32_t grid_x, uint32_t grid_y, const vec3F* pSrc_blo } pDst_block_q16[x + y * 6][3] = 0.0f; - + } // x } // y } @@ -2367,7 +2367,7 @@ static void filter_block(uint32_t grid_x, uint32_t grid_y, const vec3F* pSrc_blo for (uint32_t i = 0; i < pRow_lists[x].n; i++) p += vec3F(pSrc_block[y * 6 + pRow_lists[x].p[i].pixel]) * pRow_lists[x].p[i].weight; - + temp_block[y][x] = p; } // x } // y @@ -2403,7 +2403,7 @@ static float diff_blocks(const vec4F* pA, const vec4F* pB) float diff = 0.0f; for (uint32_t i = 0; i < BLOCK_T; i++) diff += square(pA[i][0] - pB[i][0]) + square(pA[i][1] - pB[i][1]) + square(pA[i][2] - pB[i][2]); - + return diff * (1.0f / (float)BLOCK_T); } @@ -2551,7 +2551,7 @@ static void create_smooth_maps2( float yl = clampf(max_std_dev / params.m_max_ultra_smooth_std_dev, 0.0f, 1.0f); yl = powf(yl, 2.0f); - + smooth_block_mse_scales(x, y) = lerp(params.m_ultra_smooth_max_mse_scale, smooth_block_mse_scales(x, y), yl); if (params.m_debug_images) @@ -2594,12 +2594,12 @@ static float compute_pixel_mse_itp(const vec3F& orig_pixel_itp, const vec3F& com float delta_i = orig_pixel_itp[0] - comp_pixel_itp[0]; float delta_t = orig_pixel_itp[1] - comp_pixel_itp[1]; float delta_p = orig_pixel_itp[2] - comp_pixel_itp[2]; - + float err = (delta_i * delta_i) + (delta_t * delta_t) + (delta_p * delta_p); if (delta_itp_dark_adjustment) { - // We have to process a large range of inputs, including extremely dark inputs. + // We have to process a large range of inputs, including extremely dark inputs. // Artifically amplify MSE on very dark pixels - otherwise they'll be overly compressed at higher lambdas. // This is to better handle very dark signals which could be explictly overexposed. float s = bu_math::smoothstep(0.0f, REALLY_DARK_I_THRESHOLD, orig_pixel_itp[0]); @@ -2687,7 +2687,7 @@ static float compute_pixel_delta_itp(const vec3F& a, const vec3F& b, const vec3F float err = 720.0f * sqrtf((delta_i * delta_i) + (delta_t * delta_t) + (delta_p * delta_p)); float s = bu_math::smoothstep(0.0f, REALLY_DARK_I_THRESHOLD, orig[0]); - + if (delta_itp_dark_adjustment) { // This is to better handle very dark signals which could be explictly overexposed. @@ -2701,22 +2701,22 @@ static float compute_pixel_delta_itp(const vec3F& a, const vec3F& b, const vec3F struct candidate_encoding { encoding_type m_encoding_type; - + basist::half_float m_solid_color[3]; uint32_t m_run_len; vec3F m_comp_pixels[MAX_BLOCK_H][MAX_BLOCK_W]; // [y][x] vec3F m_comp_pixels_itp[MAX_BLOCK_H][MAX_BLOCK_W]; // [y][x] - + endpoint_mode m_endpoint_mode; block_mode m_block_mode; bitwise_coder m_coder; - + // The block to code, which may not be valid ASTC. This may have to be transcoded (by requantizing the weights/endpoints) before it's valid ASTC. // Note the endpoints may be coded endpoints OR transcoded endpoints, depending on the encoding type. - astc_helpers::log_astc_block m_coded_log_blk; + astc_helpers::log_astc_block m_coded_log_blk; // The block the decoder outputs. astc_helpers::log_astc_block m_decomp_log_blk; @@ -2724,7 +2724,7 @@ struct candidate_encoding int m_reuse_delta_index; float m_t, m_d, m_bits; - + candidate_encoding() { clear(); @@ -2755,7 +2755,7 @@ struct candidate_encoding m_coded_log_blk = rhs.m_coded_log_blk; m_decomp_log_blk = rhs.m_decomp_log_blk; m_reuse_delta_index = rhs.m_reuse_delta_index; - + return *this; } @@ -2787,19 +2787,19 @@ struct candidate_encoding m_run_len = 0; clear_obj(m_comp_pixels); - + m_endpoint_mode = endpoint_mode::cInvalid; m_block_mode = block_mode::cInvalid; m_coder.restart(); - + m_coded_log_blk.clear(); m_decomp_log_blk.clear(); m_t = 0; m_d = 0; m_bits = 0; - + m_reuse_delta_index = 0; } }; @@ -2823,7 +2823,7 @@ bool decode_astc_block(uint32_t block_w, uint32_t block_h, astc_helpers::log_ast basist::half_to_float(decoded_pixels_half4[x + y * block_w][0]), basist::half_to_float(decoded_pixels_half4[x + y * block_w][1]), basist::half_to_float(decoded_pixels_half4[x + y * block_w][2])); - } // x + } // x } //y return true; @@ -2859,7 +2859,7 @@ static bool decode_file(const uint8_vec& comp_data, vector2D MAX_ASTC_HDR_6X6_DIM) || (height > MAX_ASTC_HDR_6X6_DIM)) return false; @@ -2876,11 +2876,11 @@ static bool decode_file(const uint8_vec& comp_data, vector2D num_blocks_remaining) return false; - + uint32_t prev_bx = cur_bx, prev_by = cur_by; if (cur_bx) @@ -2980,7 +2980,7 @@ static bool decode_file(const uint8_vec& comp_data, vector2D { const uint32_t width = src_img.get_width(); const uint32_t height = src_img.get_height(); - + if (pPacked_bc6h_img) pPacked_bc6h_img->resize(width, height); @@ -3365,7 +3365,7 @@ static bool pack_bc6h_image(const imagef &src_img, vector2D const uint32_t num_blocks_y = src_img.get_block_height(4); bc6h_blocks.resize(num_blocks_x, num_blocks_y); - + for (uint32_t by = 0; by < num_blocks_y; by++) { for (uint32_t bx = 0; bx < num_blocks_x; bx++) @@ -3411,7 +3411,7 @@ static bool pack_bc6h_image(const imagef &src_img, vector2D fmt_error_printf("unpack_bc6h() failed\n"); return false; } - + for (uint32_t y = 0; y < 4; y++) { for (uint32_t x = 0; x < 4; x++) @@ -3453,7 +3453,7 @@ static void estimate_partitions_mode7_and_11( uint32_t num_pats_to_examine, const uint32_t* pUnique_pat_indices_to_examine, // indices of pats to examine const vec3F *pHalf_pixels_as_floats, // block's half pixel values casted to floats const astc_hdr_codec_base_options& coptions, // options - uint32_t num_desired_pats, + uint32_t num_desired_pats, int *pDesired_pat_indices_mode11, int *pDesired_pat_indices_mode7) // output indices { BASISU_NOTE_UNUSED(coptions); @@ -3476,7 +3476,7 @@ static void estimate_partitions_mode7_and_11( candidate_res mode7_candidates[MAX_CANDIDATES]; const vec3F grayscale_axis(0.5773502691f); - + for (uint32_t examine_iter = 0; examine_iter < num_pats_to_examine; examine_iter++) { const uint32_t unique_part_index = pUnique_pat_indices_to_examine[examine_iter]; @@ -3502,7 +3502,7 @@ static void estimate_partitions_mode7_and_11( } // x } // y - + for (uint32_t i = 0; i < num_parts; i++) { assert(part_total_texels[i]); @@ -3547,7 +3547,7 @@ static void estimate_partitions_mode7_and_11( float* pCov = &part_cov[part_index][0]; float xr = .9f, xg = 1.0f, xb = .7f; - + const uint32_t NUM_POWER_ITERS = 4; for (uint32_t iter = 0; iter < NUM_POWER_ITERS; iter++) { @@ -3560,7 +3560,7 @@ static void estimate_partitions_mode7_and_11( if (m >= 1e-10f) { m = 1.0f / m; - + r *= m; g *= m; b *= m; @@ -3572,7 +3572,7 @@ static void estimate_partitions_mode7_and_11( } float len_sq = xr * xr + xg * xg + xb * xb; - + if (len_sq < 1e-10f) { xr = grayscale_axis[0]; @@ -3587,7 +3587,7 @@ static void estimate_partitions_mode7_and_11( xg *= len_sq; xb *= len_sq; } - + { // Transform the principle axis by the covariance matrix, which will scale the vector by its eigenvalue (the variance of the dataset projected onto the principle axis). float r = xr * pCov[0] + xg * pCov[1] + xb * pCov[2]; @@ -3598,13 +3598,13 @@ static void estimate_partitions_mode7_and_11( // The result is the variance along the principle axis. //float z1 = sqrtf(r * r + g * g + b * b); // this works with the principle axis //float z2 = r * xr + g * xg + b * xb; // compute length projected along xr,xg,xb - + mode11_eigenvalue_est[part_index] = r * xr + g * xg + b * xb; } { const float yrgb = grayscale_axis[0]; - + // Transform the grayscale axis by the covariance matrix, which will scale the vector by the eigenvalue (which is the variance of the dataset projected onto this vector). float r = yrgb * pCov[0] + yrgb * pCov[1] + yrgb * pCov[2]; float g = yrgb * pCov[1] + yrgb * pCov[3] + yrgb * pCov[4]; @@ -3614,7 +3614,7 @@ static void estimate_partitions_mode7_and_11( } } // part_index - + // Compute the total variance (squared error) of the other 2 axes by subtracting the total variance of all channels by the variance of the principle axis. // TODO: Could also compute the ratio of the principle axis's variance vs. the total variance. float mode11_total_sq_dist_to_line_alt = 0.0f; @@ -3727,7 +3727,7 @@ static void estimate_partitions_mode7( } vec3F part_axis(0.5773502691f); - + // TODO: This total distance can be computed rapidly. First compute the total variance of each channel (sum the diag entries of the covar matrix), // then compute the principle eigenvalue, and subtract. The result is the variance of the projection distances. float total_sq_dist_to_line = 0.0f; @@ -3793,7 +3793,7 @@ static float calc_deblocking_penalty_itp( const vec3F& q_pixel_itp = pass_src_img_itp(qx, qy); const vec3F &d_pixel_itp = candidate.m_comp_pixels_itp[qy - by * 6][qx - bx * 6]; // compressed block - + vec3F orig_delta_v(o_pixel_itp - q_pixel_itp); total_orig_mse += square(orig_delta_v[0]) + square(orig_delta_v[1]) + square(orig_delta_v[2]); @@ -3857,15 +3857,15 @@ static bool calc_strip_size( else { rows_per_strip = (num_blocks_y / total_strips) & ~1; - + if (rows_per_strip < 2) rows_per_strip = 2;// num_blocks_y; } - + assert((rows_per_strip == num_blocks_y) || ((rows_per_strip & 1) == 0)); total_strips = (num_blocks_y + rows_per_strip - 1) / rows_per_strip; - + if (global_cfg.m_debug_output) { fmt_printf("num_blocks_y: {}, total_threads : {}, Total strips : {}\n", num_blocks_y, total_threads, total_strips); @@ -3975,7 +3975,7 @@ struct uastc_hdr_6x6_debug_state std::mutex m_vis_image_mutex; std::atomic m_comp_level_hist[ASTC_HDR_6X6_MAX_COMP_LEVEL + 1]; - + std::atomic m_total_jnd_replacements; std::mutex m_stats_mutex; @@ -3991,7 +3991,7 @@ struct uastc_hdr_6x6_debug_state } } } - + void init(uint32_t width, uint32_t height) { m_stat_vis.resize(width, height); @@ -4005,7 +4005,7 @@ struct uastc_hdr_6x6_debug_state basisu::clear_obj(m_endpoint_mode_hist); basisu::clear_obj(m_block_mode_hist); basisu::clear_obj(m_block_mode_total_bits); - + for (uint32_t i = 0; i < (uint32_t)block_mode::cBMTotalModes; i++) { for (uint32_t j = 0; j < 3; j++) @@ -4032,7 +4032,7 @@ struct uastc_hdr_6x6_debug_state for (uint32_t i = 0; i < std::size(m_total_part2_stats); i++) m_total_part2_stats[i].store(0); - + for (uint32_t i = 0; i < std::size(m_dp_stats); i++) m_dp_stats[i].store(0); @@ -4156,9 +4156,9 @@ struct uastc_hdr_6x6_debug_state struct uastc_hdr_6x6_encode_state { astc_hdr_codec_base_options master_coptions; - + imagef src_img; - + imagef src_img_filtered1; imagef src_img_filtered2; @@ -4184,7 +4184,7 @@ static bool compress_strip_task( { BASISU_NOTE_UNUSED(num_blocks_y); BASISU_NOTE_UNUSED(total_strips); - + vec3F prev_comp_pixels[BLOCK_H][BLOCK_W]; // [y][x] basisu::clear_obj(prev_comp_pixels); @@ -4682,7 +4682,7 @@ static bool compress_strip_task( part_half_pixels[part_index][l] = half_pixels[y][x]; part_total_pixels[part_index] = l + 1; - } // x + } // x } // y uint8_t blk_weights[2][BLOCK_W * BLOCK_H]; @@ -4760,7 +4760,7 @@ static bool compress_strip_task( part_half_pixels[part_index][l] = half_pixels[y][x]; part_total_pixels[part_index] = l + 1; - } // x + } // x } // y uint8_t blk_weights[3][BLOCK_W * BLOCK_H]; @@ -6364,7 +6364,7 @@ static bool compress_strip_task( const uint32_t p = pat[x + y * 6]; debug_state.m_part_vis.set_clipped(bx * 6 + x, by * 6 + y, color_rgba(p ? 100 : 0, 128, p ? 100 : 0, 255)); } // x - } // y + } // y } else if (best_candidate.m_decomp_log_blk.m_num_partitions == 3) { @@ -6387,7 +6387,7 @@ static bool compress_strip_task( c.set(0, 100, 150, 255); debug_state.m_part_vis.set_clipped(bx * 6 + x, by * 6 + y, c); } // x - } // y + } // y } else if (best_candidate.m_decomp_log_blk.m_dual_plane) { @@ -6500,7 +6500,7 @@ void global_init() tm.start(); init_pq_tables(); - + init_partitions2_6x6(); init_partitions3_6x6(); @@ -6517,7 +6517,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa assert(g_initialized); if (!g_initialized) return false; - + assert(pJob_pool); if (orig_global_cfg.m_debug_output) @@ -6563,17 +6563,17 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa f = basist::ASTC_HDR_MAX_VAL; enc_state.src_img(x, y)[c] = f; - + } // c - + } // x } // y - + if (global_cfg.m_debug_images) { write_exr((global_cfg.m_debug_image_prefix + "orig.exr").c_str(), enc_state.src_img, 3, 0); } - + image src_img_compressed; tonemap_image_compressive2(src_img_compressed, enc_state.src_img); @@ -6598,10 +6598,10 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa enc_state.src_img_filtered1.resize(width, height); image_resample(enc_state.src_img, enc_state.src_img_filtered1, "gaussian", global_cfg.m_gaussian1_strength); //1.45f); - + enc_state.src_img_filtered2.resize(width, height); image_resample(enc_state.src_img, enc_state.src_img_filtered2, "gaussian", global_cfg.m_gaussian2_strength); //1.83f); - + if (global_cfg.m_debug_images) { write_exr((global_cfg.m_debug_image_prefix + "blurred1.exr").c_str(), enc_state.src_img_filtered1, 3, 0); @@ -6613,10 +6613,10 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa enc_state.src_img_itp.resize(width, height); convet_rgb_image_to_itp(enc_state.src_img, enc_state.src_img_itp, global_cfg); - + enc_state.src_img_filtered1_itp.resize(width, height); convet_rgb_image_to_itp(enc_state.src_img_filtered1, enc_state.src_img_filtered1_itp, global_cfg); - + enc_state.src_img_filtered2_itp.resize(width, height); convet_rgb_image_to_itp(enc_state.src_img_filtered2, enc_state.src_img_filtered2_itp, global_cfg); @@ -6629,20 +6629,20 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa fmt_error_printf("compress_photo: Failed computing strip sizes\n"); return false; } - + if (global_cfg.m_debug_output) fmt_printf("lambda: {}, comp_level: {}, highest_comp_level: {}, extra patterns: {}\n", global_cfg.m_lambda, global_cfg.m_master_comp_level, global_cfg.m_highest_comp_level, global_cfg.m_extra_patterns_flag); - + enc_state.coded_blocks.resize(num_blocks_x, num_blocks_y); - + bitwise_coder coded_bits; coded_bits.put_bits(0xABCD, 16); coded_bits.put_bits(width, 16); coded_bits.put_bits(height, 16); - + enc_state.packed_img.resize(width, height); - + enc_state.strip_bits.resize(total_strips); enc_state.final_astc_blocks.resize(num_blocks_x, num_blocks_y); @@ -6653,7 +6653,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa debug_state.init(width, height); else debug_state.init(0, 0); - + interval_timer tm; tm.start(); @@ -6663,7 +6663,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa for (uint32_t strip_index = 0; strip_index < total_strips; strip_index++) { const uint32_t strip_first_by = strip_index * rows_per_strip; - + uint32_t strip_last_by = minimum(strip_first_by + rows_per_strip - 1, num_blocks_y); if (strip_index == (total_strips - 1)) strip_last_by = num_blocks_y - 1; @@ -6689,7 +6689,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa if (any_failed_flag) break; - + } // strip_index pJob_pool->wait_for_all(); @@ -6699,7 +6699,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa fmt_error_printf("One or more strips failed during compression\n"); return false; } - + if (global_cfg.m_debug_output) fmt_printf("Encoding time: {} secs\n", tm.get_elapsed_secs()); @@ -6718,7 +6718,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa for (uint32_t i = 0; i < total_strips; i++) coded_bits.append(enc_state.strip_bits[i]); - + coded_bits.put_bits(0xA742, 16); coded_bits.flush(); @@ -6727,13 +6727,13 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa { write_exr((global_cfg.m_output_image_prefix + "comp.exr").c_str(), enc_state.packed_img, 3, 0); } - + if (global_cfg.m_debug_output) fmt_printf("\nTotal intermediate output bits/pixel: {3.4}\n", (float)coded_bits.get_total_bits() / (float)(width * height)); vector2D decoded_blocks1; vector2D decoded_blocks2; - + if (global_cfg.m_debug_output) fmt_printf("decode_file\n"); @@ -6830,7 +6830,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa fmt_error_printf("unpack_physical_astc_block() failed\n"); return false; } - + unpacked_astc_img.set_block_clipped(pixels, x * BLOCK_W, y * BLOCK_H, BLOCK_W, BLOCK_H); vec4F pixels_google[MAX_BLOCK_W * MAX_BLOCK_H]; @@ -6853,7 +6853,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa } } } - + if (global_cfg.m_debug_output) fmt_printf("\nUnpack succeeded\n"); @@ -6861,9 +6861,9 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa { vector2D bc6h_blocks; - + fast_bc6h_params enc_params; - + bool pack_status = pack_bc6h_image(unpacked_astc_img, bc6h_blocks, &unpacked_bc6h_img, enc_params); if (!pack_status) { @@ -6872,7 +6872,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa } unpacked_bc6h_img.crop(width, height); - + if (global_cfg.m_output_images) { write_exr((global_cfg.m_output_image_prefix + "unpacked_bc6h.exr").c_str(), unpacked_bc6h_img, 3, 0); @@ -6881,7 +6881,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa unpacked_astc_img.crop(width, height); unpacked_astc_google_img.crop(width, height); - + if (global_cfg.m_output_images) { write_exr((global_cfg.m_output_image_prefix + "unpacked_astc.exr").c_str(), unpacked_astc_img, 3, 0); @@ -6906,7 +6906,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa im.print_hp(); } } - + metrics.m_im_astc_log2.calc(enc_state.src_img, unpacked_astc_img, 0, 3, true, true); if (global_cfg.m_debug_output) @@ -6956,7 +6956,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa for (uint32_t i = 0; i < 3; i++) { im.calc(enc_state.src_img, unpacked_bc6h_img, i, 1, true, true); - + if (global_cfg.m_debug_output) { printf("%c: ", "RGBA"[i]); @@ -6978,14 +6978,14 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa if (global_cfg.m_image_stats) { image_metrics im; - + if (global_cfg.m_debug_output) printf("BC6H half float space error metrics (a piecewise linear approximation of log2 error):\n"); for (uint32_t i = 0; i < 3; i++) { im.calc_half(enc_state.src_img, unpacked_bc6h_img, i, 1, true); - + if (global_cfg.m_debug_output) { printf("%c: ", "RGBA"[i]); @@ -6994,7 +6994,7 @@ bool compress_photo(const basisu::imagef &orig_src_img, const astc_hdr_6x6_globa } metrics.m_im_bc6h_half.calc_half(enc_state.src_img, unpacked_bc6h_img, 0, 3, true); - + if (global_cfg.m_debug_output) { printf("RGB: "); diff --git a/encoder/basisu_astc_hdr_6x6_enc.h b/encoder/basisu_astc_hdr_6x6_enc.h index 0d6d2ae9..9dbc0224 100644 --- a/encoder/basisu_astc_hdr_6x6_enc.h +++ b/encoder/basisu_astc_hdr_6x6_enc.h @@ -8,19 +8,19 @@ namespace astc_6x6_hdr const uint32_t ASTC_HDR_6X6_MAX_USER_COMP_LEVEL = 12; const uint32_t ASTC_HDR_6X6_MAX_COMP_LEVEL = 4; - + const float LDR_BLACK_BIAS = 0.0f;// .49f; - + // Note: This struct is copied several times, so do not place any heavyweight objects in here. struct astc_hdr_6x6_global_config { // Important: The Delta ITP colorspace error metric we use internally makes several assumptions about the nature of the HDR RGB inputs supplied to the encoder. // This encoder computes colorspace error in the ICtCp (or more accurately the delta ITP, where CT is scaled by .5 vs. ICtCp to become T) colorspace, so getting this correct is important. - // By default the encoder assumes the input is in absolute luminance (in nits or candela per square meter, cd/m²), specified as positive-only linear light RGB, using the REC 709 colorspace gamut (but NOT the sRGB transfer function, i.e. linear light). + // By default the encoder assumes the input is in absolute luminance (in nits or candela per square meter, cd/m�), specified as positive-only linear light RGB, using the REC 709 colorspace gamut (but NOT the sRGB transfer function, i.e. linear light). // If the m_rec2020_bt2100_color_gamut flag is true, the input colorspace is treated as REC 2020/BT.2100 (which is wider than 709). - // For SDR/LDR->HDR upconversion, the REC 709 sRGB input should be converted to linear light (sRGB->linear) and the resulting normalized linear RGB values scaled by either 80 or 100 nits (the luminance of a typical SDR monitor). + // For SDR/LDR->HDR upconversion, the REC 709 sRGB input should be converted to linear light (sRGB->linear) and the resulting normalized linear RGB values scaled by either 80 or 100 nits (the luminance of a typical SDR monitor). // SDR upconversion to normalized [0,1] (i.e. non-absolute) luminances may work but is not supported because ITP errors will not be predicted correctly. - bool m_rec2020_bt2100_color_gamut = false; + bool m_rec2020_bt2100_color_gamut = false; // levels 0-3 normal levels, 4=exhaustive uint32_t m_master_comp_level = 0; @@ -35,13 +35,13 @@ namespace astc_6x6_hdr float m_jnd_delta_itp_thresh = .75f; bool m_force_one_strip = false; - + bool m_gaussian1_fallback = true; // def to true, if this is disabled m_gaussian2_fallback should be disabled too float m_gaussian1_strength = 1.45f; bool m_gaussian2_fallback = true; // def to true, hopefully rarely kicks in float m_gaussian2_strength = 1.83f; - + // m_disable_delta_endpoint_usage may give a slight increase in RDO ASTC encoding efficiency. It's also faster. bool m_disable_delta_endpoint_usage = false; @@ -67,7 +67,7 @@ namespace astc_6x6_hdr bool m_disable_twothree_subsets = false; // def to false bool m_use_solid_blocks = true; // def to true bool m_use_runs = true; // def to true - bool m_block_stat_optimizations_flag = true; // def to true + bool m_block_stat_optimizations_flag = true; // def to true bool m_rdo_candidate_diversity_boost = true; // def to true float m_rdo_candidate_diversity_boost_bit_window_weight = 1.2f; @@ -96,7 +96,7 @@ namespace astc_6x6_hdr basisu::fmt_debug_printf("m_rdo_candidate_diversity_boost: {}, m_rdo_candidate_diversity_boost_bit_window_weight: {}\n", m_rdo_candidate_diversity_boost, m_rdo_candidate_diversity_boost_bit_window_weight); basisu::fmt_debug_printf("m_favor_higher_compression: {}, m_num_reuse_xy_deltas: {}\n", m_favor_higher_compression, m_num_reuse_xy_deltas); } - + astc_hdr_6x6_global_config() { } @@ -121,7 +121,7 @@ namespace astc_6x6_hdr basisu::image_metrics m_im_bc6h_log2; basisu::image_metrics m_im_bc6h_half; }; - + // The input image should be unpadded to 6x6 boundaries, i.e. the original unexpanded image. bool compress_photo(const basisu::imagef& orig_src_img, const astc_hdr_6x6_global_config& global_cfg, basisu::job_pool* pJob_pool, basisu::uint8_vec& intermediate_tex_data, basisu::uint8_vec& astc_tex_data, result_metrics& metrics); diff --git a/encoder/basisu_astc_hdr_common.cpp b/encoder/basisu_astc_hdr_common.cpp index b720e269..65be44c1 100644 --- a/encoder/basisu_astc_hdr_common.cpp +++ b/encoder/basisu_astc_hdr_common.cpp @@ -117,7 +117,7 @@ static void compute_half_to_qlog_table(uint32_t bits, uint16_t* pTable, const ba float best_err = BIG_FLOAT_VAL; uint32_t best_qlog = 0; - + double prev_err = BIG_FLOAT_VAL; // For all possible qlog's @@ -141,13 +141,13 @@ static void compute_half_to_qlog_table(uint32_t bits, uint16_t* pTable, const ba } prev_err = err; - + // Find best if (err < best_err) { best_err = err; best_qlog = i; - + if (best_err == 0.0f) break; } @@ -171,7 +171,7 @@ static void init_qlog_tables() #if BASISU_MULTITHREADED_INIT job_pool jp(3); - + for (uint32_t bits = HALF_TO_QLOG_TABS_MIN_BITS; bits <= HALF_TO_QLOG_TABS_MAX_BITS; bits++) { jp.add_job( [bits, &qlog16_to_float]() { compute_half_to_qlog_table(bits, g_pHalf_to_qlog_tabs[bits - HALF_TO_QLOG_TABS_MIN_BITS], qlog16_to_float); }); @@ -328,7 +328,7 @@ static bool compute_least_squares_endpoints_rgb( uint32_t N, const uint8_t* pSelectors, const vec4F* pSelector_weights, vec3F* pXl, vec3F* pXh, const vec4F* pColors, const aabb3F& input_box) { - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; @@ -339,7 +339,7 @@ static bool compute_least_squares_endpoints_rgb( for (uint32_t i = 0; i < N; i++) { const uint32_t sel = pSelectors[i]; - + z00 += pSelector_weights[sel][0]; z10 += pSelector_weights[sel][1]; z11 += pSelector_weights[sel][2]; @@ -373,7 +373,7 @@ static bool compute_least_squares_endpoints_rgb( iz01 = -z01 * det; iz10 = -z10 * det; iz11 = z00 * det; - + (*pXl)[0] = (float)(iz00 * q00_r + iz01 * q10_r); (*pXh)[0] = (float)(iz10 * q00_r + iz11 * q10_r); @@ -392,7 +392,7 @@ static bool compute_least_squares_endpoints_rgb( l = input_box[0][c]; h = input_box[1][c]; } - + (*pXl)[c] = l; (*pXh)[c] = h; } @@ -429,17 +429,17 @@ static bool compute_least_squares_endpoints_rgb( } static bool compute_least_squares_endpoints_rgb_raw_weights( - uint32_t N, const uint8_t* pRaw_weights, + uint32_t N, const uint8_t* pRaw_weights, vec3F* pXl, vec3F* pXh, const vec4F* pColors, const aabb3F& input_box) { - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; float q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f; float q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f; float q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f; - + for (uint32_t i = 0; i < N; i++) { const float wt = (float)pRaw_weights[i] * (1.0f / 64.0f); @@ -541,13 +541,13 @@ static bool compute_least_squares_endpoints_2D( uint32_t N, const uint8_t* pSelectors, const vec4F* pSelector_weights, vec2F* pXl, vec2F* pXh, const vec2F* pColors, const aabb2F& input_box) { - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; float q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f; float q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f; - + for (uint32_t i = 0; i < N; i++) { const uint32_t sel = pSelectors[i]; @@ -599,7 +599,7 @@ static bool compute_least_squares_endpoints_2D( (*pXl)[c] = l; (*pXh)[c] = h; } - + pXl->clamp(0.0f, MAX_QLOG16_VAL); pXh->clamp(0.0f, MAX_QLOG16_VAL); @@ -610,7 +610,7 @@ static bool compute_least_squares_endpoints_1D( uint32_t N, const uint8_t* pSelectors, const vec4F* pSelector_weights, vec1F* pXl, vec1F* pXh, const vec1F* pColors, const aabb1F& input_box) { - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; @@ -668,10 +668,10 @@ static bool compute_least_squares_endpoints_1D( } static bool compute_weighted_least_squares_endpoints_rgb( - uint32_t N, + uint32_t N, const uint8_t* pSelectors, const vec4F* pSelector_weights, const float* pRaw_weights, /* ti */ const float* pEmphasis_weights /* wi */, - vec3F* pXl, vec3F* pXh, + vec3F* pXl, vec3F* pXh, const vec4F* pColors, /* pi */ const aabb3F& input_box) { @@ -702,7 +702,7 @@ static bool compute_weighted_least_squares_endpoints_rgb( const float pi_r = pColors[i][0], pi_g = pColors[i][1], pi_b = pColors[i][2]; weighted_mean_tw += wi * ti; - + weighted_mean_pw[0] += wi * pi_r; weighted_mean_pw[1] += wi * pi_g; weighted_mean_pw[2] += wi * pi_b; @@ -722,7 +722,7 @@ static bool compute_weighted_least_squares_endpoints_rgb( const float wi = pEmphasis_weights[i]; const float ti = pSelectors ? pSelector_weights[pSelectors[i]][3] : pRaw_weights[i]; const float pi_r = pColors[i][0], pi_g = pColors[i][1], pi_b = pColors[i][2]; - + spt[0] += wi * (pi_r - weighted_mean_pw[0]) * (ti - weighted_mean_tw); spt[1] += wi * (pi_g - weighted_mean_pw[1]) * (ti - weighted_mean_tw); spt[2] += wi * (pi_b - weighted_mean_pw[2]) * (ti - weighted_mean_tw); @@ -737,7 +737,7 @@ static bool compute_weighted_least_squares_endpoints_rgb( { float h = weighted_mean_pw[i] + (spt[i] / stt) * (1.0f - weighted_mean_tw); float l = weighted_mean_pw[i] - (spt[i] / stt) * weighted_mean_tw; - + (*pXh)[i] = h; (*pXl)[i] = l; } @@ -1128,7 +1128,7 @@ double eval_selectors( const vec3F low_color((float)pDecoded_half[lo_index * 3 + 0], (float)pDecoded_half[lo_index * 3 + 1], (float)pDecoded_half[lo_index * 3 + 2]); const vec3F high_color((float)pDecoded_half[hi_index * 3 + 0], (float)pDecoded_half[hi_index * 3 + 1], (float)pDecoded_half[hi_index * 3 + 2]); const vec3F mid_color((float)pDecoded_half[mid_index * 3 + 0], (float)pDecoded_half[mid_index * 3 + 1], (float)pDecoded_half[mid_index * 3 + 2]); - + const vec3F block_dir(high_color - low_color); for (uint32_t p = 0; p < num_pixels; p++) @@ -1140,11 +1140,11 @@ double eval_selectors( const int64_t desired_half_r_q = q2(desired_r, coptions.m_q_log_bias); const int64_t desired_half_g_q = q2(desired_g, coptions.m_q_log_bias); const int64_t desired_half_b_q = q2(desired_b, coptions.m_q_log_bias); - + // Determine which side of the middle plane the point is for a modest gain vec3F c((float)desired_r - mid_color[0], (float)desired_g - mid_color[1], (float)desired_b - mid_color[2]); float d = c.dot(block_dir); - + int i = 0, high_index = (num_weight_levels / 2) + 1; if (d >= 0.0f) { @@ -1240,11 +1240,11 @@ double eval_selectors_dual_plane( const uint32_t first_channel = (channel_index + 1) % 3; const uint32_t second_channel = (channel_index + 2) % 3; - + // First plane const double first_channel_weight = channel_weights[first_channel]; const double second_channel_weight = channel_weights[second_channel]; - + for (uint32_t p = 0; p < num_pixels; p++) { const half_float* pDesired_half = &pBlock_pixels_half[p * 3]; @@ -1284,7 +1284,7 @@ double eval_selectors_dual_plane( const half_float* pDesired_half = &pBlock_pixels_half[p * 3]; const double desired_half_a_q = q(pDesired_half[channel_index], coptions.m_q_log_bias); - + double lowest_e = BIG_FLOAT_VAL; // this is an approximation of MSLE @@ -1711,7 +1711,7 @@ bool pack_astc_mode11_submode(uint32_t submode, uint8_t* pEndpoints, int val_q[2 bool pack_astc_mode11_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& low_q16, const vec3F& high_q16, int& max_clamp_mag, bool early_out_if_clamped, int max_clamp_mag_accept_thresh) { assert(submode <= 7); - + const uint32_t a_bits = 9 + (submode >> 1); const int max_a_val = (1 << a_bits) - 1; @@ -1803,7 +1803,7 @@ void pack_astc_mode11_direct(uint8_t* pEndpoints, vec3F l_q16, vec3F h_q16) // this quantizes R and G as 7 bits vs. 8, for grayscale. //l_q = g_half_to_qlog7[bounds_check((uint32_t)l_half, 0U, 32768U)] << 1; //h_q = g_half_to_qlog7[bounds_check((uint32_t)h_half, 0U, 32768U)] << 1; - + l_q = minimum(l_q, MAX_QLOG8); h_q = minimum(h_q, MAX_QLOG8); } @@ -1982,7 +1982,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[0], 8); // R8 x2 = get_bit(qlog[0], 7); // R7 x3 = get_bit(qlog[0], 10); // R10 - x4 = get_bit(qlog[0], 6); // R6 + x4 = get_bit(qlog[0], 6); // R6 x5 = get_bit(qlog[3], 6); // S6 x6 = get_bit(qlog[3], 5); // S5 break; @@ -1996,7 +1996,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[1], 5); // G5 x2 = get_bit(qlog[0], 7); // R7 x3 = get_bit(qlog[2], 5); // B5 - x4 = get_bit(qlog[0], 6); // R6 + x4 = get_bit(qlog[0], 6); // R6 x5 = get_bit(qlog[0], 10); // R10 x6 = get_bit(qlog[0], 9); // R9 break; @@ -2010,7 +2010,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[0], 8); // R8 x2 = get_bit(qlog[0], 7); // R7 x3 = get_bit(qlog[0], 6); // R6 - x4 = get_bit(qlog[3], 7); // S7 + x4 = get_bit(qlog[3], 7); // S7 x5 = get_bit(qlog[3], 6); // S6 x6 = get_bit(qlog[3], 5); // S5 break; @@ -2024,7 +2024,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[1], 5); // G5 x2 = get_bit(qlog[0], 7); // R7 x3 = get_bit(qlog[2], 5); // B5 - x4 = get_bit(qlog[0], 6); // R6 + x4 = get_bit(qlog[0], 6); // R6 x5 = get_bit(qlog[3], 6); // S6 x6 = get_bit(qlog[3], 5); // S5 break; @@ -2039,7 +2039,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[1], 5); // G5 x2 = get_bit(qlog[2], 6); // B6 x3 = get_bit(qlog[2], 5); // B5 - x4 = get_bit(qlog[0], 6); // R6 + x4 = get_bit(qlog[0], 6); // R6 x5 = get_bit(qlog[0], 7); // R7 x6 = get_bit(qlog[3], 5); // S5 break; @@ -2052,7 +2052,7 @@ bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& x1 = get_bit(qlog[1], 5); // G5 x2 = get_bit(qlog[2], 6); // B6 x3 = get_bit(qlog[2], 5); // B5 - x4 = get_bit(qlog[0], 6); // R6 + x4 = get_bit(qlog[0], 6); // R6 x5 = get_bit(qlog[3], 6); // S6 x6 = get_bit(qlog[3], 5); // S5 break; @@ -2143,7 +2143,7 @@ bool pack_mode11(mode11_log_desc& desc, uint8_t* pEndpoints) pEndpoints[1] = (uint8_t)desc.m_b1; pEndpoints[3] = (uint8_t)desc.m_d0; pEndpoints[5] = (uint8_t)desc.m_d1 | 128; - + return true; } @@ -2161,9 +2161,9 @@ bool pack_mode11(mode11_log_desc& desc, uint8_t* pEndpoints) return false; const int va = desc.m_a, vb0 = desc.m_b0, vb1 = desc.m_b1, vc = desc.m_c, vd0 = desc.m_d0, vd1 = desc.m_d1; - + int v0 = 0, v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0; - + int x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0; switch (desc.m_submode) { @@ -2261,7 +2261,7 @@ void unpack_mode11(const uint8_t* pEndpoints, mode11_log_desc& desc) desc.m_b1 = pEndpoints[1]; desc.m_d0 = pEndpoints[3]; desc.m_d1 = pEndpoints[5] & 0x7F; - + return; } @@ -2384,7 +2384,7 @@ void decode_cem_7_config(const uint8_t* pEndpoints, int& submode_index, int &maj bool pack_mode11( const vec3F& low_color_q16, const vec3F& high_color_q16, - uint32_t ise_endpoint_range, uint8_t* pEndpoints, + uint32_t ise_endpoint_range, uint8_t* pEndpoints, const astc_hdr_codec_base_options& coptions, bool direct_only, int32_t first_submode, int32_t last_submode, bool ignore_clamping, uint32_t& submode_used) { @@ -2521,7 +2521,7 @@ bool pack_mode11( } // d } // c } // if (coptions.m_ultra_quant) - + submode_used = best_submode + 1; return (best_trial_dist != BIG_FLOAT_VAL); @@ -3039,7 +3039,7 @@ bool try_mode7( clear_obj(best_trial_endpoints); double best_trial_dist = BIG_FLOAT_VAL; int best_trial_submode = 0; - + for (int submode = first_submode; submode <= last_submode; submode++) { const int MAX_CLAMP_MAG_ACCEPT_THRESH = 16; @@ -3236,9 +3236,9 @@ double encode_astc_hdr_block_mode_11( high_color_q16 = pBlock_pixels_q16[i]; } } - + vec3F old_low_color_q16(low_color_q16), old_high_color_q16(high_color_q16); - + for (uint32_t i = 0; i < 3; i++) { low_color_q16[i] = lerp(old_low_color_q16[i], old_high_color_q16[i], 1.0f / 64.0f); @@ -3253,7 +3253,7 @@ double encode_astc_hdr_block_mode_11( clear_obj(trial_blk_weights); double trial_blk_error = BIG_FLOAT_VAL; - + bool did_improve = try_mode11(num_pixels, trial_blk_endpoints, trial_blk_weights, trial_blk_error, trial_best_submode, low_color_q16, high_color_q16, pBlock_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight_selectors, @@ -3330,7 +3330,7 @@ double encode_astc_hdr_block_mode_11( if (!compute_least_squares_endpoints_rgb(num_pixels, trial_blk_weights, &g_astc_ls_weights_ise[ise_weight_range][0], &l_q16, &h_q16, pBlock_pixels_q16, color_box_q16)) break; - + bool was_improved = try_mode11(num_pixels, blk_endpoints, blk_weights, cur_block_error, best_submode, l_q16, h_q16, pBlock_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight_selectors, @@ -3359,7 +3359,7 @@ double encode_astc_hdr_block_mode_11( float lw = LOW_EMPHASIS_WEIGHT, mw = MIDDLE_EMPHASIS_WEIGHT, hw = HIGH_EMPHASIS_WEIGHT; if (opt_mode == cWeightedLeastSquaresHeavy) lw = LOW_EMPHASIS_WEIGHT_HEAVY, mw = MIDDLE_EMPHASIS_WEIGHT_HEAVY, hw = HIGH_EMPHASIS_WEIGHT_HEAVY; - + for (uint32_t i = 0; i < num_pixels; i++) { vec3F k(vec3F(pBlock_pixels_q16[i]) - block_mean_color_q16); @@ -3368,7 +3368,7 @@ double encode_astc_hdr_block_mode_11( assert((kd >= l) && (kd <= h)); float v = (kd - l) / (h - l); - + if (v < mid) v = lerp(lw, mw, v / mid); else @@ -3655,7 +3655,7 @@ double encode_astc_hdr_block_downsampled_mode_11( clear_obj(trial_blk_endpoints); clear_obj(trial_blk_weights); - + double trial_blk_error = BIG_FLOAT_VAL; bool could_pack = try_mode11(num_pixels, trial_blk_endpoints, trial_blk_weights, trial_blk_error, trial_best_submode, @@ -3696,7 +3696,7 @@ double encode_astc_hdr_block_downsampled_mode_11( } else if (pass) break; - + if ((opt_mode == cWeightedLeastSquares) || (opt_mode == cWeightedLeastSquaresHeavy)) { float emphasis_weights[MAX_ASTC_HDR_ENC_BLOCK_PIXELS]; @@ -3797,7 +3797,7 @@ double encode_astc_hdr_block_mode_11_dual_plane( assert((first_submode >= FIRST_MODE11_SUBMODE_INDEX) && (first_submode <= last_submode)); assert(last_submode <= MAX_MODE11_SUBMODE_INDEX); - + assert(num_pixels <= MAX_ASTC_HDR_ENC_BLOCK_PIXELS); best_submode = 0; @@ -3873,7 +3873,7 @@ double encode_astc_hdr_block_mode_11_dual_plane( double trial_blk_error = BIG_FLOAT_VAL; bool did_improve = try_mode11_dual_plane(channel_index, num_pixels, trial_blk_endpoints, trial_blk_weights0, trial_blk_weights1, trial_blk_error, trial_best_submode, - low_color_q16, high_color_q16, + low_color_q16, high_color_q16, pBlock_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight_selectors, first_submode, last_submode, ignore_clamping); @@ -3947,7 +3947,7 @@ double encode_astc_hdr_block_mode_11_dual_plane( memcpy(trial_blk_weights1, blk_weights1, num_pixels); } // pass - + return cur_block_error; } @@ -3962,7 +3962,7 @@ double encode_astc_hdr_block_mode_7( uint8_t* blk_endpoints, //[4] uint8_t* blk_weights, // [num_pixels] const astc_hdr_codec_base_options& coptions, - uint32_t ise_endpoint_range, + uint32_t ise_endpoint_range, int first_submode, int last_submode, const encode_astc_block_stats* pBlock_stats) { @@ -4008,7 +4008,7 @@ double encode_astc_hdr_block_mode_7( vec3F diff(high_color_q16 - low_color_q16); - // The mul here (* block_axis_q16[0]) is because the "S" or scale value is subtracted from the high color with a scale of 1.0, + // The mul here (* block_axis_q16[0]) is because the "S" or scale value is subtracted from the high color with a scale of 1.0, // i.e. it's equivalent to a vector of (1,1,1) multiplied by scale before the sub. We want to actually move along the grayscale axis, or (0.577350259, 0.577350259, 0.577350259). float s_q16 = diff.dot(block_axis_q16) * block_axis_q16[0]; @@ -4081,7 +4081,7 @@ double encode_astc_hdr_block_mode_7( vec3F alt_diff(alt_high_color_q16 - alt_low_color_q16); - // The mul here (* block_axis_q16[0]) is because the "S" or scale value is subtracted from the high color with a scale of 1.0, + // The mul here (* block_axis_q16[0]) is because the "S" or scale value is subtracted from the high color with a scale of 1.0, // i.e. it's equivalent to a vector of (1,1,1) multiplied by scale before the sub. We want to actually move along the grayscale axis, or (0.577350259, 0.577350259, 0.577350259). float alt_s_q16 = alt_diff.dot(block_axis_q16) * block_axis_q16[0]; @@ -4803,7 +4803,7 @@ void downsample_ise_weights( assert((block_w <= MAX_ASTC_HDR_BLOCK_W) && (block_h <= MAX_ASTC_HDR_BLOCK_H)); assert((grid_w >= 2) && (grid_w <= MAX_ASTC_HDR_BLOCK_W)); assert((grid_h >= 2) && (grid_h <= MAX_ASTC_HDR_BLOCK_H)); - + assert(dequant_weight_ise_range >= astc_helpers::FIRST_VALID_WEIGHT_ISE_RANGE); assert(dequant_weight_ise_range <= astc_helpers::LAST_VALID_WEIGHT_ISE_RANGE); @@ -4902,7 +4902,7 @@ static bool refine_endpoints_mode11( { for (uint32_t i = 0; i < num_block_pixels; i++) def_pixel_block_ofs[i] = (uint8_t)i; - + pPixel_block_ofs = def_pixel_block_ofs; } @@ -4928,7 +4928,7 @@ static bool refine_endpoints_mode11( trial_blk_raw_weights[i] = upsampled_weights[pPixel_block_ofs[i]]; trial_blk_raw_weightsf[i] = (float)trial_blk_raw_weights[i] * (1.0f / 64.0f); } - + vec3F l_q16, h_q16; if (opt_mode == cOrdinaryLeastSquares) { @@ -4959,7 +4959,7 @@ static bool refine_endpoints_mode11( { float mid = (0.0f - l) / (h - l); mid = clamp(mid, .01f, .99f); - + float lw = LOW_EMPHASIS_WEIGHT, mw = MIDDLE_EMPHASIS_WEIGHT, hw = HIGH_EMPHASIS_WEIGHT; if (opt_mode == cWeightedLeastSquaresHeavy) lw = LOW_EMPHASIS_WEIGHT_HEAVY, mw = MIDDLE_EMPHASIS_WEIGHT_HEAVY, hw = HIGH_EMPHASIS_WEIGHT_HEAVY; @@ -5019,7 +5019,7 @@ static bool refine_endpoints_mode11( } uint8_t trial_endpoints[NUM_MODE11_ENDPOINTS]; - + uint32_t submode_used; bool pack_succeeded = pack_mode11(l_q16, h_q16, endpoint_ise_range, trial_endpoints, coptions, direct_only, first_submode, last_submode, false, submode_used); @@ -5046,7 +5046,7 @@ static bool refine_endpoints_mode11( const float R_WEIGHT = coptions.m_r_err_scale, G_WEIGHT = coptions.m_g_err_scale; double cur_error = 0, trial_error = 0; - + for (uint32_t p = 0; p < num_pixels; p++) { const half_float* pDesired_half = &pBlock_pixels_half[p][0]; @@ -5173,7 +5173,7 @@ static bool refine_endpoints_mode7( vec3F block_mean_color_q16(calc_mean(num_pixels, pBlock_pixels_q16)); vec3F new_high_color_q16(block_mean_color_q16); - + const float one_over_num_pixels = 1.0f / (float)num_pixels; for (uint32_t i = 0; i < num_pixels; i++) @@ -5185,7 +5185,7 @@ static bool refine_endpoints_mode7( new_high_color_q16[1] += k; new_high_color_q16[2] += k; } - + // Given a set of selectors and a high color, try to compute a better S. float t = 0.0f; @@ -5197,7 +5197,7 @@ static bool refine_endpoints_mode7( } t *= one_over_num_pixels; - + if (fabs(t) < .0000125f) return false; @@ -5223,7 +5223,7 @@ static bool refine_endpoints_mode7( if (!decode_mode7_to_qlog12(trial_endpoints, trial_e, nullptr, endpoint_ise_range)) return false; - + // -- for (uint32_t i = 0; i < 3; i++) @@ -5354,4 +5354,3 @@ bool refine_endpoints( } } // namespace basisu - diff --git a/encoder/basisu_astc_hdr_common.h b/encoder/basisu_astc_hdr_common.h index 55be403f..18f424fe 100644 --- a/encoder/basisu_astc_hdr_common.h +++ b/encoder/basisu_astc_hdr_common.h @@ -12,7 +12,7 @@ namespace basisu const uint32_t MODE11_TOTAL_SUBMODES = 8; // plus an extra hidden submode, directly encoded, for direct, so really 9 (see tables 99/100 of the ASTC spec) const uint32_t MODE7_TOTAL_SUBMODES = 6; - + // [ise_range][0] = # levels // [ise_range][1...] = lerp value [0,64] // in ASTC order @@ -33,9 +33,9 @@ namespace basisu { float m_r_err_scale, m_g_err_scale; float m_q_log_bias; - + bool m_ultra_quant; - + // If true, the ASTC HDR compressor is allowed to more aggressively vary weight indices for slightly higher compression in non-fastest mode. This will hurt BC6H quality, however. bool m_allow_uber_mode; @@ -45,7 +45,7 @@ namespace basisu bool m_take_first_non_clamping_mode7_submode; bool m_disable_weight_plane_optimization; - + astc_hdr_codec_base_options() { init(); } void init(); @@ -173,7 +173,7 @@ namespace basisu basist::half_float* pDecoded_half, vec3F* pDecoded_float, uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range); - + // Fast high precision piecewise linear approximation of log2(bias+x). // Half may be zero, positive or denormal. No NaN/Inf/negative. BASISU_FORCE_INLINE double q(basist::half_float x, float log_bias) @@ -183,7 +183,7 @@ namespace basisu fi.f = fast_half_to_float_pos_not_inf_or_nan(x); assert(fi.f >= 0.0f); - + fi.f += log_bias; return (double)fi.u; // approx log2f(fi.f), need to return double for the precision @@ -196,7 +196,7 @@ namespace basisu fi.f = fast_half_to_float_pos_not_inf_or_nan(x); assert(fi.f >= 0.0f); - + fi.f += log_bias; return fi.u; @@ -298,8 +298,8 @@ namespace basisu uint32_t ise_endpoint_range, bool uber_mode, bool constrain_ise_weight_selectors, - int32_t first_submode, int32_t last_submode, bool ignore_clamping, - opt_mode_t opt_mode, + int32_t first_submode, int32_t last_submode, bool ignore_clamping, + opt_mode_t opt_mode, const encode_astc_block_stats *pBlock_stats = nullptr); double encode_astc_hdr_block_downsampled_mode_11( @@ -325,7 +325,7 @@ namespace basisu uint32_t ise_endpoint_range, bool uber_mode, bool constrain_ise_weight_selectors, - int32_t first_submode, int32_t last_submode, + int32_t first_submode, int32_t last_submode, bool ignore_clamping); double encode_astc_hdr_block_mode_7( @@ -337,8 +337,8 @@ namespace basisu uint8_t* blk_endpoints, //[4] uint8_t* blk_weights, // [num_pixels] const astc_hdr_codec_base_options& coptions, - uint32_t ise_endpoint_range, - int first_submode = 0, int last_submode = MAX_MODE7_SUBMODE_INDEX, + uint32_t ise_endpoint_range, + int first_submode = 0, int last_submode = MAX_MODE7_SUBMODE_INDEX, const encode_astc_block_stats *pBlock_stats = nullptr); //-------------------------------------------------------------------------------------------------------------------------- @@ -373,17 +373,17 @@ namespace basisu bool pack_astc_mode11_submode(uint32_t submode, uint8_t* pEndpoints, int val_q[2][3], int& max_clamp_mag, bool early_out_if_clamped = false, int max_clamp_mag_accept_thresh = 0); bool pack_astc_mode11_submode(uint32_t submode, uint8_t* pEndpoints, const vec3F& low_q16, const vec3F& high_q16, int& max_clamp_mag, bool early_out_if_clamped = false, int max_clamp_mag_accept_thresh = 0); void pack_astc_mode11_direct(uint8_t* pEndpoints, vec3F l_q16, vec3F h_q16); - + bool pack_mode11(mode11_log_desc& desc, uint8_t* pEndpoints); void unpack_mode11(const uint8_t* pEndpoints, mode11_log_desc& desc); void decode_cem_11_config(const uint8_t* pEndpoints, int& submode_index, int& maj_index); void decode_cem_7_config(const uint8_t* pEndpoints, int& submode_index, int& maj_index); - + void dequantize_astc_weights(uint32_t n, const uint8_t* pSrc_ise_vals, uint32_t from_ise_range, uint8_t* pDst_raw_weights); const float* get_6x6_downsample_matrix(uint32_t grid_width, uint32_t grid_height); - + void downsample_weight_grid( const float* pMatrix_weights, uint32_t bx, uint32_t by, // source/from dimension (block size) @@ -413,11 +413,10 @@ namespace basisu uint32_t num_pixels, const basist::half_float pBlock_pixels_half[][3], const vec4F pBlock_pixels_q16[], const uint8_t* pPixel_block_ofs, // maps this subset's pixels to block offsets astc_hdr_codec_base_options& coptions, opt_mode_t opt_mode); - + extern bool g_astc_hdr_enc_initialized; // This MUST be called before encoding any blocks. void astc_hdr_enc_init(); } // namespace basisu - diff --git a/encoder/basisu_backend.cpp b/encoder/basisu_backend.cpp index 3fa3d889..8096e258 100644 --- a/encoder/basisu_backend.cpp +++ b/encoder/basisu_backend.cpp @@ -54,7 +54,7 @@ namespace basisu m_pFront_end = pFront_end; m_params = params; m_slices = slice_descs; - + debug_printf("basisu_backend::Init: Slices: %u, ETC1S: %u, EndpointRDOQualityThresh: %f, SelectorRDOQualityThresh: %f\n", m_slices.size(), params.m_etc1s, @@ -196,7 +196,7 @@ namespace basisu m_endpoint_remap_table_old_to_new = reorderer.get_remap_table(); } - // For endpoints, old_to_new[] may not be bijective! + // For endpoints, old_to_new[] may not be bijective! // Some "old" entries may be unused and don't get remapped into the "new" array. m_old_endpoint_was_used.clear(); @@ -220,13 +220,13 @@ namespace basisu } // slice_index debug_printf("basisu_backend::reoptimize_and_sort_endpoints_codebook: First old entry index: %u\n", first_old_entry_index); - + m_new_endpoint_was_used.clear(); m_new_endpoint_was_used.resize(r.get_total_endpoint_clusters()); m_endpoint_remap_table_new_to_old.clear(); m_endpoint_remap_table_new_to_old.resize(r.get_total_endpoint_clusters()); - + // Set unused entries in the new array to point to the first used entry in the old array. m_endpoint_remap_table_new_to_old.set_all(first_old_entry_index); @@ -235,7 +235,7 @@ namespace basisu if (m_old_endpoint_was_used[old_index]) { const uint32_t new_index = m_endpoint_remap_table_old_to_new[old_index]; - + m_new_endpoint_was_used[new_index] = true; m_endpoint_remap_table_new_to_old[new_index] = old_index; @@ -612,7 +612,7 @@ namespace basisu sort_selector_codebook(); check_for_valid_cr_blocks(); - + debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); } @@ -669,11 +669,11 @@ namespace basisu gi.unpack(gi_unpacked); char buf[256]; -#ifdef _WIN32 +#ifdef _WIN32 sprintf_s(buf, sizeof(buf), "basisu_backend_slice_%u.png", slice_index); #else snprintf(buf, sizeof(buf), "basisu_backend_slice_%u.png", slice_index); -#endif +#endif save_png(buf, gi_unpacked); } @@ -682,7 +682,7 @@ namespace basisu //uint32_t g_color_delta_hist[255 * 3 + 1]; //uint32_t g_color_delta_bad_hist[255 * 3 + 1]; - + // TODO: Split this into multiple methods. bool basisu_backend::encode_image() { @@ -718,7 +718,7 @@ namespace basisu const int COLOR_DELTA_THRESH = 8; const int SEL_DIFF_THRESHOLD = 11; - + for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++) { //const int prev_frame_slice_index = is_video ? find_video_frame(slice_index, -1) : -1; @@ -764,7 +764,7 @@ namespace basisu } // block_x } // block_y - + for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++) { for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++) @@ -842,7 +842,7 @@ namespace basisu const uint32_t cur_inten5 = etc_blk.get_inten_table(0); const etc1_endpoint_palette_entry& cur_endpoints = m_endpoint_palette[m.m_endpoint_index]; - + if (cur_err) { const float endpoint_remap_thresh = maximum(1.0f, m_params.m_endpoint_rdo_quality_thresh); @@ -858,7 +858,7 @@ namespace basisu int best_trial_idx = 0; etc_block trial_etc_blk(etc_blk); - + const int search_dist = minimum(iabs(endpoint_delta) - 1, MAX_ENDPOINT_SEARCH_DIST); for (int d = -search_dist; d < search_dist; d++) { @@ -876,7 +876,7 @@ namespace basisu continue; const etc1_endpoint_palette_entry& p = m_endpoint_palette[m_endpoint_remap_table_new_to_old[trial_idx]]; - + if (m_params.m_compression_level <= 1) { if (p.m_inten5 > cur_inten5) @@ -886,7 +886,7 @@ namespace basisu int delta_g = iabs(cur_endpoints.m_color5.g - p.m_color5.g); int delta_b = iabs(cur_endpoints.m_color5.b - p.m_color5.b); int color_delta = delta_r + delta_g + delta_b; - + if (color_delta > COLOR_DELTA_THRESH) continue; } @@ -924,7 +924,7 @@ namespace basisu const int64_t initial_best_trial_err = INT64_MAX; int64_t best_trial_err = initial_best_trial_err; int best_trial_idx = 0; - + const int search_dist = minimum(iabs(endpoint_delta) - 1, MAX_ENDPOINT_SEARCH_DIST); for (int d = -search_dist; d < search_dist; d++) { @@ -942,7 +942,7 @@ namespace basisu continue; const etc1_endpoint_palette_entry& p = m_endpoint_palette[m_endpoint_remap_table_new_to_old[trial_idx]]; - + if (m_params.m_compression_level <= 1) { if (p.m_inten5 > cur_inten5) @@ -952,7 +952,7 @@ namespace basisu int delta_g = iabs(cur_endpoints.m_color5.g - p.m_color5.g); int delta_b = iabs(cur_endpoints.m_color5.b - p.m_color5.b); int color_delta = delta_r + delta_g + delta_b; - + if (color_delta > COLOR_DELTA_THRESH) continue; } @@ -992,7 +992,7 @@ namespace basisu } #endif // BASISU_SUPPORT_SSE } // if (!g_cpu_supports_sse41) - + } // if (cur_err) } // if ((m_params.m_endpoint_rdo_quality_thresh > 1.0f) && (iabs(endpoint_delta) > 1) && (!block_endpoints_are_referenced(block_x, block_y))) @@ -1011,7 +1011,7 @@ namespace basisu if ((!is_video) || (m.m_endpoint_predictor != basist::CR_ENDPOINT_PRED_INDEX)) { int new_selector_index = m_selector_remap_table_old_to_new[m.m_selector_index]; - + const float selector_remap_thresh = maximum(1.0f, m_params.m_selector_rdo_quality_thresh); //2.5f; int selector_history_buf_index = -1; @@ -1060,7 +1060,7 @@ namespace basisu for (uint32_t p = 0; p < 16; p++) cur_err += color_distance(false, src_pixels.get_ptr()[p], block_colors[pCur_selectors[p]], false); } - + const uint64_t limit_err = (uint64_t)ceilf(cur_err * selector_remap_thresh); // Even if cur_err==limit_err, we still want to scan the history buffer because there may be equivalent entries that are cheaper to code. @@ -1091,7 +1091,7 @@ namespace basisu if (sel_diff >= SEL_DIFF_THRESHOLD) continue; } - + const uint64_t thresh_err = minimum(limit_err, best_trial_err); uint64_t trial_err = 0; @@ -1266,7 +1266,7 @@ namespace basisu //{ // printf("%u, %u, %f\n", g_color_delta_bad_hist[i], g_color_delta_hist[i], g_color_delta_hist[i] ? g_color_delta_bad_hist[i] / (float)g_color_delta_hist[i] : 0); //} - + double total_prep_time = tm.get_elapsed_secs(); debug_printf("basisu_backend::encode_image: Total prep time: %3.2f\n", total_prep_time); @@ -1521,7 +1521,7 @@ namespace basisu if (old_endpoint_was_used[old_endpoint_index]) { const uint32_t new_endpoint_index = m_endpoint_remap_table_old_to_new[old_endpoint_index]; - + new_endpoint_was_used[new_endpoint_index] = true; endpoint_remap_table_new_to_old[new_endpoint_index] = old_endpoint_index; @@ -1660,7 +1660,7 @@ namespace basisu bool basisu_backend::encode_selector_palette() { const basisu_frontend& r = *m_pFront_end; - + histogram delta_selector_pal_histogram(256); for (uint32_t q = 0; q < r.get_total_selector_clusters(); q++) diff --git a/encoder/basisu_backend.h b/encoder/basisu_backend.h index 58a9a8aa..b3365582 100644 --- a/encoder/basisu_backend.h +++ b/encoder/basisu_backend.h @@ -103,8 +103,8 @@ namespace basisu { clear(); } - - uint32_t m_endpoint_predictor; + + uint32_t m_endpoint_predictor; int m_endpoint_index; int m_selector_index; @@ -115,10 +115,10 @@ namespace basisu void clear() { m_endpoint_predictor = 0; - + m_endpoint_index = 0; m_selector_index = 0; - + m_selector_history_buf_index = 0; m_is_cr_target = false; } @@ -137,7 +137,7 @@ namespace basisu color_rgba m_color5; uint32_t m_inten5; bool m_color5_valid; - + void clear() { clear_obj(*this); @@ -153,7 +153,7 @@ namespace basisu float m_endpoint_rdo_quality_thresh; float m_selector_rdo_quality_thresh; uint32_t m_compression_level; - + bool m_used_global_codebooks; bool m_validate; @@ -285,7 +285,7 @@ namespace basisu basisu_backend_params m_params; basisu_backend_slice_desc_vec m_slices; basisu_backend_output m_output; - + etc1_endpoint_palette_entry_vec m_endpoint_palette; etc1_selector_palette_entry_vec m_selector_palette; @@ -331,12 +331,12 @@ namespace basisu return slice.m_first_block_index + block_y * slice.m_num_blocks_x + block_x; } - + uint32_t get_total_blocks(uint32_t slice_index) const { return m_slices[slice_index].m_num_blocks_x * m_slices[slice_index].m_num_blocks_y; } - + uint32_t get_total_blocks() const { uint32_t total_blocks = 0; @@ -406,4 +406,3 @@ namespace basisu }; } // namespace basisu - diff --git a/encoder/basisu_basis_file.cpp b/encoder/basisu_basis_file.cpp index 77f467f6..19b398cb 100644 --- a/encoder/basisu_basis_file.cpp +++ b/encoder/basisu_basis_file.cpp @@ -27,14 +27,14 @@ namespace basisu m_header.m_data_size = m_total_file_size - sizeof(basist::basis_file_header); m_header.m_total_slices = (uint32_t)encoder_output.m_slice_desc.size(); - + m_header.m_total_images = 0; for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++) m_header.m_total_images = maximum(m_header.m_total_images, encoder_output.m_slice_desc[i].m_source_file_index + 1); - + m_header.m_tex_format = (int)encoder_output.m_tex_format; m_header.m_flags = 0; - + if (encoder_output.m_etc1s) { assert(encoder_output.m_tex_format == basist::basis_tex_format::cETC1S); @@ -51,7 +51,7 @@ namespace basisu m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagUsesGlobalCodebook; if (encoder_output.m_srgb) m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagSRGB; - + for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++) { if (encoder_output.m_slice_desc[i].m_alpha) @@ -108,7 +108,7 @@ namespace basisu m_images_descs[i].m_image_index = slice_descs[i].m_source_file_index; m_images_descs[i].m_level_index = slice_descs[i].m_mip_index; - + if (slice_descs[i].m_alpha) m_images_descs[i].m_flags = m_images_descs[i].m_flags | basist::cSliceDescFlagsHasAlpha; if (slice_descs[i].m_iframe) @@ -186,7 +186,7 @@ namespace basisu pHeader->m_data_size = m_total_file_size - sizeof(basist::basis_file_header); pHeader->m_data_crc16 = basist::crc16(&m_comp_data[0] + sizeof(basist::basis_file_header), m_total_file_size - sizeof(basist::basis_file_header), 0); - + pHeader->m_header_crc16 = basist::crc16(&pHeader->m_data_size, sizeof(basist::basis_file_header) - BASISU_OFFSETOF(basist::basis_file_header, m_data_size), 0); pHeader->m_sig = basist::basis_file_header::cBASISSigValue; @@ -242,7 +242,7 @@ namespace basisu m_tables_file_ofs = 0; m_first_image_file_ofs = m_slice_descs_file_ofs + sizeof(basist::basis_slice_desc) * (uint32_t)slice_descs.size(); } - + uint64_t total_file_size = m_first_image_file_ofs; for (uint32_t i = 0; i < encoder_output.m_slice_image_data.size(); i++) total_file_size += encoder_output.m_slice_image_data[i].size(); diff --git a/encoder/basisu_bc7enc.cpp b/encoder/basisu_bc7enc.cpp index 914e7fbb..87c4e601 100644 --- a/encoder/basisu_bc7enc.cpp +++ b/encoder/basisu_bc7enc.cpp @@ -100,24 +100,24 @@ static void astc_init() { if (!astc_is_valid_endpoint_range(range)) continue; - + const uint32_t levels = astc_get_levels(range); uint32_t vals[256]; // TODO for (uint32_t i = 0; i < levels; i++) vals[i] = (unquant_astc_endpoint_val(i, range) << 8) | i; - + std::sort(vals, vals + levels); for (uint32_t i = 0; i < levels; i++) { uint32_t order = vals[i] & 0xFF; uint32_t unq = vals[i] >> 8; - + g_astc_sorted_order_unquant[range][i].m_unquant = (uint8_t)unq; g_astc_sorted_order_unquant[range][i].m_index = (uint8_t)order; - + } // i #if 0 @@ -186,7 +186,7 @@ static inline uint32_t astc_interpolate_linear(uint32_t l, uint32_t h, uint32_t void bc7enc_compress_block_init() { astc_init(); - + // BC7 666.1 for (int c = 0; c < 256; c++) { @@ -224,11 +224,11 @@ void bc7enc_compress_block_init() for (uint32_t l = 0; l < 16; l++) { uint32_t low = (l << 4) | l; - + for (uint32_t h = 0; h < 16; h++) { uint32_t high = (h << 4) | h; - + const int k = astc_interpolate_linear(low, high, g_bc7_weights3[BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX]); const int err = (k - c) * (k - c); @@ -240,9 +240,9 @@ void bc7enc_compress_block_init() } } // h } // l - + g_astc_4bit_3bit_optimal_endpoints[c] = best; - + } // c // ASTC [0,15] 2-bit @@ -253,11 +253,11 @@ void bc7enc_compress_block_init() for (uint32_t l = 0; l < 16; l++) { uint32_t low = (l << 4) | l; - + for (uint32_t h = 0; h < 16; h++) { uint32_t high = (h << 4) | h; - + const int k = astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX]); const int err = (k - c) * (k - c); @@ -269,9 +269,9 @@ void bc7enc_compress_block_init() } } // h } // l - + g_astc_4bit_2bit_optimal_endpoints[c] = best; - + } // c // ASTC range 7 [0,11] 2-bit @@ -282,11 +282,11 @@ void bc7enc_compress_block_init() for (uint32_t l = 0; l < 12; l++) { uint32_t low = g_astc_sorted_order_unquant[7][l].m_unquant; - + for (uint32_t h = 0; h < 12; h++) { uint32_t high = g_astc_sorted_order_unquant[7][h].m_unquant; - + const int k = astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX]); const int err = (k - c) * (k - c); @@ -298,9 +298,9 @@ void bc7enc_compress_block_init() } } // h } // l - + g_astc_range7_2bit_optimal_endpoints[c] = best; - + } // c // ASTC range 13 [0,47] 4-bit @@ -311,11 +311,11 @@ void bc7enc_compress_block_init() for (uint32_t l = 0; l < 48; l++) { uint32_t low = g_astc_sorted_order_unquant[13][l].m_unquant; - + for (uint32_t h = 0; h < 48; h++) { uint32_t high = g_astc_sorted_order_unquant[13][h].m_unquant; - + const int k = astc_interpolate_linear(low, high, g_astc_weights4[BC7ENC_ASTC_RANGE13_4BIT_OPTIMAL_INDEX]); const int err = (k - c) * (k - c); @@ -327,9 +327,9 @@ void bc7enc_compress_block_init() } } // h } // l - + g_astc_range13_4bit_optimal_endpoints[c] = best; - + } // c // ASTC range 13 [0,47] 2-bit @@ -340,11 +340,11 @@ void bc7enc_compress_block_init() for (uint32_t l = 0; l < 48; l++) { uint32_t low = g_astc_sorted_order_unquant[13][l].m_unquant; - + for (uint32_t h = 0; h < 48; h++) { uint32_t high = g_astc_sorted_order_unquant[13][h].m_unquant; - + const int k = astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX]); const int err = (k - c) * (k - c); @@ -356,9 +356,9 @@ void bc7enc_compress_block_init() } } // h } // l - + g_astc_range13_2bit_optimal_endpoints[c] = best; - + } // c // ASTC range 11 [0,31] 5-bit @@ -393,7 +393,7 @@ void bc7enc_compress_block_init() static void compute_least_squares_endpoints_rgba(uint32_t N, const uint8_t *pSelectors, const bc7enc_vec4F* pSelector_weights, bc7enc_vec4F* pXl, bc7enc_vec4F* pXh, const color_quad_u8 *pColors) { - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. double z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; @@ -401,7 +401,7 @@ static void compute_least_squares_endpoints_rgba(uint32_t N, const uint8_t *pSel double q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f; double q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f; double q00_a = 0.0f, q10_a = 0.0f, t_a = 0.0f; - + for (uint32_t i = 0; i < N; i++) { const uint32_t sel = pSelectors[i]; @@ -649,7 +649,7 @@ static uint64_t pack_astc_4bit_3bit_to_one_color(const color_cell_compressor_par { uint32_t low = (pResults->m_low_endpoint.m_c[i] << 4) | pResults->m_low_endpoint.m_c[i]; uint32_t high = (pResults->m_high_endpoint.m_c[i] << 4) | pResults->m_high_endpoint.m_c[i]; - + p.m_c[i] = (uint8_t)astc_interpolate_linear(low, high, g_bc7_weights3[BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX]); } p.m_c[3] = 255; @@ -688,10 +688,10 @@ static uint64_t pack_astc_4bit_2bit_to_one_color_rgba(const color_cell_compresso { uint32_t low = (pResults->m_low_endpoint.m_c[i] << 4) | pResults->m_low_endpoint.m_c[i]; uint32_t high = (pResults->m_high_endpoint.m_c[i] << 4) | pResults->m_high_endpoint.m_c[i]; - + p.m_c[i] = (uint8_t)astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX]); } - + uint64_t total_err = 0; for (uint32_t i = 0; i < pParams->m_num_pixels; i++) total_err += compute_color_distance_rgba(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights); @@ -727,7 +727,7 @@ static uint64_t pack_astc_range7_2bit_to_one_color(const color_cell_compressor_p { uint32_t low = g_astc_sorted_order_unquant[7][pResults->m_low_endpoint.m_c[i]].m_unquant; uint32_t high = g_astc_sorted_order_unquant[7][pResults->m_high_endpoint.m_c[i]].m_unquant; - + p.m_c[i] = (uint8_t)astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX]); } p.m_c[3] = 255; @@ -748,7 +748,7 @@ static uint64_t pack_astc_range13_2bit_to_one_color(const color_cell_compressor_ const endpoint_err *pEr = &g_astc_range13_2bit_optimal_endpoints[r]; const endpoint_err *pEg = &g_astc_range13_2bit_optimal_endpoints[g]; const endpoint_err *pEb = &g_astc_range13_2bit_optimal_endpoints[b]; - + color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 47); color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 47); pResults->m_pbits[0] = 0; @@ -767,10 +767,10 @@ static uint64_t pack_astc_range13_2bit_to_one_color(const color_cell_compressor_ { uint32_t low = g_astc_sorted_order_unquant[13][pResults->m_low_endpoint.m_c[i]].m_unquant; uint32_t high = g_astc_sorted_order_unquant[13][pResults->m_high_endpoint.m_c[i]].m_unquant; - + p.m_c[i] = (uint8_t)astc_interpolate_linear(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX]); } - + uint64_t total_err = 0; for (uint32_t i = 0; i < pParams->m_num_pixels; i++) total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights); @@ -879,18 +879,18 @@ static uint64_t evaluate_solution(const color_quad_u8 *pLow, const color_quad_u8 const int dr = actualMaxColor.m_c[0] - lr; const int dg = actualMaxColor.m_c[1] - lg; const int db = actualMaxColor.m_c[2] - lb; - + uint64_t total_err = 0; - + if (pParams->m_pForce_selectors) { for (uint32_t i = 0; i < pParams->m_num_pixels; i++) { const color_quad_u8* pC = &pParams->m_pPixels[i]; - + const uint8_t sel = pParams->m_pForce_selectors[i]; assert(sel < N); - + total_err += (pParams->m_has_alpha ? compute_color_distance_rgba : compute_color_distance_rgb)(&weightedColors[sel], pC, pParams->m_perceptual, pParams->m_weights); pResults->m_pSelectors_temp[i] = sel; @@ -931,7 +931,7 @@ static uint64_t evaluate_solution(const color_quad_u8 *pLow, const color_quad_u8 --best_sel; } total_err += err1; - + pResults->m_pSelectors_temp[i] = (uint8_t)best_sel; } } @@ -1028,7 +1028,7 @@ static uint64_t evaluate_solution(const color_quad_u8 *pLow, const color_quad_u8 memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels); } - + return total_err; } @@ -1258,7 +1258,7 @@ static uint64_t find_optimal_solution(uint32_t mode, bc7enc_vec4F xl, bc7enc_vec } } } - + fixDegenerateEndpoints(mode, &bestMinColor, &bestMaxColor, &xl, &xh, iscalep >> 1, 0); if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&bestMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&bestMaxColor, &pResults->m_high_endpoint) || (best_pbits[0] != pResults->m_pbits[0]) || (best_pbits[1] != pResults->m_pbits[1])) @@ -1297,7 +1297,7 @@ void check_best_overall_error(const color_cell_compressor_params *pParams, color colors[n-1].m_c[c] = g_astc_unquant[pParams->m_astc_endpoint_range][pResults->m_astc_high_endpoint.m_c[c]].m_unquant; assert(colors[n-1].m_c[c] == g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[c]].m_unquant); } - + for (uint32_t i = 1; i < pParams->m_num_selector_weights - 1; i++) for (uint32_t c = 0; c < 4; c++) colors[i].m_c[c] = (uint8_t)astc_interpolate_linear(colors[0].m_c[c], colors[n - 1].m_c[c], pParams->m_pSelector_weights[i]); @@ -1308,7 +1308,7 @@ void check_best_overall_error(const color_cell_compressor_params *pParams, color { const color_quad_u8 &orig = pParams->m_pPixels[p]; const color_quad_u8 &packed = colors[pResults->m_pSelectors[p]]; - + if (pParams->m_has_alpha) total_err += compute_color_distance_rgba(&orig, &packed, pParams->m_perceptual, pParams->m_weights); else @@ -1316,7 +1316,7 @@ void check_best_overall_error(const color_cell_compressor_params *pParams, color } assert(total_err == pResults->m_best_overall_err); #endif - + // HACK HACK //if (total_err != pResults->m_best_overall_err) // printf("X"); @@ -1419,12 +1419,12 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param bc7enc_vec4F color = vec4F_from_color(&pParams->m_pPixels[i]); meanColor = vec4F_add(&meanColor, &color); } - + bc7enc_vec4F meanColorScaled = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels)); meanColor = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels * 255.0f)); vec4F_saturate_in_place(&meanColor); - + if (pParams->m_has_alpha) { // Use incremental PCA for RGBA PCA, because it's simple. @@ -1487,7 +1487,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param vec4F_set(&axis, xr, xg, xb, 0); } } - + if (vec4F_dot(&axis, &axis) < .5f) { if (pParams->m_perceptual) @@ -1496,7 +1496,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param vec4F_set(&axis, 1.0f, 1.0f, 1.0f, pParams->m_has_alpha ? 1.0f : 0); vec4F_normalize_in_place(&axis); } - + bc7enc_vec4F minColor, maxColor; float l = 1e+9f, h = -1e+9f; @@ -1521,7 +1521,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param bc7enc_vec4F c1 = vec4F_add(&meanColor, &b1); minColor = vec4F_saturate(&c0); maxColor = vec4F_saturate(&c1); - + bc7enc_vec4F whiteVec; vec4F_set_scalar(&whiteVec, 1.0f); if (vec4F_dot(&minColor, &whiteVec) > vec4F_dot(&maxColor, &whiteVec)) @@ -1545,7 +1545,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param // First find a solution using the block's PCA. if (!find_optimal_solution(mode, minColor, maxColor, pParams, pResults)) return 0; - + for (uint32_t i = 0; i < pComp_params->m_least_squares_passes; i++) { // Now try to refine the solution using least squares by computing the optimal endpoints from the current selectors. @@ -1559,11 +1559,11 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param xl = vec4F_mul(&xl, (1.0f / 255.0f)); xh = vec4F_mul(&xh, (1.0f / 255.0f)); - + if (!find_optimal_solution(mode, xl, xh, pParams, pResults)) return 0; } - + if ((!pParams->m_pForce_selectors) && (pComp_params->m_uber_level > 0)) { // In uber level 1, try varying the selectors a little, somewhat like cluster fit would. First try incrementing the minimum selectors, @@ -1600,7 +1600,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param xl = vec4F_mul(&xl, (1.0f / 255.0f)); xh = vec4F_mul(&xh, (1.0f / 255.0f)); - + if (!find_optimal_solution(mode, xl, xh, pParams, pResults)) return 0; @@ -1619,7 +1619,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param xl = vec4F_mul(&xl, (1.0f / 255.0f)); xh = vec4F_mul(&xh, (1.0f / 255.0f)); - + if (!find_optimal_solution(mode, xl, xh, pParams, pResults)) return 0; @@ -1676,7 +1676,7 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param } } } - + if (!pParams->m_pForce_selectors) { // Try encoding the partition as a single color by using the optimal single colors tables to encode the block to its mean. @@ -1757,13 +1757,13 @@ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_param #if BC7ENC_CHECK_OVERALL_ERROR check_best_overall_error(pParams, pResults); #endif - + return pResults->m_best_overall_err; } uint64_t color_cell_compression_est_astc( uint32_t num_weights, uint32_t num_comps, const uint32_t *pWeight_table, - uint32_t num_pixels, const color_quad_u8* pPixels, + uint32_t num_pixels, const color_quad_u8* pPixels, uint64_t best_err_so_far, const uint32_t weights[4]) { assert(num_comps == 3 || num_comps == 4); @@ -1810,7 +1810,7 @@ uint64_t color_cell_compression_est_astc( color_quad_u8_set(&lowColor, lr, lg, lb, la); color_quad_u8_set(&highColor, hr, hg, hb, ha); - // Place endpoints at bbox diagonals and compute interpolated colors + // Place endpoints at bbox diagonals and compute interpolated colors color_quad_u8 weightedColors[32]; weightedColors[0] = lowColor; diff --git a/encoder/basisu_bc7enc.h b/encoder/basisu_bc7enc.h index 925d6b2e..af147c59 100644 --- a/encoder/basisu_bc7enc.h +++ b/encoder/basisu_bc7enc.h @@ -26,7 +26,7 @@ namespace basisu #define BC7ENC_TRUE (1) #define BC7ENC_FALSE (0) - + typedef struct { float m_c[4]; } bc7enc_vec4F; extern const float g_bc7_weights1x[2 * 4]; @@ -36,9 +36,9 @@ namespace basisu extern const float g_astc_weights4x[16 * 4]; extern const float g_astc_weights5x[32 * 4]; extern const float g_astc_weights_3levelsx[3 * 4]; - + extern basist::astc_quant_bin g_astc_sorted_order_unquant[basist::BC7ENC_TOTAL_ASTC_RANGES][256]; // [sorted unquantized order] - + struct color_cell_compressor_params { uint32_t m_num_pixels; @@ -94,12 +94,12 @@ namespace basisu }; uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_params* pParams, color_cell_compressor_results* pResults, const bc7enc_compress_block_params* pComp_params); - + uint64_t color_cell_compression_est_astc( uint32_t num_weights, uint32_t num_comps, const uint32_t* pWeight_table, uint32_t num_pixels, const basist::color_quad_u8* pPixels, uint64_t best_err_so_far, const uint32_t weights[4]); - + inline void bc7enc_compress_block_params_init_linear_weights(bc7enc_compress_block_params* p) { p->m_perceptual = BC7ENC_FALSE; @@ -128,5 +128,5 @@ namespace basisu // bc7enc_compress_block_init() MUST be called before calling bc7enc_compress_block() (or you'll get artifacts). void bc7enc_compress_block_init(); - + } // namespace basisu diff --git a/encoder/basisu_comp.cpp b/encoder/basisu_comp.cpp index 59a2a509..d684b657 100644 --- a/encoder/basisu_comp.cpp +++ b/encoder/basisu_comp.cpp @@ -63,7 +63,7 @@ namespace basisu m_opencl_failed(false) { debug_printf("basis_compressor::basis_compressor\n"); - + assert(g_library_initialized); } @@ -195,7 +195,7 @@ namespace basisu bool basis_compressor::init(const basis_compressor_params ¶ms) { debug_printf("basis_compressor::init\n"); - + if (!g_library_initialized) { error_printf("basis_compressor::init: basisu_encoder_init() MUST be called before using any encoder functionality!\n"); @@ -207,7 +207,7 @@ namespace basisu error_printf("basis_compressor::init: A non-null job_pool pointer must be specified\n"); return false; } - + m_params = params; if ((m_params.m_compute_stats) && (!m_params.m_validate_output_data)) @@ -218,7 +218,7 @@ namespace basisu m_upconverted_any_ldr_images = false; check_for_hdr_inputs(); - + if (m_params.m_debug) { debug_printf("basis_compressor::init:\n"); @@ -227,7 +227,7 @@ namespace basisu #define PRINT_INT_VALUE(v) fmt_debug_printf("{}: {} {}\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); #define PRINT_UINT_VALUE(v) fmt_debug_printf("{}: {} {}\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); #define PRINT_FLOAT_VALUE(v) fmt_debug_printf("{}: {} {}\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); - + fmt_debug_printf("Source LDR images: {}, HDR images: {}, filenames: {}, alpha filenames: {}, LDR mipmap images: {}, HDR mipmap images: {}\n", (uint64_t)m_params.m_source_images.size(), (uint64_t)m_params.m_source_images_hdr.size(), (uint64_t)m_params.m_source_filenames.size(), (uint64_t)m_params.m_source_alpha_filenames.size(), @@ -296,10 +296,10 @@ namespace basisu PRINT_BOOL_VALUE(m_renormalize); PRINT_BOOL_VALUE(m_multithreading); PRINT_BOOL_VALUE(m_disable_hierarchical_endpoint_codebooks); - + PRINT_FLOAT_VALUE(m_endpoint_rdo_thresh); PRINT_FLOAT_VALUE(m_selector_rdo_thresh); - + PRINT_BOOL_VALUE(m_mip_gen); PRINT_BOOL_VALUE(m_mip_renormalize); PRINT_BOOL_VALUE(m_mip_wrapping); @@ -319,7 +319,7 @@ namespace basisu debug_printf("m_userdata0: 0x%X, m_userdata1: 0x%X\n", m_params.m_userdata0, m_params.m_userdata1); debug_printf("m_us_per_frame: %i (%f fps)\n", m_params.m_us_per_frame, m_params.m_us_per_frame ? 1.0f / (m_params.m_us_per_frame / 1000000.0f) : 0); debug_printf("m_pack_uastc_ldr_4x4_flags: 0x%X\n", m_params.m_pack_uastc_ldr_4x4_flags); - + PRINT_BOOL_VALUE(m_rdo_uastc_ldr_4x4); PRINT_FLOAT_VALUE(m_rdo_uastc_ldr_4x4_quality_scalar); PRINT_INT_VALUE(m_rdo_uastc_ldr_4x4_dict_size); @@ -333,7 +333,7 @@ namespace basisu PRINT_INT_VALUE(m_resample_width); PRINT_INT_VALUE(m_resample_height); PRINT_FLOAT_VALUE(m_resample_factor); - + debug_printf("Has global codebooks: %u\n", m_params.m_pGlobal_codebooks ? 1 : 0); if (m_params.m_pGlobal_codebooks) { @@ -358,7 +358,7 @@ namespace basisu debug_printf("Allow UASTC HDR 4x4 uber mode: %u\n", m_params.m_uastc_hdr_4x4_options.m_allow_uber_mode); debug_printf("UASTC HDR 4x4 ultra quant: %u\n", m_params.m_uastc_hdr_4x4_options.m_ultra_quant); PRINT_BOOL_VALUE(m_hdr_favor_astc); - + #undef PRINT_BOOL_VALUE #undef PRINT_INT_VALUE #undef PRINT_UINT_VALUE @@ -367,7 +367,7 @@ namespace basisu if (!sanity_check_input_params()) return false; - + if ((m_params.m_use_opencl) && opencl_is_available() && !m_pOpenCL_context && !m_opencl_failed) { m_pOpenCL_context = opencl_create_context(); @@ -433,7 +433,7 @@ namespace basisu } } } - + basis_compressor::error_code basis_compressor::process() { debug_printf("basis_compressor::process\n"); @@ -443,7 +443,7 @@ namespace basisu // Note: After here m_params.m_hdr, m_params.m_uastc and m_fmt_mode cannot be changed. pick_format_mode(); - + if (!read_source_images()) return cECFailedReadingSourceImages; @@ -474,7 +474,7 @@ namespace basisu if (ec != cECSuccess) return ec; } - else + else { assert((m_params.m_hdr_mode == hdr_modes::cASTC_HDR_6X6) || (m_params.m_hdr_mode == hdr_modes::cASTC_HDR_6X6_INTERMEDIATE)); @@ -507,7 +507,7 @@ namespace basisu // ETC1S if (m_params.m_status_output) printf("Mode: ETC1S Quality %i, Level %i\n", m_params.m_etc1s_quality_level, (int)m_params.m_compression_level); - + if (!process_frontend()) return cECFailedFrontEnd; @@ -553,7 +553,7 @@ namespace basisu assert(0); return cECFailedEncodeUASTC; } - + m_uastc_backend_output.m_etc1s = false; m_uastc_backend_output.m_srgb = false; m_uastc_backend_output.m_slice_desc = m_slice_descs; @@ -561,13 +561,13 @@ namespace basisu m_uastc_backend_output.m_slice_image_crcs.resize(m_slice_descs.size()); astc_6x6_hdr::astc_hdr_6x6_global_config global_cfg(m_params.m_astc_hdr_6x6_options); - + global_cfg.m_image_stats = m_params.m_compute_stats; global_cfg.m_debug_images = m_params.m_debug_images; global_cfg.m_output_images = m_params.m_debug_images; global_cfg.m_debug_output = m_params.m_debug; global_cfg.m_status_output = m_params.m_status_output || m_params.m_debug; - + for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++) { gpu_image& dst_tex = m_uastc_slice_textures[slice_index]; @@ -578,7 +578,7 @@ namespace basisu const imagef& source_image = m_slice_images_hdr[slice_index]; assert(source_image.get_width() && source_image.get_height()); - + uint8_vec intermediate_tex_data, astc_tex_data; global_cfg.m_debug_image_prefix = m_params.m_astc_hdr_6x6_options.m_debug_image_prefix; @@ -586,7 +586,7 @@ namespace basisu global_cfg.m_output_image_prefix = m_params.m_astc_hdr_6x6_options.m_output_image_prefix; global_cfg.m_output_image_prefix += fmt_string("slice_{}_", slice_index); - + if (m_params.m_debug) fmt_debug_printf("----------------------------------------------------------------------------\n"); @@ -648,7 +648,7 @@ namespace basisu m_params.m_uastc_hdr_4x4_options.m_r_err_scale = 1.0f; m_params.m_uastc_hdr_4x4_options.m_g_err_scale = 1.0f; } - + const float DEFAULT_BC6H_ERROR_WEIGHT = .65f;// .85f; const float LOWEST_BC6H_ERROR_WEIGHT = .1f; m_params.m_uastc_hdr_4x4_options.m_bc6h_err_weight = m_params.m_hdr_favor_astc ? LOWEST_BC6H_ERROR_WEIGHT : DEFAULT_BC6H_ERROR_WEIGHT; @@ -657,7 +657,7 @@ namespace basisu any_failures.store(false); astc_hdr_4x4_block_stats enc_stats; - + struct uastc_blk_desc { uint32_t m_solid_flag; @@ -681,7 +681,7 @@ namespace basisu return false; } - + bool operator== (const uastc_blk_desc& desc) const { if (this == &desc) @@ -708,7 +708,7 @@ namespace basisu std::map unique_block_descs; std::mutex unique_block_desc_mutex; - + for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++) { gpu_image& tex = m_uastc_slice_textures[slice_index]; @@ -722,14 +722,14 @@ namespace basisu std::atomic total_blocks_processed; total_blocks_processed.store(0); - + const uint32_t N = 256; for (uint32_t block_index_iter = 0; block_index_iter < total_blocks; block_index_iter += N) { const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(total_blocks, block_index_iter + N); - - m_params.m_pJob_pool->add_job([this, first_index, last_index, num_blocks_x, num_blocks_y, total_blocks, &source_image, + + m_params.m_pJob_pool->add_job([this, first_index, last_index, num_blocks_x, num_blocks_y, total_blocks, &source_image, &tex, &total_blocks_processed, &any_failures, &enc_stats, &unique_block_descs, &unique_block_desc_mutex] { BASISU_NOTE_UNUSED(num_blocks_y); @@ -750,7 +750,7 @@ namespace basisu source_image.extract_block_clamped(&block_pixels[0], block_x * 4, block_y * 4, 4, 4); basist::astc_blk& dest_block = *(basist::astc_blk*)tex.get_block_ptr(block_x, block_y); - + float rgb_pixels[16 * 3]; basist::half_float rgb_pixels_half[16 * 3]; for (uint32_t i = 0; i < 16; i++) @@ -764,7 +764,7 @@ namespace basisu rgb_pixels[i * 3 + 2] = block_pixels[i][2]; rgb_pixels_half[i * 3 + 2] = float_to_half_non_neg_no_nan_inf(block_pixels[i][2]); } - + bool status = astc_hdr_4x4_enc_block(&rgb_pixels[0], rgb_pixels_half, m_params.m_uastc_hdr_4x4_options, all_results); if (!status) { @@ -774,10 +774,10 @@ namespace basisu double best_err = 1e+30f; int best_result_index = -1; - + const double bc6h_err_weight = m_params.m_uastc_hdr_4x4_options.m_bc6h_err_weight; const double astc_err_weight = (1.0f - bc6h_err_weight); - + for (uint32_t i = 0; i < all_results.size(); i++) { basist::half_float unpacked_bc6h_block[4 * 4 * 3]; @@ -795,9 +795,9 @@ namespace basisu } const astc_hdr_4x4_pack_results& best_results = all_results[best_result_index]; - + astc_hdr_4x4_pack_results_to_block(dest_block, best_results); - + // Verify that this block is valid UASTC HDR and we can successfully transcode it to BC6H. // (Well, except in fastest mode.) if (m_params.m_uastc_hdr_4x4_options.m_level > 0) @@ -830,12 +830,12 @@ namespace basisu blk_desc.m_weight_ise_range = best_results.m_best_blk.m_weight_ise_range; blk_desc.m_endpoint_ise_range = best_results.m_best_blk.m_endpoint_ise_range; } - + { std::lock_guard lck(unique_block_desc_mutex); - + auto res = unique_block_descs.insert(std::make_pair(blk_desc, uastc_blk_desc_stats())); - + (res.first)->second.m_count++; #ifdef UASTC_HDR_DEBUG_SAVE_CATEGORIZED_BLOCKS (res.first)->second.m_blks.push_back(dest_block); @@ -853,7 +853,7 @@ namespace basisu } }); - + } // block_index_iter m_params.m_pJob_pool->wait_for_all(); @@ -867,7 +867,7 @@ namespace basisu m_uastc_backend_output.m_slice_image_crcs[slice_index] = basist::crc16(tex.get_ptr(), tex.get_size_in_bytes(), 0); } // slice_index - + debug_printf("basis_compressor::encode_slices_to_uastc_4x4_hdr: Total time: %3.3f secs\n", tm.get_elapsed_secs()); if (m_params.m_debug) @@ -914,11 +914,11 @@ namespace basisu debug_printf(" }\n"); } #endif - + c++; } printf("\n"); - + enc_stats.print(); } @@ -938,7 +938,7 @@ namespace basisu m_uastc_backend_output.m_slice_desc = m_slice_descs; m_uastc_backend_output.m_slice_image_data.resize(m_slice_descs.size()); m_uastc_backend_output.m_slice_image_crcs.resize(m_slice_descs.size()); - + for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++) { gpu_image& tex = m_uastc_slice_textures[slice_index]; @@ -949,7 +949,7 @@ namespace basisu const uint32_t num_blocks_y = tex.get_blocks_y(); const uint32_t total_blocks = tex.get_total_blocks(); const image& source_image = m_slice_images[slice_index]; - + std::atomic total_blocks_processed; total_blocks_processed.store(0); @@ -958,11 +958,11 @@ namespace basisu { const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(total_blocks, block_index_iter + N); - + m_params.m_pJob_pool->add_job([this, first_index, last_index, num_blocks_x, num_blocks_y, total_blocks, &source_image, &tex, &total_blocks_processed] { BASISU_NOTE_UNUSED(num_blocks_y); - + uint32_t uastc_flags = m_params.m_pack_uastc_ldr_4x4_flags; if ((m_params.m_rdo_uastc_ldr_4x4) && (m_params.m_rdo_uastc_ldr_4x4_favor_simpler_modes_in_rdo_mode)) uastc_flags |= cPackUASTCFavorSimplerModes; @@ -981,7 +981,7 @@ namespace basisu encode_uastc(&block_pixels[0][0].r, dest_block, uastc_flags); total_blocks_processed++; - + uint32_t val = total_blocks_processed; if (((val & 16383) == 16383) && m_params.m_status_output) { @@ -1005,7 +1005,7 @@ namespace basisu rdo_params.m_lz_dict_size = m_params.m_rdo_uastc_ldr_4x4_dict_size; rdo_params.m_smooth_block_max_error_scale = m_params.m_rdo_uastc_ldr_4x4_max_smooth_block_error_scale; rdo_params.m_max_smooth_block_std_dev = m_params.m_rdo_uastc_ldr_4x4_smooth_block_max_std_dev; - + bool status = uastc_rdo(tex.get_total_blocks(), (basist::uastc_block*)tex.get_ptr(), (const color_rgba *)m_source_blocks[slice_desc.m_first_block_index].m_pixels, rdo_params, m_params.m_pack_uastc_ldr_4x4_flags, m_params.m_rdo_uastc_ldr_4x4_multithreading ? m_params.m_pJob_pool : nullptr, (m_params.m_rdo_uastc_ldr_4x4_multithreading && m_params.m_pJob_pool) ? basisu::minimum(4, (uint32_t)m_params.m_pJob_pool->get_total_threads()) : 0); @@ -1017,11 +1017,11 @@ namespace basisu m_uastc_backend_output.m_slice_image_data[slice_index].resize(tex.get_size_in_bytes()); memcpy(&m_uastc_backend_output.m_slice_image_data[slice_index][0], tex.get_ptr(), tex.get_size_in_bytes()); - + m_uastc_backend_output.m_slice_image_crcs[slice_index] = basist::crc16(tex.get_ptr(), tex.get_size_in_bytes(), 0); - + } // slice_index - + return cECSuccess; } @@ -1057,8 +1057,8 @@ namespace basisu pSource_image = &mips[level - 1]; } - bool status = image_resample(*pSource_image, level_img, - //m_params.m_mip_filter.c_str(), + bool status = image_resample(*pSource_image, level_img, + //m_params.m_mip_filter.c_str(), "box", // TODO: negative lobes in the filter are causing negative colors, try Mitchell m_params.m_mip_scale, m_params.m_mip_wrapping, 0, has_alpha ? 4 : 3); if (!status) @@ -1113,12 +1113,12 @@ namespace basisu image &level_img = *enlarge_vector(mips, 1); level_img.resize(level_width, level_height); - - int result = stbir_resize_uint8_generic( + + int result = stbir_resize_uint8_generic( (const uint8_t *)img.get_ptr(), img.get_width(), img.get_height(), img.get_pitch() * sizeof(color_rgba), (uint8_t *)level_img.get_ptr(), level_img.get_width(), level_img.get_height(), level_img.get_pitch() * sizeof(color_rgba), has_alpha ? 4 : 3, has_alpha ? 3 : STBIR_ALPHA_CHANNEL_NONE, m_params.m_mip_premultiplied ? STBIR_FLAG_ALPHA_PREMULTIPLIED : 0, - m_params.m_mip_wrapping ? STBIR_EDGE_WRAP : STBIR_EDGE_CLAMP, filter, m_params.m_mip_srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, + m_params.m_mip_wrapping ? STBIR_EDGE_WRAP : STBIR_EDGE_CLAMP, filter, m_params.m_mip_srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, nullptr); if (result == 0) @@ -1126,7 +1126,7 @@ namespace basisu error_printf("basis_compressor::generate_mipmaps: stbir_resize_uint8_generic() failed!\n"); return false; } - + if (m_params.m_mip_renormalize) level_img.renormalize_normal_map(); } @@ -1250,7 +1250,7 @@ namespace basisu if (m_params.m_source_mipmap_images.size() || m_params.m_source_mipmap_images_hdr.size()) return true; - + // See if any input filenames are .DDS bool any_dds = false, all_dds = true; for (uint32_t i = 0; i < m_params.m_source_filenames.size(); i++) @@ -1319,7 +1319,7 @@ namespace basisu ldr_mips.erase_index(0U); m_params.m_source_mipmap_images.back().swap(ldr_mips); - + any_mipmaps = true; } } @@ -1339,7 +1339,7 @@ namespace basisu hdr_mips.erase_index(0U); m_params.m_source_mipmap_images_hdr.back().swap(hdr_mips); - + any_mipmaps = true; } @@ -1363,7 +1363,7 @@ namespace basisu error_printf("HDR mode enabled, but only LDR .DDS files were loaded. HDR mode requires half or float (HDR) .DDS inputs.\n"); return false; } - + return true; } @@ -1371,7 +1371,7 @@ namespace basisu { debug_printf("basis_compressor::read_source_images\n"); - const uint32_t total_source_files = m_params.m_read_source_images ? (uint32_t)m_params.m_source_filenames.size() : + const uint32_t total_source_files = m_params.m_read_source_images ? (uint32_t)m_params.m_source_filenames.size() : (m_params.m_hdr ? (uint32_t)m_params.m_source_images_hdr.size() : (uint32_t)m_params.m_source_images.size()); if (!total_source_files) @@ -1395,7 +1395,7 @@ namespace basisu basisu::vector source_images_hdr; basisu::vector source_filenames; - + // TODO: Note HDR images don't support alpha here, currently. // First load all source images, and determine if any have an alpha channel. @@ -1530,7 +1530,7 @@ namespace basisu for (uint32_t x = 0; x < file_image_hdr.get_width(); x++) { const vec4F& c = file_image_hdr(x, y); - + // For now, alpha is always 1.0f in UASTC HDR. file_image_hdr(x, y).set(c[m_params.m_swizzle[0]], c[m_params.m_swizzle[1]], c[m_params.m_swizzle[2]], 1.0f); // c[m_params.m_swizzle[3]]); } @@ -1648,7 +1648,7 @@ namespace basisu source_filenames.push_back(pSource_filename); } - // Check if the caller has generated their own mipmaps. + // Check if the caller has generated their own mipmaps. if (m_params.m_hdr) { if (m_params.m_source_mipmap_images_hdr.size()) @@ -1661,7 +1661,7 @@ namespace basisu } } } - else + else { if (m_params.m_source_mipmap_images.size()) { @@ -1702,23 +1702,23 @@ namespace basisu for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++) { const std::string &source_filename = source_filenames[source_file_index]; - + basisu::vector slices; basisu::vector slices_hdr; - + slices.reserve(32); slices_hdr.reserve(32); - + // The first (largest) mipmap level. image *pFile_image = source_images.size() ? &source_images[source_file_index] : nullptr; imagef *pFile_image_hdr = source_images_hdr.size() ? &source_images_hdr[source_file_index] : nullptr; - + // Reserve a slot for mip0. if (m_params.m_hdr) slices_hdr.resize(1); else slices.resize(1); - + if ((!m_params.m_hdr) && (m_params.m_source_mipmap_images.size())) { // User-provided mipmaps for each layer or image in the texture array. @@ -1800,10 +1800,10 @@ namespace basisu uint_vec mip_indices(m_params.m_hdr ? slices_hdr.size() : slices.size()); for (uint32_t i = 0; i < (m_params.m_hdr ? slices_hdr.size() : slices.size()); i++) mip_indices[i] = i; - + if ((!m_params.m_hdr) && (m_any_source_image_has_alpha) && (!m_params.m_uastc)) { - // For ETC1S, if source has alpha, then even mips will have RGB, and odd mips will have alpha in RGB. + // For ETC1S, if source has alpha, then even mips will have RGB, and odd mips will have alpha in RGB. basisu::vector alpha_slices; uint_vec new_mip_indices; @@ -1822,7 +1822,7 @@ namespace basisu lvl_a(x, y).set_noclamp_rgba(a, a, a, 255); } } - + lvl_rgb.set_alpha(255); alpha_slices.push_back(lvl_rgb); @@ -1844,7 +1844,7 @@ namespace basisu { assert(slices.size() == mip_indices.size()); } - + for (uint32_t slice_index = 0; slice_index < (m_params.m_hdr ? slices_hdr.size() : slices.size()); slice_index++) { image *pSlice_image = m_params.m_hdr ? nullptr : &slices[slice_index]; @@ -1903,10 +1903,10 @@ namespace basisu m_stats[dest_image_index].m_width = orig_width; m_stats[dest_image_index].m_height = orig_height; - debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", - m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), - orig_width, orig_height, - m_params.m_hdr ? pSlice_image_hdr->get_width() : pSlice_image->get_width(), + debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", + m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), + orig_width, orig_height, + m_params.m_hdr ? pSlice_image_hdr->get_width() : pSlice_image->get_width(), m_params.m_hdr ? pSlice_image_hdr->get_height() : pSlice_image->get_height()); basisu_backend_slice_desc& slice_desc = m_slice_descs[dest_image_index]; @@ -1969,7 +1969,7 @@ namespace basisu error_printf("Too many slices!\n"); return false; } - + // Basic sanity check on the slices for (uint32_t i = 1; i < m_slice_descs.size(); i++) { @@ -1979,7 +1979,7 @@ namespace basisu // Make sure images are in order int image_delta = (int)slice_desc.m_source_file_index - (int)prev_slice_desc.m_source_file_index; if (image_delta > 1) - return false; + return false; // Make sure mipmap levels are in order if (!image_delta) @@ -2002,8 +2002,8 @@ namespace basisu if (m_params.m_status_output) { printf("Slice: %u, alpha: %u, orig width/height: %ux%u, width/height: %ux%u, first_block: %u, image_index: %u, mip_level: %u, iframe: %u\n", - i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, - slice_desc.m_width, slice_desc.m_height, + i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, + slice_desc.m_width, slice_desc.m_height, slice_desc.m_first_block_index, slice_desc.m_source_file_index, slice_desc.m_mip_index, slice_desc.m_iframe); } @@ -2058,20 +2058,20 @@ namespace basisu } // Do some basic validation for 2D arrays, cubemaps, video, and volumes. - bool basis_compressor::validate_texture_type_constraints() + bool basis_compressor::validate_texture_type_constraints() { debug_printf("basis_compressor::validate_texture_type_constraints\n"); // In 2D mode anything goes (each image may have a different resolution and # of mipmap levels). if (m_params.m_tex_type == basist::cBASISTexType2D) return true; - + uint32_t total_basis_images = 0; for (uint32_t slice_index = 0; slice_index < (m_params.m_hdr ? m_slice_images_hdr.size() : m_slice_images.size()); slice_index++) { const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index]; - + total_basis_images = maximum(total_basis_images, slice_desc.m_source_file_index + 1); } @@ -2094,7 +2094,7 @@ namespace basisu const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index]; image_mipmap_levels[slice_desc.m_source_file_index] = maximum(image_mipmap_levels[slice_desc.m_source_file_index], slice_desc.m_mip_index + 1); - + if (slice_desc.m_mip_index != 0) continue; @@ -2184,7 +2184,7 @@ namespace basisu bool basis_compressor::process_frontend() { debug_printf("basis_compressor::process_frontend\n"); - + #if 0 // TODO basis_etc1_pack_params pack_params; @@ -2235,21 +2235,21 @@ namespace basisu error_printf("Too many selector clusters! (%u but max is %u)\n", selector_clusters, basisu_frontend::cMaxSelectorClusters); return false; } - + if (m_params.m_etc1s_quality_level != -1) { const float quality = saturate(m_params.m_etc1s_quality_level / 255.0f); - + const float bits_per_endpoint_cluster = 14.0f; const float max_desired_endpoint_cluster_bits_per_texel = 1.0f; // .15f int max_endpoints = static_cast((max_desired_endpoint_cluster_bits_per_texel * total_texels) / bits_per_endpoint_cluster); - + const float mid = 128.0f / 255.0f; float color_endpoint_quality = quality; const float endpoint_split_point = 0.5f; - + // In v1.2 and in previous versions, the endpoint codebook size at quality 128 was 3072. This wasn't quite large enough. const int ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE = 4800; const int MAX_ENDPOINT_CODEBOOK_SIZE = 8192; @@ -2260,7 +2260,7 @@ namespace basisu max_endpoints = clamp(max_endpoints, 256, ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE); max_endpoints = minimum(max_endpoints, m_total_blocks); - + if (max_endpoints < 64) max_endpoints = 64; endpoint_clusters = clamp((uint32_t)(.5f + lerp(32, static_cast(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters); @@ -2271,12 +2271,12 @@ namespace basisu max_endpoints = clamp(max_endpoints, 256, MAX_ENDPOINT_CODEBOOK_SIZE); max_endpoints = minimum(max_endpoints, m_total_blocks); - + if (max_endpoints < ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE) max_endpoints = ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE; endpoint_clusters = clamp((uint32_t)(.5f + lerp(ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE, static_cast(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters); } - + float bits_per_selector_cluster = 14.0f; const float max_desired_selector_cluster_bits_per_texel = 1.0f; // .15f @@ -2300,7 +2300,7 @@ namespace basisu { if (!m_params.m_endpoint_rdo_thresh.was_changed()) m_params.m_endpoint_rdo_thresh *= .25f; - + if (!m_params.m_selector_rdo_thresh.was_changed()) m_params.m_selector_rdo_thresh *= .25f; } @@ -2327,12 +2327,12 @@ namespace basisu if (!m_params.m_endpoint_rdo_thresh.was_changed()) m_params.m_endpoint_rdo_thresh *= lerp(1.0f, .75f, l); - + if (!m_params.m_selector_rdo_thresh.was_changed()) m_params.m_selector_rdo_thresh *= lerp(1.0f, .75f, l); } } - + basisu_frontend::params p; p.m_num_source_blocks = m_total_blocks; p.m_pSource_blocks = &m_source_blocks[0]; @@ -2348,7 +2348,7 @@ namespace basisu p.m_validate = m_params.m_validate_etc1s; p.m_pJob_pool = m_params.m_pJob_pool; p.m_pGlobal_codebooks = m_params.m_pGlobal_codebooks; - + // Don't keep trying to use OpenCL if it ever fails. p.m_pOpenCL_context = !m_opencl_failed ? m_pOpenCL_context : nullptr; @@ -2357,7 +2357,7 @@ namespace basisu error_printf("basisu_frontend::init() failed!\n"); return false; } - + m_frontend.compress(); if (m_frontend.get_opencl_failed()) @@ -2368,18 +2368,18 @@ namespace basisu for (uint32_t i = 0; i < m_slice_descs.size(); i++) { char filename[1024]; -#ifdef _WIN32 +#ifdef _WIN32 sprintf_s(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i); #else snprintf(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i); -#endif +#endif m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, true); #ifdef _WIN32 sprintf_s(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i); #else snprintf(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i); -#endif +#endif m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, false); } } @@ -2484,7 +2484,7 @@ namespace basisu m_output_basis_file = comp_data; uint32_t total_orig_pixels = 0; - + for (uint32_t i = 0; i < m_slice_descs.size(); i++) { const basisu_backend_slice_desc& slice_desc = m_slice_descs[i]; @@ -2500,14 +2500,14 @@ namespace basisu // HDR 6x6 TODO // HACK HACK const bool is_hdr_6x6 = m_params.m_hdr && (m_params.m_hdr_mode != hdr_modes::cUASTC_HDR_4X4); - + if (m_params.m_validate_output_data) { interval_timer tm; tm.start(); basist::basisu_transcoder_init(); - + debug_printf("basist::basisu_transcoder_init: Took %f ms\n", tm.get_elapsed_ms()); // Verify the compressed data by transcoding it to ASTC (or ETC1)/BC7 and validating the CRC's. @@ -2715,7 +2715,7 @@ namespace basisu } } // if (m_params.m_validate_output_data) - + return true; } @@ -2756,7 +2756,7 @@ namespace basisu { const std::string filename(string_format("%s_compressive_tonemapped.png", pBasename)); image compressive_tonemapped_img; - + bool status = tonemap_image_compressive(compressive_tonemapped_img, hdr_img); if (!status) { @@ -2824,7 +2824,7 @@ namespace basisu uint32_t total_texels = 0; for (uint32_t i = 0; i < m_slice_descs.size(); i++) total_texels += (m_slice_descs[i].m_orig_width * m_slice_descs[i].m_orig_height); - + m_basis_bits_per_texel = ((float)comp_size * 8.0f) / total_texels; fmt_debug_printf("Output file size: {}, {3.2} bits/texel, LZ compressed file size: {}, {3.2} bits/texel\n", @@ -2833,7 +2833,7 @@ namespace basisu } m_stats.resize(m_slice_descs.size()); - + if (m_params.m_validate_output_data) { if (m_params.m_hdr) @@ -2906,7 +2906,7 @@ namespace basisu im.calc(m_slice_images_hdr[slice_index], m_decoded_output_textures_astc_hdr_unpacked[slice_index], 0, 3, true, true); s.m_basis_rgb_avg_log2_psnr = (float)im.m_psnr; - + if (m_params.m_print_stats) { printf("\nASTC Log2 RGB: "); @@ -2924,7 +2924,7 @@ namespace basisu printf("\n"); } } - + if (m_params.m_debug_images) { std::string out_basename; @@ -2940,7 +2940,7 @@ namespace basisu { gpu_image bc6h_tex(m_decoded_output_textures[slice_index]); bc6h_tex.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height); - + std::string filename(out_basename + "_bc6h.dds"); write_compressed_texture_file(filename.c_str(), bc6h_tex, true); printf("Wrote .DDS file %s\n", filename.c_str()); @@ -2950,9 +2950,9 @@ namespace basisu { gpu_image astc_tex(m_decoded_output_textures_astc_hdr[slice_index]); astc_tex.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height); - + std::string filename1(out_basename + "_astc.astc"); - + uint32_t block_width = 4, block_height = 4; if ((m_params.m_hdr_mode == hdr_modes::cASTC_HDR_6X6) || (m_params.m_hdr_mode == hdr_modes::cASTC_HDR_6X6_INTERMEDIATE)) { @@ -2972,7 +2972,7 @@ namespace basisu { imagef astc_img(m_decoded_output_textures_astc_hdr_unpacked[slice_index]); astc_img.resize(slice_desc.m_orig_width, slice_desc.m_orig_height); - + std::string filename(out_basename + "_unpacked_astc.exr"); write_exr(filename.c_str(), astc_img, 3, 0); printf("Wrote .EXR file %s\n", filename.c_str()); @@ -3007,7 +3007,7 @@ namespace basisu printf("Slice: %u\n", slice_index); image_stats& s = m_stats[slice_index]; - + image_metrics em; // ---- .basis stats @@ -3183,10 +3183,10 @@ namespace basisu } // if (m_params.m_hdr) } // if (m_params.m_validate_output_data) - + return true; } - + // Make sure all the mip 0's have the same dimensions and number of mipmap levels, or we can't encode the KTX2 file. bool basis_compressor::validate_ktx2_constraints() { @@ -3232,7 +3232,7 @@ namespace basisu // LDR ETC1S texture data in a custom format, with global codebooks static uint8_t g_ktx2_etc1s_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x28,0x0,0xA3,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3F,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF }; static uint8_t g_ktx2_etc1s_alpha_dfd[60] = { 0x3C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x38,0x0,0xA3,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3F,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x40,0x0,0x3F,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF }; - + // colorModel=KTX2_KDF_DF_MODEL_UASTC_LDR_4X4 (0xA6) // LDR UASTC 4x4 texture data in a custom block format static uint8_t g_ktx2_uastc_ldr_4x4_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x28,0x0,0xA6,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7F,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF }; @@ -3240,7 +3240,7 @@ namespace basisu // colorModel=KTX2_KDF_DF_MODEL_UASTC_HDR_4X4 (0xA7) // Standard ASTC HDR 4x4 texture data but constrained for easy transcoding to BC6H, either highest quality or RDO optimized. - static uint8_t g_ktx2_uastc_hdr_4x4_nonalpha_dfd[44] = + static uint8_t g_ktx2_uastc_hdr_4x4_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0, // 0 totalSize 0x0,0x0,0x0,0x0, // 1 descriptorType/vendorId @@ -3288,7 +3288,7 @@ namespace basisu 0x0,0x0,0x0,0x0, // 9 sampleLower (0.0) 0x00, 0x00, 0x80, 0x3F // 10 sampleHigher (1.0) }; - + bool basis_compressor::get_dfd(uint8_vec &dfd, const basist::ktx2_header &header) { const uint8_t* pDFD; @@ -3353,7 +3353,7 @@ namespace basisu dfd_len = sizeof(g_ktx2_etc1s_nonalpha_dfd); } } - + assert(dfd_len >= 44); dfd.resize(dfd_len); @@ -3367,7 +3367,7 @@ namespace basisu dfd_bits &= ~(0xFF << 8); dfd_bits |= (basist::KTX2_DF_PRIMARIES_BT2020 << 8); } - + // Transfer function dfd_bits &= ~(0xFF << 16); @@ -3401,7 +3401,7 @@ namespace basisu if (m_params.m_uastc) { dfd_chan0 &= ~(0xF << 24); - + // TODO: Allow the caller to override this if (m_any_source_image_has_alpha) dfd_chan0 |= (basist::KTX2_DF_CHANNEL_UASTC_RGBA << 24); @@ -3692,7 +3692,7 @@ namespace basisu // Key values basist::ktx2_transcoder::key_value_vec key_values(m_params.m_ktx2_key_values); - + basist::ktx2_add_key_value(key_values, "KTXwriter", fmt_string("Basis Universal {}", BASISU_LIB_VERSION_STRING)); if (m_params.m_hdr) @@ -3764,7 +3764,7 @@ namespace basisu #if BASISU_DISABLE_KTX2_ALIGNMENT_WORKAROUND break; #endif - + // Hack to ensure the KVD block ends on a 16 byte boundary, because we have no other official way of aligning the data. uint32_t kvd_end_file_offset = kvd_file_offset + (uint32_t)key_value_data.size(); uint32_t bytes_needed_to_pad = (16 - (kvd_end_file_offset & 15)) & 15; @@ -3786,13 +3786,13 @@ namespace basisu // Just add the padding. It's likely not necessary anymore, but can't really hurt. //printf("WARNING: Due to a KTX2 validator bug related to mipPadding, we must insert a dummy key into the KTX2 file of %u bytes\n", bytes_needed_to_pad); - - // We're not good - need to add a dummy key large enough to force file alignment so the mip level array gets aligned. + + // We're not good - need to add a dummy key large enough to force file alignment so the mip level array gets aligned. // We can't just add some bytes before the mip level array because ktx2check will see that as extra data in the file that shouldn't be there in ktxValidator::validateDataSize(). key_values.enlarge(1); for (uint32_t i = 0; i < (bytes_needed_to_pad - 4 - 1 - 1); i++) key_values.back().m_key.push_back(127); - + key_values.back().m_key.push_back(0); key_values.back().m_value.push_back(0); @@ -3800,13 +3800,13 @@ namespace basisu key_values.sort(); key_value_data.resize(0); - + // Try again } basisu::vector level_index_array(total_levels); memset(level_index_array.data(), 0, level_index_array.size_in_bytes()); - + m_output_ktx2_file.clear(); m_output_ktx2_file.reserve(m_output_basis_file.size()); @@ -3815,7 +3815,7 @@ namespace basisu // Level index array append_vector(m_output_ktx2_file, (const uint8_t*)level_index_array.data(), level_index_array.size_in_bytes()); - + // DFD const uint8_t* pDFD = dfd.data(); uint32_t dfd_len = (uint32_t)dfd.size(); @@ -3869,7 +3869,7 @@ namespace basisu for (int level = total_levels - 1; level >= 0; level--) { level_index_array[level].m_byte_length = compressed_level_data_bytes[level].size(); - + //if (m_params.m_uastc) if (can_use_zstd) { @@ -3879,7 +3879,7 @@ namespace basisu level_index_array[level].m_byte_offset = m_output_ktx2_file.size(); append_vector(m_output_ktx2_file, compressed_level_data_bytes[level]); } - + // Write final header memcpy(m_output_ktx2_file.data(), &header, sizeof(header)); @@ -3921,7 +3921,7 @@ namespace basisu std::atomic result; result.store(true); - + std::atomic opencl_failed; opencl_failed.store(false); @@ -3936,19 +3936,19 @@ namespace basisu tm.start(); basis_compressor c; - + // Dummy job pool job_pool task_jpool(1); params.m_pJob_pool = &task_jpool; // TODO: Remove this flag entirely - params.m_multithreading = true; - + params.m_multithreading = true; + // Stop using OpenCL if a failure ever occurs. if (opencl_failed) params.m_use_opencl = false; bool status = c.init(params); - + if (c.get_opencl_failed()) opencl_failed.store(true); @@ -3977,7 +3977,7 @@ namespace basisu else { results.m_error_code = basis_compressor::cECFailedInitializing; - + result = false; } @@ -4004,7 +4004,7 @@ namespace basisu { assert((pSource_images != nullptr) || (pSource_images_hdr != nullptr)); assert(!((pSource_images != nullptr) && (pSource_images_hdr != nullptr))); - + // Check input parameters if (pSource_images) { @@ -4043,7 +4043,7 @@ namespace basisu comp_params.m_y_flip = (flags_and_quality & cFlagYFlip) != 0; comp_params.m_debug = (flags_and_quality & cFlagDebug) != 0; comp_params.m_debug_images = (flags_and_quality & cFlagDebugImages) != 0; - + // Copy the largest mipmap level if (pSource_images) { @@ -4075,7 +4075,7 @@ namespace basisu comp_params.m_source_mipmap_images_hdr[0][i - 1] = (*pSource_images_hdr)[i]; } } - + comp_params.m_multithreading = (flags_and_quality & cFlagThreaded) != 0; comp_params.m_use_opencl = (flags_and_quality & cFlagUseOpenCL) != 0; @@ -4096,9 +4096,9 @@ namespace basisu { comp_params.m_etc1s_quality_level = basisu::maximum(1, flags_and_quality & 255); } - + comp_params.m_create_ktx2_file = (flags_and_quality & cFlagKTX2) != 0; - + if (comp_params.m_create_ktx2_file) { // Set KTX2 specific parameters. @@ -4239,7 +4239,7 @@ namespace basisu const uint32_t W = 1024, H = 1024; basisu::vector images; image& img = images.enlarge(1)->resize(W, H); - + const uint32_t NUM_RAND_LETTERS = 6000;// 40000; rand r; @@ -4281,7 +4281,7 @@ namespace basisu error_printf("basis_benchmark_etc1s_opencl: basis_compress() failed (CPU)!\n"); return false; } - + best_cpu_time = minimum(best_cpu_time, cpu_time); basis_free_data(pComp_data); @@ -4324,11 +4324,8 @@ namespace basisu } printf("Best GPU time: %3.3f\n", best_gpu_time); - + return best_gpu_time < best_cpu_time; } } // namespace basisu - - - diff --git a/encoder/basisu_comp.h b/encoder/basisu_comp.h index ffa1fdf2..106d83bd 100644 --- a/encoder/basisu_comp.h +++ b/encoder/basisu_comp.h @@ -43,10 +43,10 @@ namespace basisu const uint32_t BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION = 16384; // Allow block's color distance to increase by 1.5 while searching for an alternative nearby endpoint. - const float BASISU_DEFAULT_ENDPOINT_RDO_THRESH = 1.5f; - + const float BASISU_DEFAULT_ENDPOINT_RDO_THRESH = 1.5f; + // Allow block's color distance to increase by 1.25 while searching the selector history buffer for a close enough match. - const float BASISU_DEFAULT_SELECTOR_RDO_THRESH = 1.25f; + const float BASISU_DEFAULT_SELECTOR_RDO_THRESH = 1.25f; const int BASISU_DEFAULT_QUALITY = 128; const float BASISU_DEFAULT_HYBRID_SEL_CB_QUALITY_THRESH = 2.0f; @@ -75,7 +75,7 @@ namespace basisu m_filename.clear(); m_width = 0; m_height = 0; - + m_basis_rgb_avg_psnr = 0.0f; m_basis_rgb_avg_log2_psnr = 0.0f; @@ -94,7 +94,7 @@ namespace basisu m_bc7_luma_709_psnr = 0.0f; m_bc7_luma_601_psnr = 0.0f; m_bc7_luma_709_ssim = 0.0f; - + m_best_etc1s_rgb_avg_psnr = 0.0f; m_best_etc1s_luma_709_psnr = 0.0f; m_best_etc1s_luma_601_psnr = 0.0f; @@ -128,7 +128,7 @@ namespace basisu float m_bc7_luma_709_psnr; float m_bc7_luma_601_psnr; float m_bc7_luma_709_ssim; - + // LDR: Highest achievable quality ETC1S statistics float m_best_etc1s_rgb_avg_psnr; float m_best_etc1s_luma_709_psnr; @@ -141,7 +141,7 @@ namespace basisu enum class hdr_modes { // standard but constrained ASTC HDR 4x4 tex data that can be rapidly transcoded to BC6H - cUASTC_HDR_4X4, + cUASTC_HDR_4X4, // standard RDO optimized or non-RDO (highest quality) ASTC HDR 6x6 tex data that can be rapidly re-encoded to BC6H cASTC_HDR_6X6, // a custom intermediate format based off ASTC HDR that can be rapidly decoded straight to ASTC HDR or re-encoded to BC6H @@ -301,7 +301,7 @@ namespace basisu m_no_endpoint_rdo.clear(); m_endpoint_rdo_thresh.clear(); - + m_mip_gen.clear(); m_mip_scale.clear(); m_mip_filter = "kaiser"; @@ -349,13 +349,13 @@ namespace basisu m_ldr_hdr_upconversion_srgb_to_linear.clear(); m_hdr_favor_astc.clear(); - + m_uastc_hdr_4x4_options.init(); m_astc_hdr_6x6_options.clear(); m_ldr_hdr_upconversion_nit_multiplier.clear(); m_ldr_hdr_upconversion_black_bias.clear(); - + m_pJob_pool = nullptr; } @@ -405,10 +405,10 @@ namespace basisu } } - // By default we generate LDR ETC1S data. + // By default we generate LDR ETC1S data. // if m_uastc is true but m_hdr is not true, we generate UASTC 4x4 LDR data (8bpp with or without RDO). // if m_uastc is true and m_hdr is true, we generate 4x4 or 6x6 HDR data (either standard ASTC, constrained ASTC, RDO ASTC, or intermediate), controlled by m_hdr_mode. - + // True to generate UASTC .basis/.KTX2 file data, otherwise ETC1S. // Should be true for any non-ETC1S format (UASTC 4x4 LDR, UASTC 4x4 HDR, RDO ASTC 6x6 HDR, and ASTC 6x6 HDR intermediate). bool_param m_uastc; @@ -419,25 +419,25 @@ namespace basisu // If m_hdr is true, this specifies which mode we operate in (currently UASTC 4x4 HDR or ASTC 6x6 HDR). Defaults to UASTC 4x4 HDR for backwards compatibility. hdr_modes m_hdr_mode; - + bool_param m_use_opencl; - // If m_read_source_images is true, m_source_filenames (and optionally m_source_alpha_filenames) contains the filenames of PNG etc. images to read. + // If m_read_source_images is true, m_source_filenames (and optionally m_source_alpha_filenames) contains the filenames of PNG etc. images to read. // Otherwise, the compressor processes the images in m_source_images or m_source_images_hdr. basisu::vector m_source_filenames; basisu::vector m_source_alpha_filenames; - + basisu::vector m_source_images; - + basisu::vector m_source_images_hdr; - + // Stores mipmaps starting from level 1. Level 0 is still stored in m_source_images, as usual. // If m_source_mipmaps isn't empty, automatic mipmap generation isn't done. m_source_mipmaps.size() MUST equal m_source_images.size() or the compressor returns an error. // The compressor applies the user-provided swizzling (in m_swizzle) to these images. basisu::vector< basisu::vector > m_source_mipmap_images; basisu::vector< basisu::vector > m_source_mipmap_images_hdr; - + // Filename of the output basis/ktx2 file std::string m_out_filename; @@ -448,19 +448,19 @@ namespace basisu // If true, the compressor will print basis status to stdout during compression. bool_param m_status_output; - + // Output debug information during compression bool_param m_debug; bool_param m_validate_etc1s; - + // m_debug_images is pretty slow bool_param m_debug_images; - // ETC1S compression level, from 0 to BASISU_MAX_COMPRESSION_LEVEL (higher is slower). + // ETC1S compression level, from 0 to BASISU_MAX_COMPRESSION_LEVEL (higher is slower). // This parameter controls numerous internal encoding speed vs. compression efficiency/performance tradeoffs. // Note this is NOT the same as the ETC1S quality level, and most users shouldn't change this. param m_compression_level; - + // Use perceptual sRGB colorspace metrics instead of linear bool_param m_perceptual; @@ -476,20 +476,20 @@ namespace basisu // Write the output basis/ktx2 file to disk using m_out_filename bool_param m_write_output_basis_or_ktx2_files; - - // Compute and display image metrics + + // Compute and display image metrics bool_param m_compute_stats; // Print stats to stdout, if m_compute_stats is true. bool_param m_print_stats; - + // Check to see if any input image has an alpha channel, if so then the output basis/ktx2 file will have alpha channels bool_param m_check_for_alpha; - + // Always put alpha slices in the output basis/ktx2 file, even when the input doesn't have alpha - bool_param m_force_alpha; + bool_param m_force_alpha; bool_param m_multithreading; - + // Split the R channel to RGB and the G channel to alpha, then write a basis/ktx2 file with alpha channels uint8_t m_swizzle[4]; @@ -498,25 +498,25 @@ namespace basisu // If true the front end will not use 2 level endpoint codebook searching, for slightly higher quality but much slower execution. // Note some m_compression_level's disable this automatically. bool_param m_disable_hierarchical_endpoint_codebooks; - + // mipmap generation parameters bool_param m_mip_gen; param m_mip_scale; std::string m_mip_filter; bool_param m_mip_srgb; bool_param m_mip_premultiplied; // not currently supported - bool_param m_mip_renormalize; + bool_param m_mip_renormalize; bool_param m_mip_wrapping; bool_param m_mip_fast; param m_mip_smallest_dimension; - - // ETC1S codebook size (quality) control. + + // ETC1S codebook size (quality) control. // If m_etc1s_quality_level != -1, it controls the quality level. It ranges from [1,255] or [BASISU_QUALITY_MIN, BASISU_QUALITY_MAX]. // Otherwise m_max_endpoint_clusters/m_max_selector_clusters controls the codebook sizes directly. uint32_t m_etc1s_max_endpoint_clusters; uint32_t m_etc1s_max_selector_clusters; int m_etc1s_quality_level; - + // m_tex_type, m_userdata0, m_userdata1, m_framerate - These fields go directly into the .basis file header. basist::basis_texture_type m_tex_type; uint32_t m_userdata0; @@ -556,11 +556,11 @@ namespace basisu bool_param m_validate_output_data; // LDR->HDR upconversion parameters. - // - // If true, LDR images (such as PNG) will be converted to normalized [0,1] linear light (via a sRGB->Linear conversion), or absolute luminance (nits or candelas per meter squared), and then processed as HDR. + // + // If true, LDR images (such as PNG) will be converted to normalized [0,1] linear light (via a sRGB->Linear conversion), or absolute luminance (nits or candelas per meter squared), and then processed as HDR. // Otherwise, LDR images are assumed to already be in linear light (i.e. they don't use the sRGB transfer function). bool_param m_ldr_hdr_upconversion_srgb_to_linear; - + // m_ldr_hdr_upconversion_nit_multiplier is only used when loading SDR/LDR images and compressing to an HDR output format. // By default m_ldr_hdr_upconversion_nit_multiplier is 0. It's an override for the default. // When loading LDR images, a default multiplier of 1.0 will be used in UASTC 4x4 HDR mode. Partially for backwards compatibility with previous library releases, and also because it doesn't really matter with this encoder what the multiplier is. @@ -573,7 +573,7 @@ namespace basisu // If true, ASTC HDR quality is favored more than BC6H quality. Otherwise it's a rough balance. bool_param m_hdr_favor_astc; - + job_pool *m_pJob_pool; }; @@ -588,7 +588,7 @@ namespace basisu // Note it *should* be possible to call init() multiple times with different inputs, but this scenario isn't well tested. Ideally, create 1 object, compress, then delete it. bool init(const basis_compressor_params ¶ms); - + enum error_code { cECSuccess = 0, @@ -609,7 +609,7 @@ namespace basisu // The output .basis file will always be valid of process() succeeded. const uint8_vec &get_output_basis_file() const { return m_output_basis_file; } - + // The output .ktx2 file will only be valid if m_create_ktx2_file was true and process() succeeded. const uint8_vec& get_output_ktx2_file() const { return m_output_ktx2_file; } @@ -617,18 +617,18 @@ namespace basisu uint32_t get_basis_file_size() const { return m_basis_file_size; } double get_basis_bits_per_texel() const { return m_basis_bits_per_texel; } - + bool get_any_source_image_has_alpha() const { return m_any_source_image_has_alpha; } bool get_opencl_failed() const { return m_opencl_failed; } - + private: basis_compressor_params m_params; - + opencl_context_ptr m_pOpenCL_context; basist::basis_tex_format m_fmt_mode; - + basisu::vector m_slice_images; basisu::vector m_slice_images_hdr; @@ -636,11 +636,11 @@ namespace basisu uint32_t m_basis_file_size; double m_basis_bits_per_texel; - + basisu_backend_slice_desc_vec m_slice_descs; uint32_t m_total_blocks; - + basisu_frontend m_frontend; // These are 4x4 blocks. @@ -658,7 +658,7 @@ namespace basisu basisu::vector m_decoded_output_textures; // BC6H in HDR mode basisu::vector m_decoded_output_textures_unpacked; - + basisu::vector m_decoded_output_textures_bc7; basisu::vector m_decoded_output_textures_unpacked_bc7; @@ -669,16 +669,16 @@ namespace basisu uint8_vec m_output_basis_file; uint8_vec m_output_ktx2_file; - + basisu::vector m_uastc_slice_textures; basisu_backend_output m_uastc_backend_output; // The amount the HDR input has to be scaled up in case it had to be rescaled to fit into half floats. - float m_hdr_image_scale; - + float m_hdr_image_scale; + // The upconversion multiplier used to load LDR images in HDR mode. float m_ldr_to_hdr_upconversion_nit_multiplier; - + // True if any loaded source images were LDR and upconverted to HDR. bool m_upconverted_any_ldr_images; @@ -741,8 +741,8 @@ namespace basisu return 4; } }; - - // Alternative simple C-style wrapper API around the basis_compressor class. + + // Alternative simple C-style wrapper API around the basis_compressor class. // This doesn't expose every encoder feature, but it's enough to get going. // Important: basisu_encoder_init() MUST be called first before calling these functions. // @@ -751,16 +751,16 @@ namespace basisu // OR // pImageRGBA: pointer to a 32-bpp RGBx or RGBA raster image, R first in memory, A last. Top scanline first in memory. // width/height/pitch_in_pixels: dimensions of pImageRGBA - // + // // flags_and_quality: Combination of the above flags logically OR'd with the ETC1S or UASTC level, i.e. "cFlagSRGB | cFlagGenMipsClamp | cFlagThreaded | 128" or "cFlagSRGB | cFlagGenMipsClamp | cFlagUASTC | cFlagThreaded | cPackUASTCLevelDefault". // In ETC1S mode, the lower 8-bits are the ETC1S quality level which ranges from [1,255] (higher=better quality/larger files) // In UASTC mode, the lower 8-bits are the UASTC LDR/HDR pack level (see cPackUASTCLevelFastest, etc.). Fastest/lowest quality is 0, so be sure to set it correctly. Valid values are [0,4] for both LDR/HDR. // In UASTC mode, be sure to set this, otherwise it defaults to 0 (fastest/lowest quality). - // + // // uastc_rdo_quality: Float UASTC RDO quality level (0=no change, higher values lower quality but increase compressibility, initially try .5-1.5) - // + // // pSize: Returns the output data's compressed size in bytes - // + // // Return value is the compressed .basis or .ktx2 file data, or nullptr on failure. Must call basis_free() to free it. enum { @@ -774,22 +774,22 @@ namespace basisu cFlagSRGB = 1 << 13, // input texture is sRGB, use perceptual colorspace metrics, also use sRGB filtering during mipmap gen, and also sets KTX2 output transfer func to sRGB cFlagGenMipsClamp = 1 << 14, // generate mipmaps with clamp addressing cFlagGenMipsWrap = 1 << 15, // generate mipmaps with wrap addressing - + cFlagYFlip = 1 << 16, // flip source image on Y axis before compression - + cFlagUASTCRDO = 1 << 17, // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar) - + cFlagPrintStats = 1 << 18, // print image stats to stdout cFlagPrintStatus = 1 << 19, // print status to stdout - + cFlagDebugImages = 1 << 20, // enable status output cFlagREC2020 = 1 << 21 // ASTC 6x6 modes: treat input as REC 2020 vs. the default 709 }; - // This function accepts an array of source images. + // This function accepts an array of source images. // If more than one image is provided, it's assumed the images form a mipmap pyramid and automatic mipmap generation is disabled. - // Returns a pointer to the compressed .basis or .ktx2 file data. *pSize is the size of the compressed data. + // Returns a pointer to the compressed .basis or .ktx2 file data. *pSize is the size of the compressed data. // Important: The returned block MUST be manually freed using basis_free_data(). // basisu_encoder_init() MUST be called first! // LDR version. To compress the LDR source image as HDR: Use the cFlagHDR flag. @@ -839,7 +839,7 @@ namespace basisu double m_basis_bits_per_texel; bool m_any_source_image_has_alpha; - parallel_results() + parallel_results() { clear(); } @@ -855,7 +855,7 @@ namespace basisu m_any_source_image_has_alpha = false; } }; - + // Compresses an array of input textures across total_threads threads using the basis_compressor class. // Compressing multiple textures at a time is substantially more efficient than just compressing one at a time. // total_threads must be >= 1. @@ -863,6 +863,5 @@ namespace basisu uint32_t total_threads, const basisu::vector ¶ms_vec, basisu::vector< parallel_results > &results_vec); - -} // namespace basisu +} // namespace basisu diff --git a/encoder/basisu_enc.cpp b/encoder/basisu_enc.cpp index 68b57ab6..97deed9e 100644 --- a/encoder/basisu_enc.cpp +++ b/encoder/basisu_enc.cpp @@ -81,7 +81,7 @@ namespace basisu // This is a Public Domain 8x8 font from here: // https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h - const uint8_t g_debug_font8x8_basic[127 - 32 + 1][8] = + const uint8_t g_debug_font8x8_basic[127 - 32 + 1][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 ( ) { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) @@ -183,7 +183,7 @@ namespace basisu bool g_library_initialized; std::mutex g_encoder_init_mutex; - + // Encoder library initialization (just call once at startup) bool basisu_encoder_init(bool use_opencl, bool opencl_force_serialization) { @@ -193,7 +193,7 @@ namespace basisu return true; detect_sse41(); - + basist::basisu_transcoder_init(); pack_etc1_solid_color_init(); //uastc_init(); @@ -241,7 +241,7 @@ namespace basisu if (total_chars >= (int)BUF_SIZE) { basisu::vector var_buf(total_chars + 1); - + va_copy(args_copy, args); int total_chars_retry = vsnprintf(var_buf.data(), var_buf.size(), pFmt, args_copy); va_end(args_copy); @@ -316,7 +316,7 @@ namespace basisu #else #error TODO #endif - + interval_timer::interval_timer() : m_start_time(0), m_stop_time(0), m_started(false), m_stopped(false) { if (!g_timer_freq) @@ -350,7 +350,7 @@ namespace basisu timer_ticks delta = stop_time - m_start_time; return delta * g_timer_freq; } - + void interval_timer::init() { if (!g_timer_freq) @@ -377,7 +377,7 @@ namespace basisu return ticks * g_timer_freq; } - // Note this is linear<->sRGB, NOT REC709 which uses slightly different equations/transfer functions. + // Note this is linear<->sRGB, NOT REC709 which uses slightly different equations/transfer functions. // However the gamuts/white points of REC709 and sRGB are the same. float linear_to_srgb(float l) { @@ -387,7 +387,7 @@ namespace basisu else return saturate(1.055f * powf(l, 1.0f / 2.4f) - .055f); } - + float srgb_to_linear(float s) { assert(s >= 0.0f && s <= 1.0f); @@ -396,21 +396,21 @@ namespace basisu else return saturate(powf((s + .055f) * (1.0f / 1.055f), 2.4f)); } - + const uint32_t MAX_32BIT_ALLOC_SIZE = 250000000; - + bool load_tga(const char* pFilename, image& img) { int w = 0, h = 0, n_chans = 0; uint8_t* pImage_data = read_tga(pFilename, w, h, n_chans); - + if ((!pImage_data) || (!w) || (!h) || ((n_chans != 3) && (n_chans != 4))) { error_printf("Failed loading .TGA image \"%s\"!\n", pFilename); if (pImage_data) free(pImage_data); - + return false; } @@ -426,7 +426,7 @@ namespace basisu return false; } } - + img.resize(w, h); const uint8_t *pSrc = pImage_data; @@ -469,7 +469,7 @@ namespace basisu { interval_timer tm; tm.start(); - + if (!buf_size) return false; @@ -488,7 +488,7 @@ namespace basisu return true; } - + bool load_png(const char* pFilename, image& img) { uint8_vec buffer; @@ -507,9 +507,9 @@ namespace basisu uint8_t *pImage_data = jpgd::decompress_jpeg_image_from_file(pFilename, &width, &height, &actual_comps, 4, jpgd::jpeg_decoder::cFlagLinearChromaFiltering); if (!pImage_data) return false; - + img.init(pImage_data, width, height, 4); - + free(pImage_data); return true; @@ -642,7 +642,7 @@ namespace basisu dst[2] = basist::half_to_float(pSrc_pixel[2]); dst[3] = basist::half_to_float(pSrc_pixel[3]); } - + pSrc_image_h += (width * 4); } @@ -722,7 +722,7 @@ namespace basisu return ((strcasecmp(pExt, "hdr") == 0) || (strcasecmp(pExt, "exr") == 0)); } - + // TODO: move parameters to struct, add a HDR clean flag to eliminate NaN's/Inf's bool load_image_hdr(const char* pFilename, imagef& img, bool ldr_srgb_to_linear, float linear_nit_multiplier, float ldr_black_bias) { @@ -740,7 +740,7 @@ namespace basisu return false; return true; } - + if (strcasecmp(pExt, "exr") == 0) { int n_chans = 0; @@ -760,12 +760,12 @@ namespace basisu return true; } - + bool save_png(const char* pFilename, const image &img, uint32_t image_save_flags, uint32_t grayscale_comp) { if (!img.get_total_pixels()) return false; - + void* pPNG_data = nullptr; size_t PNG_data_size = 0; @@ -783,7 +783,7 @@ namespace basisu else { bool has_alpha = false; - + if ((image_save_flags & cImageSaveIgnoreAlpha) == 0) has_alpha = img.has_alpha(); @@ -800,7 +800,7 @@ namespace basisu pDst[0] = pSrc->r; pDst[1] = pSrc->g; pDst[2] = pSrc->b; - + pSrc++; pDst += 3; } @@ -824,10 +824,10 @@ namespace basisu } free(pPNG_data); - + return status; } - + bool read_file_to_vec(const char* pFilename, uint8_vec& data) { FILE* pFile = nullptr; @@ -838,7 +838,7 @@ namespace basisu #endif if (!pFile) return false; - + fseek(pFile, 0, SEEK_END); #ifdef _WIN32 int64_t filesize = _ftelli64(pFile); @@ -909,7 +909,7 @@ namespace basisu return false; } fseek(pFile, 0, SEEK_SET); - + if (fread(pData, 1, (size_t)len, pFile) != (size_t)len) { fclose(pFile); @@ -942,19 +942,19 @@ namespace basisu return fclose(pFile) != EOF; } - + bool image_resample(const image &src, image &dst, bool srgb, - const char *pFilter, float filter_scale, + const char *pFilter, float filter_scale, bool wrapping, uint32_t first_comp, uint32_t num_comps) { assert((first_comp + num_comps) <= 4); const int cMaxComps = 4; - + const uint32_t src_w = src.get_width(), src_h = src.get_height(); const uint32_t dst_w = dst.get_width(), dst_h = dst.get_height(); - + if (maximum(src_w, src_h) > BASISU_RESAMPLER_MAX_DIMENSION) { printf("Image is too large!\n"); @@ -963,10 +963,10 @@ namespace basisu if (!src_w || !src_h || !dst_w || !dst_h) return false; - + if ((num_comps < 1) || (num_comps > cMaxComps)) return false; - + if ((minimum(dst_w, dst_h) < 1) || (maximum(dst_w, dst_h) > BASISU_RESAMPLER_MAX_DIMENSION)) { printf("Image is too large!\n"); @@ -997,7 +997,7 @@ namespace basisu std::vector samples[cMaxComps]; Resampler *resamplers[cMaxComps]; - + resamplers[0] = new Resampler(src_w, src_h, dst_w, dst_h, wrapping ? Resampler::BOUNDARY_WRAP : Resampler::BOUNDARY_CLAMP, 0.0f, 1.0f, pFilter, nullptr, nullptr, filter_scale, filter_scale, 0, 0); @@ -1057,7 +1057,7 @@ namespace basisu break; const bool linear_flag = !srgb || (comp_index == 3); - + color_rgba *pDst = &dst(0, dst_y); for (uint32_t x = 0; x < dst_w; x++) @@ -1090,7 +1090,7 @@ namespace basisu return true; } - bool image_resample(const imagef& src, imagef& dst, + bool image_resample(const imagef& src, imagef& dst, const char* pFilter, float filter_scale, bool wrapping, uint32_t first_comp, uint32_t num_comps) @@ -1183,7 +1183,7 @@ namespace basisu const float* pOutput_samples = resamplers[c]->get_line(); if (!pOutput_samples) break; - + vec4F* pDst = &dst(0, dst_y); for (uint32_t x = 0; x < dst_w; x++) @@ -1216,9 +1216,9 @@ namespace basisu A[0].m_key = 1; return; } - + A[0].m_key += A[1].m_key; - + int s = 2, r = 0, next; for (next = 1; next < (num_syms - 1); ++next) { @@ -1310,7 +1310,7 @@ namespace basisu for (i = 0; i < num_syms; i++) { uint32_t freq = pSyms0[i].m_key; - + // We scale all input frequencies to 16-bits. assert(freq <= UINT16_MAX); @@ -1501,7 +1501,7 @@ namespace basisu uint32_t total_used = tab.get_total_used_codes(); put_bits(total_used, cHuffmanMaxSymsLog2); - + if (!total_used) return 0; @@ -1565,7 +1565,7 @@ namespace basisu const uint32_t l = syms[i] & 63, e = syms[i] >> 6; put_code(l, ct); - + if (l == cHuffmanSmallZeroRunCode) put_bits(e, cHuffmanSmallZeroRunExtraBits); else if (l == cHuffmanBigZeroRunCode) @@ -1592,7 +1592,7 @@ namespace basisu huffman_encoding_table etab; etab.init(h, 16); - + { bitwise_coder c; c.init(1024); @@ -1727,9 +1727,9 @@ namespace basisu // We now have chosen an entry to place in the picked list, now determine which side it goes on. const uint32_t entry_to_move = m_entries_to_do[best_entry]; - + float side = pick_side(num_syms, entry_to_move, pDist_func, pCtx, dist_func_weight); - + // Put entry_to_move either on the "left" or "right" side of the picked entries if (side <= 0) m_entries_picked.push_back(entry_to_move); @@ -1832,7 +1832,7 @@ namespace basisu } return which_side; } - + void image_metrics::calc(const imagef& a, const imagef& b, uint32_t first_chan, uint32_t total_chans, bool avg_comp_error, bool log) { assert((first_chan < 4U) && (first_chan + total_chans <= 4U)); @@ -1846,13 +1846,13 @@ namespace basisu m_has_neg = false; m_any_abnormal = false; m_hf_mag_overflow = false; - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) { const vec4F& ca = a(x, y), &cb = b(x, y); - + if (total_chans) { for (uint32_t c = 0; c < total_chans; c++) @@ -1867,7 +1867,7 @@ namespace basisu if (std::isinf(fa) || std::isinf(fb) || std::isnan(fa) || std::isnan(fb)) m_any_abnormal = true; - + const double delta = fabs(fa - fb); max_e = basisu::maximum(max_e, delta); @@ -1902,10 +1902,10 @@ namespace basisu } double ca_l = get_luminance(ca), cb_l = get_luminance(cb); - + double delta = fabs(ca_l - cb_l); max_e = basisu::maximum(max_e, delta); - + if (log) { double log2_delta = log2(basisu::maximum(0.0f, ca_l) + 1.0f) - log2(basisu::maximum(0.0f, cb_l) + 1.0f); @@ -1931,7 +1931,7 @@ namespace basisu m_mean = (float)(sum / total_values); m_mean_squared = (float)(sum_sqr / total_values); m_rms = (float)sqrt(sum_sqr / total_values); - + const double max_val = 1.0f; m_psnr = m_rms ? (float)clamp(log10(max_val / m_rms) * 20.0f, 0.0f, 1000.0f) : 1000.0f; } @@ -1949,7 +1949,7 @@ namespace basisu m_any_abnormal = false; uint_vec hist(65536); - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) @@ -1960,7 +1960,7 @@ namespace basisu { if ((ca[i] < 0.0f) || (cb[i] < 0.0f)) m_has_neg = true; - + if ((fabs(ca[i]) > basist::MAX_HALF_FLOAT) || (fabs(cb[i]) > basist::MAX_HALF_FLOAT)) m_hf_mag_overflow = true; @@ -2013,7 +2013,7 @@ namespace basisu m_has_neg = false; m_hf_mag_overflow = false; m_any_abnormal = false; - + double sum = 0.0f, sum2 = 0.0f; m_max = 0; @@ -2050,7 +2050,7 @@ namespace basisu } // x } // y - + double total_values = (double)width * (double)height; if (avg_comp_error) total_values *= (double)clamp(total_chans, 1, 4); @@ -2170,7 +2170,7 @@ namespace basisu uint32_t hash_hsieh(const uint8_t *pBuf, size_t len) { - if (!pBuf || !len) + if (!pBuf || !len) return 0; uint32_t h = static_cast(len); @@ -2183,23 +2183,23 @@ namespace basisu const uint16_t *pWords = reinterpret_cast(pBuf); h += pWords[0]; - + const uint32_t t = (pWords[1] << 11) ^ h; h = (h << 16) ^ t; - + pBuf += sizeof(uint32_t); - + h += h >> 11; } switch (bytes_left) { - case 1: + case 1: h += *reinterpret_cast(pBuf); h ^= h << 10; h += h >> 1; break; - case 2: + case 2: h += *reinterpret_cast(pBuf); h ^= h << 11; h += h >> 17; @@ -2213,7 +2213,7 @@ namespace basisu default: break; } - + h ^= h << 3; h += h >> 5; h ^= h << 4; @@ -2224,7 +2224,7 @@ namespace basisu return h; } - job_pool::job_pool(uint32_t num_threads) : + job_pool::job_pool(uint32_t num_threads) : m_num_active_jobs(0) { m_kill_flag.store(false); @@ -2246,10 +2246,10 @@ namespace basisu job_pool::~job_pool() { debug_printf("job_pool::~job_pool\n"); - + // Notify all workers that they need to die right now. m_kill_flag.store(true); - + m_has_work.notify_all(); #ifdef __EMSCRIPTEN__ @@ -2259,7 +2259,7 @@ namespace basisu break; std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - + // At this point all worker threads should be exiting or exited. // We could call detach(), but this seems to just call join() anyway. #endif @@ -2268,7 +2268,7 @@ namespace basisu for (uint32_t i = 0; i < m_threads.size(); i++) m_threads[i].join(); } - + void job_pool::add_job(const std::function& job) { std::unique_lock lock(m_mutex); @@ -2288,7 +2288,7 @@ namespace basisu std::unique_lock lock(m_mutex); m_queue.emplace_back(std::move(job)); - + const size_t queue_size = m_queue.size(); lock.unlock(); @@ -2337,7 +2337,7 @@ namespace basisu //debug_printf("job_pool::job_thread: starting %u\n", index); m_num_active_workers.fetch_add(1); - + while (true) { std::unique_lock lock(m_mutex); @@ -2363,9 +2363,9 @@ namespace basisu --m_num_active_jobs; - // Now check if there are no more jobs remaining. + // Now check if there are no more jobs remaining. const bool all_done = m_queue.empty() && !m_num_active_jobs; - + lock.unlock(); if (all_done) @@ -2426,7 +2426,7 @@ namespace basisu // Simple validation if ((hdr.m_cmap != 0) && (hdr.m_cmap != 1)) return nullptr; - + if (hdr.m_cmap) { if ((hdr.m_cmap_bpp == 0) || (hdr.m_cmap_bpp > 32)) @@ -2585,13 +2585,13 @@ namespace basisu bytes_remaining += bytes_to_skip; } } - + width = hdr.m_width; height = hdr.m_height; const uint32_t source_pitch = width * tga_bytes_per_pixel; const uint32_t dest_pitch = width * n_chans; - + uint8_t *pImage = (uint8_t *)malloc(dest_pitch * height); if (!pImage) return nullptr; @@ -2613,7 +2613,7 @@ namespace basisu int pixels_remaining = width; uint8_t *pDst = &input_line_buf[0]; - do + do { if (!run_remaining) { @@ -2798,7 +2798,7 @@ namespace basisu if (!filedata.size() || (filedata.size() > UINT32_MAX)) return nullptr; - + return read_tga(&filedata[0], (uint32_t)filedata.size(), width, height, n_chans); } @@ -2945,13 +2945,13 @@ namespace basisu if (cur_line.size() < 3) return false; - + if (!is_x && !is_y) return false; comp[d] = is_x ? 0 : 1; dir[d] = (is_neg_x || is_neg_y) ? -1 : 1; - + uint32_t& dim = d ? minor_dim : major_dim; cur_line.erase(0, 3); @@ -2989,7 +2989,7 @@ namespace basisu if ((dim < 1) || (dim > MAX_SUPPORTED_DIM)) return false; } - + // temp image: width=minor, height=major img.resize(minor_dim, major_dim); @@ -3017,7 +3017,7 @@ namespace basisu } else { - // c[0]/red is 2.Check GB and E for validity. + // c[0]/red is 2.Check GB and E for validity. color_rgba c; memcpy(&c, &filedata[cur_ofs], 4); @@ -3139,7 +3139,7 @@ namespace basisu // width=minor axis dimension // height=major axis dimension // in file, pixels are emitted in minor order, them major (so major=scanlines in the file) - + imagef final_img; if (comp[0] == 0) // if major axis is X final_img.resize(major_dim, minor_dim); @@ -3156,10 +3156,10 @@ namespace basisu uint32_t dst_x = 0, dst_y = 0; // is the minor dim output x? - if (comp[1] == 0) + if (comp[1] == 0) { // minor axis is x, major is y - + // is minor axis (which is output x) flipped? if (dir[1] < 0) dst_x = minor_dim - 1 - minor_iter; @@ -3218,7 +3218,7 @@ namespace basisu return buf; } - + static uint8_vec& append_string(uint8_vec& buf, const std::string& str) { if (!str.size()) @@ -3235,7 +3235,7 @@ namespace basisu if (max_v < 1e-32f) rgbe.clear(); - else + else { int e; const float scale = frexp(max_v, &e) * 256.0f / max_v; @@ -3248,14 +3248,14 @@ namespace basisu const bool RGBE_FORCE_RAW = false; const bool RGBE_FORCE_OLD_CRUNCH = false; // note must readers (particularly stb_image.h's) don't properly support this, when they should - + bool write_rgbe(uint8_vec &file_data, imagef& img, rgbe_header_info& hdr_info) { if (!img.get_width() || !img.get_height()) return false; const uint32_t width = img.get_width(), height = img.get_height(); - + file_data.resize(0); file_data.reserve(1024 + img.get_width() * img.get_height() * 4); @@ -3288,7 +3288,7 @@ namespace basisu { int prev_r = -1, prev_g = -1, prev_b = -1, prev_e = -1; uint32_t cur_run_len = 0; - + for (uint32_t x = 0; x < width; x++) { color_rgba rgbe; @@ -3301,7 +3301,7 @@ namespace basisu // this ensures rshift stays 0, it's lame but this path is only for testing readers color_rgba f(1, 1, 1, cur_run_len - 1); append_vector(file_data, (const uint8_t*)&f, sizeof(f)); - append_vector(file_data, (const uint8_t*)&rgbe, sizeof(rgbe)); + append_vector(file_data, (const uint8_t*)&rgbe, sizeof(rgbe)); cur_run_len = 0; } } @@ -3311,12 +3311,12 @@ namespace basisu { color_rgba f(1, 1, 1, cur_run_len); append_vector(file_data, (const uint8_t*)&f, sizeof(f)); - + cur_run_len = 0; } - + append_vector(file_data, (const uint8_t*)&rgbe, sizeof(rgbe)); - + prev_r = rgbe[0]; prev_g = rgbe[1]; prev_b = rgbe[2]; @@ -3341,7 +3341,7 @@ namespace basisu { color_rgba rgbe(2, 2, width >> 8, width & 0xFF); append_vector(file_data, (const uint8_t*)&rgbe, sizeof(rgbe)); - + for (uint32_t x = 0; x < width; x++) { float2rgbe(rgbe, img(x, y)); @@ -3353,7 +3353,7 @@ namespace basisu for (uint32_t c = 0; c < 4; c++) { int raw_ofs = -1; - + uint32_t x = 0; while (x < width) { @@ -3368,7 +3368,7 @@ namespace basisu break; run_len++; } - + const uint32_t cost_to_keep_raw = ((raw_ofs != -1) ? 0 : 1) + run_len; // 0 or 1 bytes to start a raw run, then the repeated bytes issued as raw const uint32_t cost_to_take_run = 2 + 1; // 2 bytes to issue the RLE, then 1 bytes to start whatever follows it (raw or RLE) @@ -3392,7 +3392,7 @@ namespace basisu raw_ofs = -1; file_data.push_back(cur_byte); - + x++; } } // x @@ -3411,7 +3411,7 @@ namespace basisu return false; return write_vec_to_file(pFilename, file_data); } - + bool read_exr(const char* pFilename, imagef& img, int& n_chans) { n_chans = 0; @@ -3419,7 +3419,7 @@ namespace basisu int width = 0, height = 0; float* out_rgba = nullptr; const char* err = nullptr; - + int status = LoadEXRWithLayer(&out_rgba, &width, &height, pFilename, nullptr, &err, &n_chans); if (status != 0) { @@ -3438,7 +3438,7 @@ namespace basisu } img.resize(width, height); - + if (n_chans == 1) { const float* pSrc = out_rgba; @@ -3492,16 +3492,16 @@ namespace basisu { assert((n_chans == 1) || (n_chans == 3) || (n_chans == 4)); - const bool linear_hint = (flags & WRITE_EXR_LINEAR_HINT) != 0, + const bool linear_hint = (flags & WRITE_EXR_LINEAR_HINT) != 0, store_float = (flags & WRITE_EXR_STORE_FLOATS) != 0, no_compression = (flags & WRITE_EXR_NO_COMPRESSION) != 0; - + const uint32_t width = img.get_width(), height = img.get_height(); assert(width && height); - + if (!width || !height) return false; - + float_vec layers[4]; float* image_ptrs[4]; for (uint32_t c = 0; c < n_chans; c++) @@ -3530,7 +3530,7 @@ namespace basisu assert(0); return false; } - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) @@ -3554,7 +3554,7 @@ namespace basisu image.height = height; header.num_channels = n_chans; - + header.channels = (EXRChannelInfo*)calloc(header.num_channels, sizeof(EXRChannelInfo)); // Must be (A)BGR order, since most of EXR viewers expect this channel order. @@ -3565,37 +3565,37 @@ namespace basisu c = "BGR"[i]; else if (n_chans == 4) c = "ABGR"[i]; - + header.channels[i].name[0] = c; header.channels[i].name[1] = '\0'; header.channels[i].p_linear = linear_hint; } - + header.pixel_types = (int*)calloc(header.num_channels, sizeof(int)); header.requested_pixel_types = (int*)calloc(header.num_channels, sizeof(int)); - + if (!no_compression) header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; - for (int i = 0; i < header.num_channels; i++) + for (int i = 0; i < header.num_channels; i++) { // pixel type of input image - header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of output image to be stored in .EXR - header.requested_pixel_types[i] = store_float ? TINYEXR_PIXELTYPE_FLOAT : TINYEXR_PIXELTYPE_HALF; + header.requested_pixel_types[i] = store_float ? TINYEXR_PIXELTYPE_FLOAT : TINYEXR_PIXELTYPE_HALF; } const char* pErr_msg = nullptr; int ret = SaveEXRImageToFile(&image, &header, pFilename, &pErr_msg); - if (ret != TINYEXR_SUCCESS) + if (ret != TINYEXR_SUCCESS) { error_printf("Save EXR err: %s\n", pErr_msg); FreeEXRErrorMessage(pErr_msg); } - + free(header.channels); free(header.pixel_types); free(header.requested_pixel_types); @@ -3609,7 +3609,7 @@ namespace basisu va_list args; va_start(args, pFmt); -#ifdef _WIN32 +#ifdef _WIN32 vsprintf_s(buf, sizeof(buf), pFmt, args); #else vsnprintf(buf, sizeof(buf), pFmt, args); @@ -3634,7 +3634,7 @@ namespace basisu for (uint32_t x = 0; x < 8; x++) { const uint32_t q = row_bits & (1 << x); - + const color_rgba* pColor = q ? &fg : pBG; if (!pColor) continue; @@ -3654,8 +3654,8 @@ namespace basisu } } } - - // Very basic global Reinhard tone mapping, output converted to sRGB with no dithering, alpha is carried through unchanged. + + // Very basic global Reinhard tone mapping, output converted to sRGB with no dithering, alpha is carried through unchanged. // Only used for debugging/development. void tonemap_image_reinhard(image &ldr_img, const imagef &hdr_img, float exposure, bool add_noise, bool per_component, bool luma_scaling) { @@ -3665,7 +3665,7 @@ namespace basisu rand r; r.seed(128); - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) @@ -3700,7 +3700,7 @@ namespace basisu { //Lmapped = L / (1.0f + L); //Lmapped /= L; - + Lmapped = 1.0f / (1.0f + L); } @@ -3920,7 +3920,7 @@ namespace basisu dst_img.set_all(color_rgba(0, 0, 0, 255)); basisu::vector half_img(width * 3 * height); - + uint32_t low_h = UINT32_MAX, high_h = 0; for (uint32_t y = 0; y < height; y++) @@ -3944,7 +3944,7 @@ namespace basisu low_h = minimum(low_h, h); high_h = maximum(high_h, h); - + half_img[(x + y * width) * 3 + i] = (basist::half_float)h; } // i @@ -3961,7 +3961,7 @@ namespace basisu for (uint32_t i = 0; i < 3; i++) { basist::half_float h = half_img[(x + y * width) * 3 + i]; - + float f = (float)(h - low_h) / (float)(high_h - low_h); int iv = basisu::clamp((int)std::round(f * 255.0f), 0, 255); @@ -3974,5 +3974,5 @@ namespace basisu return true; } - + } // namespace basisu diff --git a/encoder/basisu_enc.h b/encoder/basisu_enc.h index 5373b60c..0176dc09 100644 --- a/encoder/basisu_enc.h +++ b/encoder/basisu_enc.h @@ -63,7 +63,7 @@ namespace basisu void error_vprintf(const char* pFmt, va_list args); void error_printf(const char *pFmt, ...); - + template inline void fmt_error_printf(const char* pFmt, Args&&... args) { @@ -74,9 +74,9 @@ namespace basisu } void platform_sleep(uint32_t ms); - + // Helpers - + inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); @@ -94,18 +94,18 @@ namespace basisu return val << shift; } - inline int32_t clampi(int32_t value, int32_t low, int32_t high) - { - if (value < low) - value = low; - else if (value > high) - value = high; - return value; + inline int32_t clampi(int32_t value, int32_t low, int32_t high) + { + if (value < low) + value = low; + else if (value > high) + value = high; + return value; } inline uint8_t mul_8(uint32_t v, uint32_t a) { - v = v * a + 128; + v = v * a + 128; return (uint8_t)((v + (v >> 8)) >> 8); } @@ -165,7 +165,7 @@ namespace basisu return bits; } - + // Open interval inline int bounds_check(int v, int l, int h) { (void)v; (void)l; (void)h; assert(v >= l && v < h); return v; } inline uint32_t bounds_check(uint32_t v, uint32_t l, uint32_t h) { (void)v; (void)l; (void)h; assert(v >= l && v < h); return v; } @@ -199,10 +199,10 @@ namespace basisu return -1; return (int)res; } - + // Hashing - - inline uint32_t bitmix32c(uint32_t v) + + inline uint32_t bitmix32c(uint32_t v) { v = (v + 0x7ed55d16) + (v << 12); v = (v ^ 0xc761c23c) ^ (v >> 19); @@ -213,7 +213,7 @@ namespace basisu return v; } - inline uint32_t bitmix32(uint32_t v) + inline uint32_t bitmix32(uint32_t v) { v -= (v << 6); v ^= (v >> 17); @@ -339,7 +339,7 @@ namespace basisu }; // Linear algebra - + template class vec { @@ -444,7 +444,7 @@ namespace basisu inline const T *get_ptr() const { return reinterpret_cast(&m_v[0]); } inline T *get_ptr() { return reinterpret_cast(&m_v[0]); } - + inline vec operator- () const { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = -m_v[i]; return res; } inline vec operator+ () const { return *this; } inline vec &operator+= (const vec &other) { for (uint32_t i = 0; i < N; i++) m_v[i] += other.m_v[i]; return *this; } @@ -453,14 +453,14 @@ namespace basisu inline vec &operator*=(const vec &other) { for (uint32_t i = 0; i < N; i++) m_v[i] *= other.m_v[i]; return *this; } inline vec &operator/= (T s) { for (uint32_t i = 0; i < N; i++) m_v[i] /= s; return *this; } inline vec &operator*= (T s) { for (uint32_t i = 0; i < N; i++) m_v[i] *= s; return *this; } - + friend inline vec operator+(const vec &lhs, const vec &rhs) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = lhs.m_v[i] + rhs.m_v[i]; return res; } friend inline vec operator-(const vec &lhs, const vec &rhs) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = lhs.m_v[i] - rhs.m_v[i]; return res; } friend inline vec operator*(const vec &lhs, T val) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = lhs.m_v[i] * val; return res; } friend inline vec operator*(T val, const vec &rhs) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = val * rhs.m_v[i]; return res; } friend inline vec operator/(const vec &lhs, T val) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = lhs.m_v[i] / val; return res; } friend inline vec operator/(const vec &lhs, const vec &rhs) { vec res; for (uint32_t i = 0; i < N; i++) res.m_v[i] = lhs.m_v[i] / rhs.m_v[i]; return res; } - + static inline T dot_product(const vec &lhs, const vec &rhs) { T res = lhs.m_v[0] * rhs.m_v[0]; for (uint32_t i = 1; i < N; i++) res += lhs.m_v[i] * rhs.m_v[i]; return res; } inline T dot(const vec &rhs) const { return dot_product(*this, rhs); } @@ -534,7 +534,7 @@ namespace basisu template struct bitwise_copyable< vec > { enum { cFlag = true }; }; template struct bitwise_movable< vec > { enum { cFlag = true }; }; - + template class matrix { @@ -798,7 +798,7 @@ namespace basisu } #undef BASISU_GET_KEY - + // Very simple job pool with no dependencies. class job_pool { @@ -808,24 +808,24 @@ namespace basisu // num_threads is the TOTAL number of job pool threads, including the calling thread! So 2=1 new thread, 3=2 new threads, etc. job_pool(uint32_t num_threads); ~job_pool(); - + void add_job(const std::function& job); void add_job(std::function&& job); void wait_for_all(); size_t get_total_threads() const { return 1 + m_threads.size(); } - + private: std::vector m_threads; std::vector > m_queue; - + std::mutex m_mutex; std::condition_variable m_has_work; std::condition_variable m_no_more_jobs; - + uint32_t m_num_active_jobs; - + std::atomic m_kill_flag; std::atomic m_num_active_workers; @@ -870,7 +870,7 @@ namespace basisu return *this; } }; - + class color_rgba { public: @@ -994,7 +994,7 @@ namespace basisu inline const uint8_t &operator[] (uint32_t index) const { assert(index < 4); return m_comps[index]; } inline uint8_t &operator[] (uint32_t index) { assert(index < 4); return m_comps[index]; } - + inline void clear() { m_comps[0] = 0; @@ -1030,7 +1030,7 @@ namespace basisu } inline int get_601_luma() const { return (19595U * m_comps[0] + 38470U * m_comps[1] + 7471U * m_comps[2] + 32768U) >> 16U; } - inline int get_709_luma() const { return (13938U * m_comps[0] + 46869U * m_comps[1] + 4729U * m_comps[2] + 32768U) >> 16U; } + inline int get_709_luma() const { return (13938U * m_comps[0] + 46869U * m_comps[1] + 4729U * m_comps[2] + 32768U) >> 16U; } inline int get_luma(bool luma_601) const { return luma_601 ? get_601_luma() : get_709_luma(); } inline uint32_t get_bgra_uint32() const { return b | (g << 8) | (r << 16) | (a << 24); } @@ -1070,7 +1070,7 @@ namespace basisu else return color_distance(c0.r, c0.g, c0.b, c1.r, c1.g, c1.b); } - + // TODO: Allow user to control channel weightings. inline uint32_t color_distance(bool perceptual, const color_rgba &e1, const color_rgba &e2, bool alpha) { @@ -1091,7 +1091,7 @@ namespace basisu const float dcb = cb1 - cb2; uint32_t d = static_cast(32.0f*4.0f*dl*dl + 32.0f*2.0f*(.5f / (1.0f - .2126f))*(.5f / (1.0f - .2126f))*dcr*dcr + 32.0f*.25f*(.5f / (1.0f - .0722f))*(.5f / (1.0f - .0722f))*dcb*dcb); - + if (alpha) { int da = static_cast(e1.a) - static_cast(e2.a); @@ -1108,7 +1108,7 @@ namespace basisu int delta_l = dr * 27 + dg * 92 + db * 9; int delta_cr = dr * 128 - delta_l; int delta_cb = db * 128 - delta_l; - + uint32_t id = ((uint32_t)(delta_l * delta_l) >> 7U) + ((((uint32_t)(delta_cr * delta_cr) >> 7U) * 26U) >> 7U) + ((((uint32_t)(delta_cb * delta_cb) >> 7U) * 3U) >> 7U); @@ -1209,7 +1209,7 @@ namespace basisu return true; } - + inline std::string string_tolower(const std::string& s) { std::string result(s); @@ -1254,7 +1254,7 @@ namespace basisu char fname_buf[_MAX_FNAME] = { 0 }; char ext_buf[_MAX_EXT] = { 0 }; - errno_t error = _splitpath_s(p, + errno_t error = _splitpath_s(p, pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0, pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0, pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0, @@ -1286,7 +1286,7 @@ namespace basisu if ((pDir->size()) && (pDir->back() != '/')) *pDir += "/"; } - + if (pFilename) { *pFilename = pBaseName; @@ -1313,7 +1313,7 @@ namespace basisu return (c == '/'); #endif } - + inline bool is_drive_separator(char c) { #ifdef _WIN32 @@ -1341,7 +1341,7 @@ namespace basisu string_combine_path(dst, p, q); string_combine_path(dst, dst.c_str(), r); } - + inline void string_combine_path_and_extension(std::string &dst, const char *p, const char *q, const char *r, const char *pExt) { string_combine_path(dst, p, q, r); @@ -1543,7 +1543,7 @@ namespace basisu codebook.resize(0); codebook.reserve(max_clusters); - + uint32_t node_index = 0; while (true) @@ -1554,7 +1554,7 @@ namespace basisu { codebook.resize(codebook.size() + 1); codebook.back() = cur.m_training_vecs; - + if (node_stack.empty()) break; @@ -1562,7 +1562,7 @@ namespace basisu node_stack.pop_back(); continue; } - + node_stack.push_back(cur.m_right_index); node_index = cur.m_left_index; } @@ -1603,7 +1603,7 @@ namespace basisu assert(node.is_leaf()); var_heap.delete_top(); - + if (node.m_training_vecs.size() > 1) { if (split_node(node_index, var_heap, l_children, r_children)) @@ -1692,7 +1692,7 @@ namespace basisu m_nodes[node_index].m_left_index = l_child_index; m_nodes[node_index].m_right_index = r_child_index; - + m_nodes[node_index].m_codebook_index = m_next_codebook_index; m_next_codebook_index++; @@ -1706,7 +1706,7 @@ namespace basisu if ((l_child.m_var <= 0.0f) && (l_child.m_training_vecs.size() > 1)) { TrainingVectorType v(m_training_vecs[l_child.m_training_vecs[0]].first); - + for (uint32_t i = 1; i < l_child.m_training_vecs.size(); i++) { if (!(v == m_training_vecs[l_child.m_training_vecs[i]].first)) @@ -1733,10 +1733,10 @@ namespace basisu if ((l_child.m_var > 0.0f) && (l_child.m_training_vecs.size() > 1)) var_heap.add_heap(l_child_index, l_child.m_var); - + if ((r_child.m_var > 0.0f) && (r_child.m_training_vecs.size() > 1)) var_heap.add_heap(r_child_index, r_child.m_var); - + return true; } @@ -1832,7 +1832,7 @@ namespace basisu for (uint32_t i = 0; i < node.m_training_vecs.size(); i++) { const TrainingVectorType& v = m_training_vecs[node.m_training_vecs[i]].first; - + l = TrainingVectorType::component_min(l, v); h = TrainingVectorType::component_max(h, v); } @@ -1913,8 +1913,8 @@ namespace basisu const uint32_t cMaxIters = 6; for (uint32_t iter = 0; iter < cMaxIters; iter++) { - l_children.resize(0); - r_children.resize(0); + l_children.resize(0); + r_children.resize(0); TrainingVectorType new_l_child(cZero), new_r_child(cZero); @@ -1966,7 +1966,7 @@ namespace basisu { const TrainingVectorType& v = m_training_vecs[node.m_training_vecs[i]].first; const uint64_t weight = m_training_vecs[node.m_training_vecs[i]].second; - + if ((!i) || (v == firstVec)) { firstVec = v; @@ -2068,7 +2068,7 @@ namespace basisu } Quantizer quantizers[cMaxThreads]; - + bool success_flags[cMaxThreads]; clear_obj(success_flags); @@ -2164,10 +2164,10 @@ namespace basisu bool even_odd_input_pairs_equal) { typedef bit_hasher training_vec_bit_hasher; - - typedef std::unordered_map < typename Quantizer::training_vec_type, weighted_block_group, + + typedef std::unordered_map < typename Quantizer::training_vec_type, weighted_block_group, training_vec_bit_hasher> group_hash; - + //interval_timer tm; //tm.start(); @@ -2176,7 +2176,7 @@ namespace basisu unique_vecs.reserve(20000); weighted_block_group g; - + if (even_odd_input_pairs_equal) { g.m_indices.resize(2); @@ -2261,7 +2261,7 @@ namespace basisu typename group_hash::const_iterator group_iter = unique_vec_iters[group_index]; const uint_vec& training_vec_indices = group_iter->second.m_indices; - + append_vector(codebook.back(), training_vec_indices); } } @@ -2338,7 +2338,7 @@ namespace basisu const double inv_total = 1.0f / total; const double neg_inv_log2 = -1.0f / log(2.0f); - + double e = 0.0f; for (uint32_t i = 0; i < m_hist.size(); i++) if (m_hist[i]) @@ -2347,7 +2347,7 @@ namespace basisu return e; } }; - + struct sym_freq { uint32_t m_key; @@ -2357,7 +2357,7 @@ namespace basisu sym_freq *canonical_huffman_radix_sort_syms(uint32_t num_syms, sym_freq *pSyms0, sym_freq *pSyms1); void canonical_huffman_calculate_minimum_redundancy(sym_freq *A, int num_syms); void canonical_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size); - + class huffman_encoding_table { public: @@ -2378,7 +2378,7 @@ namespace basisu bool init(uint32_t num_syms, const uint16_t *pFreq, uint32_t max_code_size); bool init(uint32_t num_syms, const uint32_t *pSym_freq, uint32_t max_code_size); - + inline const uint16_vec &get_codes() const { return m_codes; } inline const uint8_vec &get_code_sizes() const { return m_code_sizes; } @@ -2409,7 +2409,7 @@ namespace basisu m_bytes(other.m_bytes), m_bit_buffer(other.m_bit_buffer), m_bit_buffer_size(other.m_bit_buffer_size), - m_total_bits(other.m_total_bits) + m_total_bits(other.m_total_bits) { } @@ -2491,7 +2491,7 @@ namespace basisu m_bit_buffer = 0; m_bit_buffer_size = 0; - + return 8; } @@ -2540,7 +2540,7 @@ namespace basisu if (v < u) return put_bits(v, k); - + uint32_t x = v + u; assert((x >> 1) >= u); @@ -2552,20 +2552,20 @@ namespace basisu inline uint32_t put_rice(uint32_t v, uint32_t m) { assert(m); - + const uint64_t start_bits = m_total_bits; uint32_t q = v >> m, r = v & ((1 << m) - 1); // rice coding sanity check assert(q <= 64); - + for (; q > 16; q -= 16) put_bits(0xFFFF, 16); put_bits((1 << q) - 1, q); put_bits(r << 1, m + 1); - + return (uint32_t)(m_total_bits - start_bits); } @@ -2575,13 +2575,13 @@ namespace basisu const uint32_t chunk_size = 1 << chunk_bits; const uint32_t chunk_mask = chunk_size - 1; - + uint32_t total_bits = 0; for ( ; ; ) { uint32_t next_v = v >> chunk_bits; - + total_bits += put_bits((v & chunk_mask) | (next_v ? chunk_size : 0), chunk_bits + 1); if (!next_v) break; @@ -2598,11 +2598,11 @@ namespace basisu { for (uint32_t i = 0; i < other.m_bytes.size(); i++) put_bits(other.m_bytes[i], 8); - + if (other.m_bit_buffer_size) put_bits(other.m_bit_buffer, other.m_bit_buffer_size); } - + private: uint8_vec m_bytes; uint32_t m_bit_buffer, m_bit_buffer_size; @@ -2632,7 +2632,7 @@ namespace basisu inline void init(uint32_t bits_per_sym, uint32_t total_syms_per_group) { assert((bits_per_sym * total_syms_per_group) <= 16 && total_syms_per_group >= 1 && bits_per_sym >= 1); - + m_bits_per_sym = bits_per_sym; m_total_syms_per_group = total_syms_per_group; m_cur_sym_bits = 0; @@ -2686,7 +2686,7 @@ namespace basisu return true; } - + inline uint32_t emit_next_sym(bitwise_coder &c) { uint32_t bits = 0; @@ -2716,7 +2716,7 @@ namespace basisu bool huffman_test(int rand_seed); // VQ index reordering - + class palette_index_reorderer { public: @@ -2737,7 +2737,7 @@ namespace basisu typedef float(*pEntry_dist_func)(uint32_t i, uint32_t j, void *pCtx); void init(uint32_t num_indices, const uint32_t *pIndices, uint32_t num_syms, pEntry_dist_func pDist_func, void *pCtx, float dist_func_weight); - + // Table remaps old to new symbol indices inline const uint_vec &get_remap_table() const { return m_remap_table; } @@ -2758,12 +2758,12 @@ namespace basisu class image { public: - image() : + image() : m_width(0), m_height(0), m_pitch(0) { } - image(uint32_t w, uint32_t h, uint32_t p = UINT32_MAX) : + image(uint32_t w, uint32_t h, uint32_t p = UINT32_MAX) : m_width(0), m_height(0), m_pitch(0) { resize(w, h, p); @@ -2829,7 +2829,7 @@ namespace basisu image &clear() { - m_width = 0; + m_width = 0; m_height = 0; m_pitch = 0; clear_vector(m_pixels); @@ -2857,7 +2857,7 @@ namespace basisu void init(const uint8_t *pImage, uint32_t width, uint32_t height, uint32_t comps) { assert(comps >= 1 && comps <= 4); - + resize(width, height); for (uint32_t y = 0; y < height; y++) @@ -2943,7 +2943,7 @@ namespace basisu p = w; clear(); - + if ((!p) || (!w) || (!h)) return *this; @@ -3022,8 +3022,8 @@ namespace basisu y = wrap_v ? posmod(y, m_height) : clamp(y, 0, m_height - 1); return m_pixels[x + y * m_pitch]; } - - inline image &set_clipped(int x, int y, const color_rgba &c) + + inline image &set_clipped(int x, int y, const color_rgba &c) { if ((static_cast(x) < m_width) && (static_cast(y) < m_height)) (*this)(x, y) = c; @@ -3187,7 +3187,7 @@ namespace basisu } void debug_text(uint32_t x_ofs, uint32_t y_ofs, uint32_t x_scale, uint32_t y_scale, const color_rgba &fg, const color_rgba *pBG, bool alpha_only, const char* p, ...); - + vec4F get_filtered_vec4F(float x, float y) const { x -= .5f; @@ -3229,7 +3229,7 @@ namespace basisu return result; } - + private: uint32_t m_width, m_height, m_pitch; // all in pixels color_rgba_vec m_pixels; @@ -3242,12 +3242,12 @@ namespace basisu class imagef { public: - imagef() : + imagef() : m_width(0), m_height(0), m_pitch(0) { } - imagef(uint32_t w, uint32_t h, uint32_t p = UINT32_MAX) : + imagef(uint32_t w, uint32_t h, uint32_t p = UINT32_MAX) : m_width(0), m_height(0), m_pitch(0) { resize(w, h, p); @@ -3307,7 +3307,7 @@ namespace basisu imagef &clear() { - m_width = 0; + m_width = 0; m_height = 0; m_pitch = 0; clear_vector(m_pixels); @@ -3363,7 +3363,7 @@ namespace basisu set_clipped(x + ix, y + iy, c); return *this; } - + imagef &crop(uint32_t w, uint32_t h, uint32_t p = UINT32_MAX, const vec4F &background = vec4F(0,0,0,1)) { if (p == UINT32_MAX) @@ -3382,7 +3382,7 @@ namespace basisu cur_state.swap(m_pixels); m_pixels.resize(p * h); - + for (uint32_t y = 0; y < h; y++) { for (uint32_t x = 0; x < w; x++) @@ -3445,8 +3445,8 @@ namespace basisu y = wrap_v ? posmod(y, m_height) : clamp(y, 0, m_height - 1); return m_pixels[x + y * m_pitch]; } - - inline imagef &set_clipped(int x, int y, const vec4F &c) + + inline imagef &set_clipped(int x, int y, const vec4F &c) { if ((static_cast(x) < m_width) && (static_cast(y) < m_height)) (*this)(x, y) = c; @@ -3531,7 +3531,7 @@ namespace basisu { float &p = c[s]; union { float f; uint32_t u; } x; x.f = p; - + if ((std::isnan(p)) || (std::isinf(p)) || (x.u == 0x80000000)) { if (std::isnan(p)) @@ -3576,14 +3576,14 @@ namespace basisu fprintf(stderr, "One or more input pixels was negative -- setting these pixel components to 0 because ASTC HDR doesn't support signed values.\n"); neg_msg = true; } - + status = false; } if (p > highest_mag) { p = highest_mag; - + if (!clamp_msg) { fprintf(stderr, "One or more input pixels had to be clamped to %f.\n", highest_mag); @@ -3647,7 +3647,7 @@ namespace basisu return result; } - + private: uint32_t m_width, m_height, m_pitch; // all in pixels vec4F_vec m_pixels; @@ -3709,9 +3709,9 @@ namespace basisu }; extern fast_linear_to_srgb g_fast_linear_to_srgb; - + // Image metrics - + class image_metrics { public: @@ -3762,7 +3762,7 @@ namespace basisu bool load_jpg(const char *pFilename, image& img); bool load_jpg(const uint8_t* pBuf, size_t buf_size, image& img); inline bool load_jpg(const std::string &filename, image &img) { return load_jpg(filename.c_str(), img); } - + // Currently loads .PNG, .TGA, or .JPG bool load_image(const char* pFilename, image& img); inline bool load_image(const std::string &filename, image &img) { return load_image(filename.c_str(), img); } @@ -3771,9 +3771,9 @@ namespace basisu // Supports .HDR and most (but not all) .EXR's (see TinyEXR). bool load_image_hdr(const char* pFilename, imagef& img, bool ldr_srgb_to_linear = true, float linear_nit_multiplier = 1.0f, float ldr_black_bias = 0.0f); - + inline bool load_image_hdr(const std::string& filename, imagef& img, bool ldr_srgb_to_linear = true, float linear_nit_multiplier = 1.0f, float ldr_black_bias = 0.0f) - { + { return load_image_hdr(filename.c_str(), img, ldr_srgb_to_linear, linear_nit_multiplier, ldr_black_bias); } @@ -3791,7 +3791,7 @@ namespace basisu uint8_t *read_tga(const uint8_t *pBuf, uint32_t buf_size, int &width, int &height, int &n_chans); uint8_t *read_tga(const char *pFilename, int &width, int &height, int &n_chans); - + struct rgbe_header_info { std::string m_program; @@ -3803,13 +3803,13 @@ namespace basisu double m_exposure; // watts/steradian/m^2. bool m_has_exposure; - void clear() - { - m_program.clear(); - m_gamma = 1.0f; - m_has_gamma = false; - m_exposure = 1.0f; - m_has_exposure = false; + void clear() + { + m_program.clear(); + m_gamma = 1.0f; + m_has_gamma = false; + m_exposure = 1.0f; + m_has_exposure = false; } }; @@ -3821,7 +3821,7 @@ namespace basisu bool read_exr(const char* pFilename, imagef& img, int& n_chans); bool read_exr(const void* pMem, size_t mem_size, imagef& img); - + enum { WRITE_EXR_LINEAR_HINT = 1, // hint for lossy comp. methods: exr_perceptual_treatment_t, logarithmic or linear, defaults to logarithmic @@ -3831,7 +3831,7 @@ namespace basisu // Supports 1 (Y), 3 (RGB), or 4 (RGBA) channel images. bool write_exr(const char* pFilename, const imagef& img, uint32_t n_chans, uint32_t flags); - + enum { cImageSaveGrayscale = 1, @@ -3840,26 +3840,26 @@ namespace basisu bool save_png(const char* pFilename, const image& img, uint32_t image_save_flags = 0, uint32_t grayscale_comp = 0); inline bool save_png(const std::string &filename, const image &img, uint32_t image_save_flags = 0, uint32_t grayscale_comp = 0) { return save_png(filename.c_str(), img, image_save_flags, grayscale_comp); } - + bool read_file_to_vec(const char* pFilename, uint8_vec& data); - bool read_file_to_data(const char* pFilename, void *pData, size_t len); + bool read_file_to_data(const char* pFilename, void *pData, size_t len); bool write_data_to_file(const char* pFilename, const void* pData, size_t len); - + inline bool write_vec_to_file(const char* pFilename, const uint8_vec& v) { return v.size() ? write_data_to_file(pFilename, &v[0], v.size()) : write_data_to_file(pFilename, "", 0); } - + bool image_resample(const image &src, image &dst, bool srgb = false, - const char *pFilter = "lanczos4", float filter_scale = 1.0f, + const char *pFilter = "lanczos4", float filter_scale = 1.0f, bool wrapping = false, uint32_t first_comp = 0, uint32_t num_comps = 4); - bool image_resample(const imagef& src, imagef& dst, + bool image_resample(const imagef& src, imagef& dst, const char* pFilter = "lanczos4", float filter_scale = 1.0f, bool wrapping = false, uint32_t first_comp = 0, uint32_t num_comps = 4); - + // Timing - + typedef uint64_t timer_ticks; class interval_timer @@ -3872,7 +3872,7 @@ namespace basisu double get_elapsed_secs() const; inline double get_elapsed_ms() const { return 1000.0f* get_elapsed_secs(); } - + static void init(); static inline timer_ticks get_ticks_per_sec() { return g_freq; } static timer_ticks get_ticks(); @@ -3948,7 +3948,7 @@ namespace basisu void tonemap_image_reinhard(image& ldr_img, const imagef& hdr_img, float exposure, bool add_noise = false, bool per_component = true, bool luma_scaling = false); bool tonemap_image_compressive(image& dst_img, const imagef& hdr_test_img); bool tonemap_image_compressive2(image& dst_img, const imagef& hdr_test_img); - + // Intersection enum eClear { cClear = 0 }; enum eInitExpand { cInitExpand = 0 }; @@ -4239,9 +4239,9 @@ namespace basisu BASISU_FORCE_INLINE float fast_half_to_float_pos_not_inf_or_nan(basist::half_float h) { assert(!basist::half_is_signed(h) && !basist::is_half_inf_or_nan(h)); - + // add 112 to the exponent (112+half float's exp bias of 15=float32's bias of 127) - static const fu32 K = { 0x77800000 }; + static const fu32 K = { 0x77800000 }; fu32 o; o.u = h << 13; @@ -4257,7 +4257,7 @@ namespace basisu // Sutract 112 from the exponent, to change the bias from 127 to 15. static const fu32 g_f_to_h{ 0x7800000 }; - + fu32 fu; fu.f = minimum((float)basist::MAX_HALF_FLOAT, fabsf(f)) * g_f_to_h.f; @@ -4269,17 +4269,17 @@ namespace basisu { assert(!isnan(f) && !isinf(f)); assert((f >= 0.0f) && (f <= basist::MAX_HALF_FLOAT)); - + // Sutract 112 from the exponent, to change the bias from 127 to 15. static const fu32 g_f_to_h{ 0x7800000 }; fu32 fu; fu.f = f * g_f_to_h.f; - + return (basist::half_float)((fu.u >> (23 - 10)) & 0x7FFF); } - + inline basist::half_float fast_float_to_half_no_clamp_neg_nan_or_inf(float f) { assert(!isnan(f) && !isinf(f)); @@ -4304,7 +4304,7 @@ namespace basisu return (basist::half_float)h; } - + } // namespace basisu #include "basisu_math.h" diff --git a/encoder/basisu_etc.cpp b/encoder/basisu_etc.cpp index ba1c1423..4ad0dbda 100644 --- a/encoder/basisu_etc.cpp +++ b/encoder/basisu_etc.cpp @@ -39,7 +39,7 @@ namespace basisu { -16,-48,-64,-80,8,40,56,72 }, { -16,-40,-64,-80,8,32,56,72 }, { -16,-32,-64,-80,8,24,56,72 }, { -16,-40,-56,-80,8,32,48,72 }, { -24,-32,-56,-80,16,24,48,72 }, { -8,-16,-24,-80,0,8,16,72 }, { -32,-48,-64,-72,24,40,56,64 }, { -24,-40,-56,-72,16,32,48,64 } }; - + // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte. static uint16_t g_etc1_inverse_lookup[2 * 8 * 4][256]; // [ diff/inten_table/selector][desired_color ] @@ -113,7 +113,7 @@ namespace basisu static uint32_t etc1_decode_value(uint32_t diff, uint32_t inten, uint32_t selector, uint32_t packed_c) { - const uint32_t limit = diff ? 32 : 16; + const uint32_t limit = diff ? 32 : 16; BASISU_NOTE_UNUSED(limit); assert((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit)); int c; @@ -261,7 +261,7 @@ namespace basisu return best_error; } - + const uint32_t BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE = 165; static const struct { uint8_t m_v[4]; } g_cluster_fit_order_tab[BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE] = @@ -300,7 +300,7 @@ namespace basisu { { 2, 1, 2, 3 } },{ { 4, 1, 0, 3 } },{ { 3, 1, 1, 3 } },{ { 1, 1, 2, 4 } },{ { 2, 1, 0, 5 } }, { { 1, 0, 1, 6 } },{ { 0, 2, 1, 5 } },{ { 0, 2, 0, 6 } },{ { 1, 1, 1, 5 } },{ { 1, 1, 0, 6 } } }; - + const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] = { { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 }, @@ -600,7 +600,7 @@ namespace basisu const int y3 = pInten_modifer_table[3]; pDst[3].set(ir + y3, ig + y3, ib + y3, 255); } - + bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha) { const bool diff_flag = block.get_diff_bit(); @@ -723,7 +723,7 @@ namespace basisu { return (n << 4) | n; } - + uint64_t etc_block::evaluate_etc1_error(const color_rgba* pBlock_pixels, bool perceptual, int subblock_index) const { color_rgba unpacked_block[16]; @@ -772,7 +772,7 @@ namespace basisu } } } - + bool etc1_optimizer::compute() { assert(m_pResult->m_pSelectors); @@ -817,19 +817,19 @@ namespace basisu const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels; uint64_t actual_error = 0; - + bool perceptual; if (m_pParams->m_quality >= cETCQualityMedium) perceptual = m_pParams->m_perceptual; else perceptual = (m_pParams->m_quality == cETCQualityFast) ? false : m_pParams->m_perceptual; - + for (uint32_t i = 0; i < n; i++) actual_error += color_distance(perceptual, pSrc_pixels[i], block_colors[pSelectors[i]], false); assert(actual_error == m_best_solution.m_error); } -#endif +#endif m_pResult->m_error = m_best_solution.m_error; @@ -1014,10 +1014,10 @@ namespace basisu m_luma.resize(n); m_sorted_luma_indices.resize(n); m_sorted_luma.resize(n); - + int min_r = 255, min_g = 255, min_b = 255; int max_r = 0, max_g = 0, max_b = 0; - + for (uint32_t i = 0; i < n; i++) { const color_rgba& c = m_pParams->m_pSrc_pixels[i]; @@ -1055,7 +1055,7 @@ namespace basisu m_pSorted_luma = &m_sorted_luma[0]; m_pSorted_luma_indices = &m_sorted_luma_indices[0]; - + for (uint32_t i = 0; i < n; i++) m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]]; } @@ -1086,7 +1086,7 @@ namespace basisu return true; } - + static uint8_t g_eval_dist_tables[8][256] = { // 99% threshold @@ -1255,7 +1255,7 @@ namespace basisu } trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color; trial_solution.m_coords.m_color4 = m_pParams->m_use_color4; - + #if BASISU_DEBUG_ETC_ENCODER_DEEPER printf("Eval done: %u error: %I64u best error so far: %I64u\n", (trial_solution.m_error < pBest_solution->m_error), trial_solution.m_error, pBest_solution->m_error); #endif @@ -1269,7 +1269,7 @@ namespace basisu success = true; } } - + return success; } @@ -1300,14 +1300,14 @@ namespace basisu } const color_rgba base_color(coords.get_scaled_color()); - + const uint32_t n = m_pParams->m_num_src_pixels; assert(trial_solution.m_selectors.size() == n); trial_solution.m_error = UINT64_MAX; - + const bool perceptual = (m_pParams->m_quality == cETCQualityFast) ? false : m_pParams->m_perceptual; - + for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table) { const int* pInten_table = g_etc1_inten_tables[inten_table]; @@ -1327,10 +1327,10 @@ namespace basisu // 0 1 2 3 // 01 12 23 const uint32_t block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] }; - + uint64_t total_error = 0; const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels; - + if (perceptual) { if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0]) diff --git a/encoder/basisu_etc.h b/encoder/basisu_etc.h index 5c44bd48..1001d0c7 100644 --- a/encoder/basisu_etc.h +++ b/encoder/basisu_etc.h @@ -76,7 +76,7 @@ namespace basisu // 000 001 010 011 100 101 110 111 // 0 1 2 3 -4 -3 -2 -1 }; - + extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues]; extern const uint8_t g_etc1_to_selector_index[cETC1SelectorValues]; extern const uint8_t g_selector_index_to_etc1[cETC1SelectorValues]; @@ -92,7 +92,7 @@ namespace basisu { // big endian uint64: // bit ofs: 56 48 40 32 24 16 8 0 - // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 + // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 union { uint64_t m_uint64; @@ -275,7 +275,7 @@ namespace basisu const uint32_t byte_bit_ofs = bit_index & 7; const uint32_t mask = 1 << byte_bit_ofs; - + const uint32_t lsb = etc1_val & 1; const uint32_t msb = etc1_val >> 1; @@ -510,7 +510,7 @@ namespace basisu b.r = (base5_color.r << 3U) | (base5_color.r >> 2U); b.g = (base5_color.g << 3U) | (base5_color.g >> 2U); b.b = (base5_color.b << 3U) | (base5_color.b >> 2U); - + const int* pInten_table = g_etc1_inten_tables[inten_table]; pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255); @@ -646,7 +646,7 @@ namespace basisu void set_block_color5_etc1s(const color_rgba &c_unscaled) { set_diff_bit(true); - + set_base5_color(pack_color5(c_unscaled, false)); set_delta3_color(pack_delta3(0, 0, 0)); } @@ -679,11 +679,11 @@ namespace basisu int dr = c1_unscaled.r - c0_unscaled.r; int dg = c1_unscaled.g - c0_unscaled.g; int db = c1_unscaled.b - c0_unscaled.b; - + dr = clamp(dr, cETC1ColorDeltaMin, cETC1ColorDeltaMax); dg = clamp(dg, cETC1ColorDeltaMin, cETC1ColorDeltaMax); db = clamp(db, cETC1ColorDeltaMin, cETC1ColorDeltaMax); - + set_delta3_color(pack_delta3(dr, dg, db)); return true; @@ -785,12 +785,12 @@ namespace basisu return static_cast(x); } }; - + typedef basisu::vector etc_block_vec; // Returns false if the unpack fails (could be bogus data or ETC2) bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha = false); - + enum basis_etc_quality { cETCQualityFast, @@ -1077,13 +1077,13 @@ namespace basisu enum { cSolutionsTriedHashBits = 10, cTotalSolutionsTriedHashSize = 1 << cSolutionsTriedHashBits, cSolutionsTriedHashMask = cTotalSolutionsTriedHashSize - 1 }; uint8_t m_solutions_tried[cTotalSolutionsTriedHashSize / 8]; - + void get_nearby_inten_tables(uint32_t idx, int &first_inten_table, int &last_inten_table) { first_inten_table = maximum(idx - 1, 0); last_inten_table = minimum(cETC1IntenModifierValues, idx + 1); } - + bool check_for_redundant_solution(const etc1_solution_coordinates& coords); bool evaluate_solution_slow(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution); bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution); @@ -1105,7 +1105,7 @@ namespace basisu { etc1_optimizer m_optimizer; }; - + void pack_etc1_solid_color_init(); uint64_t pack_etc1_block_solid_color(etc_block& block, const uint8_t* pColor); @@ -1177,5 +1177,5 @@ namespace basisu uint64_t pack_eac_a8(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX); void pack_eac_a8(eac_a8_block* pBlock, const uint8_t* pPixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX); - + } // namespace basisu diff --git a/encoder/basisu_frontend.cpp b/encoder/basisu_frontend.cpp index 99ac2aa9..102f1bdc 100644 --- a/encoder/basisu_frontend.cpp +++ b/encoder/basisu_frontend.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// TODO: +// TODO: // This code originally supported full ETC1 and ETC1S, so there's some legacy stuff to be cleaned up in here. // Add endpoint tiling support (where we force adjacent blocks to use the same endpoints during quantization), for a ~10% or more increase in bitrate at same SSIM. The backend already supports this. // @@ -40,20 +40,20 @@ namespace basisu const uint32_t BASISU_ENDPOINT_PARENT_CODEBOOK_SIZE = 16; const uint32_t BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_01 = 32; const uint32_t BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_DEFAULT = 16; - + // TODO - How to handle internal verifies in the basisu lib static inline void handle_verify_failure(int line) { error_printf("basisu_frontend: verify check failed at line %i!\n", line); abort(); } - + bool basisu_frontend::init(const params &p) { debug_printf("basisu_frontend::init: Multithreaded: %u, Job pool total threads: %u, NumEndpointClusters: %u, NumSelectorClusters: %u, Perceptual: %u, CompressionLevel: %u\n", p.m_multithreaded, p.m_pJob_pool ? p.m_pJob_pool->get_total_threads() : 0, p.m_max_endpoint_clusters, p.m_max_selector_clusters, p.m_perceptual, p.m_compression_level); - + if ((p.m_max_endpoint_clusters < 1) || (p.m_max_endpoint_clusters > cMaxEndpointClusters)) return false; if ((p.m_max_selector_clusters < 1) || (p.m_max_selector_clusters > cMaxSelectorClusters)) @@ -61,9 +61,9 @@ namespace basisu m_source_blocks.resize(0); append_vector(m_source_blocks, p.m_pSource_blocks, p.m_num_source_blocks); - + m_params = p; - + if (m_params.m_pOpenCL_context) { BASISU_ASSUME(sizeof(cl_pixel_block) == sizeof(pixel_block)); @@ -80,7 +80,7 @@ namespace basisu m_encoded_blocks.resize(m_params.m_num_source_blocks); memset(&m_encoded_blocks[0], 0, m_encoded_blocks.size() * sizeof(m_encoded_blocks[0])); - + m_num_endpoint_codebook_iterations = 1; m_num_selector_codebook_iterations = 1; @@ -150,7 +150,7 @@ namespace basisu if (m_params.m_disable_hierarchical_endpoint_codebooks) m_use_hierarchical_endpoint_codebooks = false; - debug_printf("Endpoint refinement: %u, Hierarchical endpoint codebooks: %u, Hierarchical selector codebooks: %u, Endpoint codebook iters: %u, Selector codebook iters: %u\n", + debug_printf("Endpoint refinement: %u, Hierarchical endpoint codebooks: %u, Hierarchical selector codebooks: %u, Endpoint codebook iters: %u, Selector codebook iters: %u\n", m_endpoint_refinement, m_use_hierarchical_endpoint_codebooks, m_use_hierarchical_selector_codebooks, m_num_endpoint_codebook_iterations, m_num_selector_codebook_iterations); return true; @@ -238,7 +238,7 @@ namespace basisu { BASISU_FRONTEND_VERIFY(validate_endpoint_cluster_hierarchy(false)); } - + eliminate_redundant_or_empty_endpoint_clusters(); if (m_params.m_validate) @@ -252,7 +252,7 @@ namespace basisu if (early_out) break; } - + if (m_params.m_validate) { BASISU_FRONTEND_VERIFY(check_etc1s_constraints()); @@ -268,13 +268,13 @@ namespace basisu if (m_use_hierarchical_selector_codebooks) compute_selector_clusters_within_each_parent_cluster(); - + if (m_params.m_compression_level == 0) { create_optimized_selector_codebook(0); find_optimal_selector_clusters_for_each_block(); - + introduce_special_selector_clusters(); } else @@ -295,7 +295,7 @@ namespace basisu } } } - + optimize_selector_codebook(); if (m_params.m_debug_stats) @@ -321,7 +321,7 @@ namespace basisu const basist::basisu_lowlevel_etc1s_transcoder::endpoint_vec& endpoints = pTranscoder->get_endpoints(); const basist::basisu_lowlevel_etc1s_transcoder::selector_vec& selectors = pTranscoder->get_selectors(); - + m_endpoint_cluster_etc_params.resize(endpoints.size()); for (uint32_t i = 0; i < endpoints.size(); i++) { @@ -420,7 +420,7 @@ namespace basisu const uint32_t last_index = minimum(m_total_blocks, first_index + N); m_params.m_pJob_pool->add_job([this, first_index, last_index, pass] { - + for (uint32_t block_index = first_index; block_index < last_index; block_index++) { const etc_block& blk = pass ? m_encoded_blocks[block_index] : m_etc1_blocks_etc1s[block_index]; @@ -433,7 +433,7 @@ namespace basisu uint64_t best_err = UINT64_MAX; uint32_t best_index = 0; etc_block best_block(trial_blk); - + for (uint32_t i = 0; i < m_endpoint_cluster_etc_params.size(); i++) { if (m_endpoint_cluster_etc_params[i].m_inten_table[0] > blk.get_inten_table(0)) @@ -546,7 +546,7 @@ namespace basisu m_selector_cluster_block_indices.resize(selectors.size()); for (uint32_t block_index = 0; block_index < m_etc1_blocks_etc1s.size(); block_index++) m_selector_cluster_block_indices[m_block_selector_cluster_index[block_index]].push_back(block_index); - + return true; } @@ -580,9 +580,9 @@ namespace basisu const uint32_t new_selector_cluster_index = m_optimized_cluster_selectors.size_u32(); m_optimized_cluster_selectors.push_back(blk); - + vector_ensure_element_is_valid(m_selector_cluster_block_indices, new_selector_cluster_index); - + for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++) { if (m_orig_encoded_blocks[block_index].get_raw_selector_bits() != blk.get_raw_selector_bits()) @@ -590,7 +590,7 @@ namespace basisu // See if using flat selectors actually decreases the block's error. const uint32_t old_selector_cluster_index = m_block_selector_cluster_index[block_index]; - + etc_block cur_blk; const uint32_t endpoint_cluster_index = get_subblock_endpoint_cluster_index(block_index, 0); cur_blk.set_block_color5_etc1s(get_endpoint_cluster_unscaled_color(endpoint_cluster_index, false)); @@ -606,10 +606,10 @@ namespace basisu if (new_err >= cur_err) continue; - + // Change the block to use the new cluster m_block_selector_cluster_index[block_index] = new_selector_cluster_index; - + m_selector_cluster_block_indices[new_selector_cluster_index].push_back(block_index); block_relocated_flags[block_index] = true; @@ -685,7 +685,7 @@ namespace basisu old_to_new[i] = (find_res.first)->second; continue; } - + old_to_new[i] = total_new_entries++; new_to_old.push_back(i); } @@ -714,7 +714,7 @@ namespace basisu { new_selector_cluster_indices[m_block_selector_cluster_index[i]].push_back(i); } - + m_optimized_cluster_selectors.swap(new_optimized_cluster_selectors); m_selector_cluster_block_indices.swap(new_selector_cluster_indices); @@ -725,7 +725,7 @@ namespace basisu for (uint32_t j = 0; j < m_selector_clusters_within_each_parent_cluster[i].size(); j++) m_selector_clusters_within_each_parent_cluster[i][j] = old_to_new[m_selector_clusters_within_each_parent_cluster[i][j]]; } - + debug_printf("optimize_selector_codebook: Before: %u After: %u\n", orig_total_selector_clusters, total_new_entries); } @@ -735,11 +735,11 @@ namespace basisu interval_timer tm; tm.start(); - + m_etc1_blocks_etc1s.resize(m_total_blocks); bool use_cpu = true; - + if (m_params.m_pOpenCL_context) { uint32_t total_perms = 64; @@ -749,7 +749,7 @@ namespace basisu total_perms = 16; else if (m_params.m_compression_level == BASISU_MAX_COMPRESSION_LEVEL) total_perms = OPENCL_ENCODE_ETC1S_MAX_PERMS; - + bool status = opencl_encode_etc1s_blocks(m_params.m_pOpenCL_context, m_etc1_blocks_etc1s.data(), m_params.m_perceptual, total_perms); if (status) use_cpu = false; @@ -760,7 +760,7 @@ namespace basisu m_opencl_failed = true; } } - + if (use_cpu) { const uint32_t N = 4096; @@ -817,16 +817,16 @@ namespace basisu m_params.m_pJob_pool->wait_for_all(); } // use_cpu - + debug_printf("init_etc1_images: Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); } void basisu_frontend::init_endpoint_training_vectors() { debug_printf("init_endpoint_training_vectors\n"); - + vec6F_quantizer::array_of_weighted_training_vecs &training_vecs = m_endpoint_clusterizer.get_training_vecs(); - + training_vecs.resize(m_total_blocks * 2); const uint32_t N = 16384; @@ -838,12 +838,12 @@ namespace basisu m_params.m_pJob_pool->add_job( [this, first_index, last_index, &training_vecs] { for (uint32_t block_index = first_index; block_index < last_index; block_index++) - { + { const etc_block &blk = m_etc1_blocks_etc1s[block_index]; color_rgba block_colors[2]; blk.get_block_low_high_colors(block_colors, 0); - + vec6F v; v[0] = block_colors[0].r * (1.0f / 255.0f); v[1] = block_colors[0].g * (1.0f / 255.0f); @@ -851,7 +851,7 @@ namespace basisu v[3] = block_colors[1].r * (1.0f / 255.0f); v[4] = block_colors[1].g * (1.0f / 255.0f); v[5] = block_colors[1].b * (1.0f / 255.0f); - + training_vecs[block_index * 2 + 0] = std::make_pair(v, 1); training_vecs[block_index * 2 + 1] = std::make_pair(v, 1); @@ -919,12 +919,12 @@ namespace basisu for (uint32_t cluster_index = 0; cluster_index < m_endpoint_clusters.size(); cluster_index++) { const uint_vec &cluster = m_endpoint_clusters[cluster_index]; - + uint32_t parent_cluster_index = 0; for (uint32_t j = 0; j < cluster.size(); j++) { const uint32_t block_index = cluster[j] >> 1; - + BASISU_FRONTEND_VERIFY(block_index < m_block_parent_endpoint_cluster.size()); if (!j) @@ -938,7 +938,7 @@ namespace basisu } } } - + if (m_params.m_debug_stats) debug_printf("Total endpoint clusters: %u, parent clusters: %u\n", m_endpoint_clusters.size_u32(), m_endpoint_parent_clusters.size_u32()); } @@ -996,7 +996,7 @@ namespace basisu BASISU_FRONTEND_VERIFY(cluster_indices.size()); vector_sort(cluster_indices); - + auto last = std::unique(cluster_indices.begin(), cluster_indices.end()); cluster_indices.erase(last, cluster_indices.end()); } @@ -1009,8 +1009,8 @@ namespace basisu const uint32_t N = 512; for (uint32_t cluster_index_iter = 0; cluster_index_iter < m_endpoint_clusters.size(); cluster_index_iter += N) { - const uint32_t first_index = cluster_index_iter; - const uint32_t last_index = minimum(m_endpoint_clusters.size_u32(), cluster_index_iter + N); + const uint32_t first_index = cluster_index_iter; + const uint32_t last_index = minimum(m_endpoint_clusters.size_u32(), cluster_index_iter + N); m_params.m_pJob_pool->add_job( [this, first_index, last_index] { @@ -1039,7 +1039,7 @@ namespace basisu const endpoint_cluster_etc_params &etc_params = m_endpoint_cluster_etc_params[cluster_index]; assert(etc_params.m_valid); - + color_rgba block_colors[4]; etc_block::get_block_colors5(block_colors, etc_params.m_color_unscaled[0], etc_params.m_inten_table[0], true); @@ -1071,7 +1071,7 @@ namespace basisu quant_err.m_cluster_subblock_index = cluster_indices_iter; quant_err.m_block_index = block_index; quant_err.m_subblock_index = subblock_index; - + { std::lock_guard lock(m_lock); @@ -1088,7 +1088,7 @@ namespace basisu vector_sort(m_subblock_endpoint_quant_err_vec); } - + void basisu_frontend::introduce_new_endpoint_clusters() { debug_printf("introduce_new_endpoint_clusters\n"); @@ -1159,9 +1159,9 @@ namespace basisu BASISU_FRONTEND_VERIFY(cluster_sizes[subblock_to_move.m_cluster_index] >= 2); cluster_sizes[subblock_to_move.m_cluster_index] -= 2; - + ignore_cluster.insert(subblock_to_move.m_cluster_index); - + total_new_clusters++; num_new_endpoint_clusters--; @@ -1197,23 +1197,23 @@ namespace basisu inline std::size_t operator()(const color_rgba& k) const { uint32_t v = *(const uint32_t*)&k; - + //return bitmix32(v); - + //v ^= (v << 10); //v ^= (v >> 12); - + return v; } }; - + // Given each endpoint cluster, gather all the block pixels which are in that cluster and compute optimized ETC1S endpoints for them. // TODO: Don't optimize endpoint clusters which haven't changed. // If step>=1, we check to ensure the new endpoint values actually decrease quantization error. void basisu_frontend::generate_endpoint_codebook(uint32_t step) { debug_printf("generate_endpoint_codebook\n"); - + interval_timer tm; tm.start(); @@ -1226,7 +1226,7 @@ namespace basisu const uint32_t total_clusters = (uint32_t)m_endpoint_clusters.size(); basisu::vector pixel_clusters(total_clusters); - + std::vector input_pixels; input_pixels.reserve(m_total_blocks * 16); @@ -1259,7 +1259,7 @@ namespace basisu pixel_weights.resize(pixel_weights.size() + total_pixels); uint64_t dst_ofs = first_pixel_index; - + uint64_t total_r = 0, total_g = 0, total_b = 0; for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++) { @@ -1311,7 +1311,7 @@ namespace basisu const uint64_t first_pixel_index = input_pixels.size(); uint32_t prev_color = 0, cur_weight = 0; - + for (uint32_t i = 0; i < colors.size(); i++) { uint32_t cur_color = pSorted[i]; @@ -1359,7 +1359,7 @@ namespace basisu uint32_t *pPrev_weight = nullptr; color_rgba prev_color; - + { color_rgba cur_color = pBlock_pixels[0]; auto res = color_hasher.insert(cur_color, 0); @@ -1371,7 +1371,7 @@ namespace basisu prev_color = cur_color; pPrev_weight = &(res.first)->second; } - + for (uint32_t i = 1; i < 16; i++) { color_rgba cur_color = pBlock_pixels[i]; @@ -1404,9 +1404,9 @@ namespace basisu input_pixels.resize(first_pixel_index + total_unique_pixels); pixel_weights.resize(first_pixel_index + total_unique_pixels); - + uint32_t j = 0; - + for (auto it = color_hasher.begin(); it != color_hasher.end(); ++it, ++j) { input_pixels[first_pixel_index + j] = it->first; @@ -1456,7 +1456,7 @@ namespace basisu for (uint32_t old_cluster_index = 0; old_cluster_index < m_endpoint_clusters.size(); old_cluster_index++) { const uint32_t new_cluster_index = sorted_cluster_indices_old_to_new[old_cluster_index]; - + const etc_block& blk = output_blocks[new_cluster_index]; endpoint_cluster_etc_params& prev_etc_params = m_endpoint_cluster_etc_params[old_cluster_index]; @@ -1464,7 +1464,7 @@ namespace basisu prev_etc_params.m_valid = true; etc_block::unpack_color5(prev_etc_params.m_color_unscaled[0], blk.get_base5_color(), false); prev_etc_params.m_inten_table[0] = blk.get_inten_table(0); - prev_etc_params.m_color_error[0] = 0; // dummy value - we don't actually use this + prev_etc_params.m_color_error[0] = 0; // dummy value - we don't actually use this } use_cpu = false; @@ -1647,7 +1647,7 @@ namespace basisu uint32_t basisu_frontend::refine_endpoint_clusterization() { debug_printf("refine_endpoint_clusterization\n"); - + if (m_use_hierarchical_endpoint_codebooks) compute_endpoint_clusters_within_each_parent_cluster(); @@ -1668,9 +1668,9 @@ namespace basisu } // cluster_indices_iter } - + //---------------------------------------------------------- - + // Create a new endpoint clusterization interval_timer tm; @@ -1687,7 +1687,7 @@ namespace basisu const uint32_t total_parent_clusters = (uint32_t)m_endpoint_clusters_within_each_parent_cluster.size(); basisu::vector cl_block_info_structs(m_total_blocks); - + // the size of each parent cluster, in total clusters uint_vec parent_cluster_sizes(total_parent_clusters); for (uint32_t i = 0; i < total_parent_clusters; i++) @@ -1701,7 +1701,7 @@ namespace basisu cur_ofs += parent_cluster_sizes[i]; } - + // Note: total_actual_endpoint_clusters is not necessarly equal to m_endpoint_clusters.size(), because clusters may live in multiple parent clusters after the first refinement step. BASISU_FRONTEND_VERIFY(cur_ofs >= m_endpoint_clusters.size()); const uint32_t total_actual_endpoint_clusters = cur_ofs; @@ -1727,11 +1727,11 @@ namespace basisu cl_endpoint_cluster_structs[dst_ofs + j].m_cluster_index = (uint16_t)endpoint_cluster_index; } } - + for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++) { const uint32_t block_parent_endpoint_cluster_index = m_block_parent_endpoint_cluster[block_index]; - + cl_block_info_structs[block_index].m_num_clusters = (uint16_t)(parent_cluster_sizes[block_parent_endpoint_cluster_index]); cl_block_info_structs[block_index].m_first_cluster_ofs = (uint16_t)(first_parent_cluster_ofs[block_parent_endpoint_cluster_index]); @@ -1746,7 +1746,7 @@ namespace basisu uint_vec sorted_block_indices(m_total_blocks); indirect_sort(m_total_blocks, sorted_block_indices.data(), block_cluster_indices.data()); - + bool status = opencl_refine_endpoint_clusterization( m_params.m_pOpenCL_context, cl_block_info_structs.data(), @@ -1902,7 +1902,7 @@ namespace basisu break; } } // j - + best_cluster_indices[block_index] = best_cluster_index; } // block_index @@ -1912,9 +1912,9 @@ namespace basisu } // block_index_iter m_params.m_pJob_pool->wait_for_all(); - + } // use_cpu - + debug_printf("refine_endpoint_clusterization time: %3.3f secs\n", tm.get_elapsed_secs()); basisu::vector > optimized_endpoint_clusters(m_endpoint_clusters.size()); @@ -1957,7 +1957,7 @@ namespace basisu basisu::vector > new_endpoint_clusters(m_endpoint_clusters.size()); basisu::vector new_subblock_etc_params(m_endpoint_clusters.size()); - + for (uint32_t i = 0; i < m_endpoint_clusters.size(); i++) { uint32_t j = sorted_endpoint_cluster_indices[i]; @@ -1972,7 +1972,7 @@ namespace basisu new_endpoint_clusters.resize(0); new_subblock_etc_params.resize(0); - + for (int i = 0; i < (int)m_endpoint_clusters.size(); ) { if (!m_endpoint_clusters[i].size()) @@ -1990,7 +1990,7 @@ namespace basisu new_endpoint_clusters.push_back(m_endpoint_clusters[i]); new_subblock_etc_params.push_back(m_endpoint_cluster_etc_params[i]); - + for (int k = i + 1; k < j; k++) { append_vector(new_endpoint_clusters.back(), m_endpoint_clusters[k]); @@ -1998,7 +1998,7 @@ namespace basisu i = j; } - + if (m_endpoint_clusters.size() != new_endpoint_clusters.size()) { if (m_params.m_debug_stats) @@ -2013,7 +2013,7 @@ namespace basisu void basisu_frontend::create_initial_packed_texture() { debug_printf("create_initial_packed_texture\n"); - + interval_timer tm; tm.start(); @@ -2026,7 +2026,7 @@ namespace basisu for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++) { uint32_t cluster0 = m_block_endpoint_clusters_indices[block_index][0]; - + const color_rgba& color_unscaled = m_endpoint_cluster_etc_params[cluster0].m_color_unscaled[0]; uint32_t inten = m_endpoint_cluster_etc_params[cluster0].m_inten_table[0]; @@ -2088,7 +2088,7 @@ namespace basisu m_params.m_pJob_pool->wait_for_all(); } // use_cpu - + m_orig_encoded_blocks = m_encoded_blocks; debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); @@ -2105,7 +2105,7 @@ namespace basisu for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++) { const uint32_t block_index = cluster_indices[cluster_indices_iter]; - + block_selector_cluster_indices[block_index] = cluster_index; } // cluster_indices_iter @@ -2130,7 +2130,7 @@ namespace basisu BASISU_FRONTEND_VERIFY(cluster_indices.size()); vector_sort(cluster_indices); - + auto last = std::unique(cluster_indices.begin(), cluster_indices.end()); cluster_indices.erase(last, cluster_indices.end()); } @@ -2139,11 +2139,11 @@ namespace basisu void basisu_frontend::generate_selector_clusters() { debug_printf("generate_selector_clusters\n"); - + typedef tree_vector_quant vec16F_clusterizer; - + vec16F_clusterizer::array_of_weighted_training_vecs training_vecs(m_total_blocks); - + const uint32_t N = 4096; for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N) { @@ -2171,10 +2171,10 @@ namespace basisu const uint32_t cColorDistToWeight = 300; const uint32_t cMaxWeight = 4096; uint32_t weight = clamp(dist / cColorDistToWeight, 1, cMaxWeight); - + training_vecs[block_index].first = v; training_vecs[block_index].second = weight; - + } // block_index } ); @@ -2235,7 +2235,7 @@ namespace basisu for (uint32_t cluster_index = 0; cluster_index < m_selector_cluster_block_indices.size(); cluster_index++) { const uint_vec &cluster = m_selector_cluster_block_indices[cluster_index]; - + uint32_t parent_cluster_index = 0; for (uint32_t j = 0; j < cluster.size(); j++) { @@ -2267,7 +2267,7 @@ namespace basisu debug_printf("Total selector clusters (from m_selector_cluster_block_indices.size()): %u\n", (uint32_t)m_selector_cluster_block_indices.size()); m_optimized_cluster_selectors.resize(total_selector_clusters); - + // For each selector codebook entry, and for each of the 4x4 selectors, determine which selector minimizes the error across all the blocks that use that quantized selector. const uint32_t N = 256; for (uint32_t cluster_index_iter = 0; cluster_index_iter < total_selector_clusters; cluster_index_iter += N) @@ -2351,7 +2351,7 @@ namespace basisu m_params.m_pJob_pool->wait_for_all(); debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); - + if (m_params.m_debug_images) { uint32_t max_selector_cluster_size = 0; @@ -2377,7 +2377,7 @@ namespace basisu uint32_t block_index = cluster_block_indices[i]; const etc_block &blk = m_orig_encoded_blocks[block_index]; - + for (uint32_t y = 0; y < 4; y++) for (uint32_t x = 0; x < 4; x++) selector_cluster_vis.set_clipped(x_spacer_len + x + 5 * i, selector_cluster_index * 5 + y, color_rgba((blk.get_selector(x, y) * 255) / 3)); @@ -2399,7 +2399,7 @@ namespace basisu interval_timer tm; tm.start(); - + if (m_params.m_validate) { // Sanity checks @@ -2414,7 +2414,7 @@ namespace basisu } m_block_selector_cluster_index.resize(m_total_blocks); - + if (m_params.m_compression_level == 0) { // Just leave the blocks in their original selector clusters. @@ -2435,7 +2435,7 @@ namespace basisu return; } - + bool use_cpu = true; if ((m_params.m_pOpenCL_context) && m_use_hierarchical_selector_codebooks) @@ -2444,17 +2444,17 @@ namespace basisu basisu::vector selector_structs; selector_structs.reserve(m_optimized_cluster_selectors.size()); - + uint_vec parent_selector_cluster_offsets(num_parent_clusters); uint_vec selector_cluster_indices; selector_cluster_indices.reserve(m_optimized_cluster_selectors.size()); - + uint32_t cur_ofs = 0; for (uint32_t parent_index = 0; parent_index < num_parent_clusters; parent_index++) { parent_selector_cluster_offsets[parent_index] = cur_ofs; - + for (uint32_t j = 0; j < m_selector_clusters_within_each_parent_cluster[parent_index].size(); j++) { const uint32_t selector_cluster_index = m_selector_clusters_within_each_parent_cluster[parent_index][j]; @@ -2464,7 +2464,7 @@ namespace basisu sel_bits |= (m_optimized_cluster_selectors[selector_cluster_index].get_selector(p & 3, p >> 2) << (p * 2)); selector_structs.enlarge(1)->m_packed_selectors = sel_bits; - + selector_cluster_indices.push_back(selector_cluster_index); } @@ -2472,7 +2472,7 @@ namespace basisu } const uint32_t total_input_selectors = cur_ofs; - + basisu::vector block_structs(m_total_blocks); for (uint32_t i = 0; i < m_total_blocks; i++) { @@ -2496,7 +2496,7 @@ namespace basisu selector_cluster_indices.data(), output_selector_cluster_indices.data(), m_params.m_perceptual); - + if (!status) { error_printf("basisu_frontend::find_optimal_selector_clusters_for_each_block: opencl_find_optimal_selector_clusters_for_each_block() failed! Using CPU.\n"); @@ -2510,7 +2510,7 @@ namespace basisu m_selector_cluster_block_indices[i].resize(0); m_selector_cluster_block_indices[i].reserve(128); } - + for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++) { etc_block& blk = m_encoded_blocks[block_index]; @@ -2542,7 +2542,7 @@ namespace basisu } } } - + const uint32_t N = 2048; for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N) { @@ -2550,13 +2550,13 @@ namespace basisu const uint32_t last_index = minimum(m_total_blocks, first_index + N); m_params.m_pJob_pool->add_job( [this, first_index, last_index, &unpacked_optimized_cluster_selectors] { - + int prev_best_cluster_index = 0; for (uint32_t block_index = first_index; block_index < last_index; block_index++) { const pixel_block& block = get_source_pixel_block(block_index); - + etc_block& blk = m_encoded_blocks[block_index]; if ((block_index > first_index) && (block == get_source_pixel_block(block_index - 1))) @@ -2564,18 +2564,18 @@ namespace basisu blk.set_raw_selector_bits(m_optimized_cluster_selectors[prev_best_cluster_index].get_raw_selector_bits()); m_block_selector_cluster_index[block_index] = prev_best_cluster_index; - + continue; } - + const color_rgba* pBlock_pixels = block.get_ptr(); - + color_rgba trial_block_colors[4]; blk.get_block_colors_etc1s(trial_block_colors); // precompute errors for the i-th block pixel and selector sel: [sel][i] uint32_t trial_errors[4][16]; - + if (m_params.m_perceptual) { for (uint32_t sel = 0; sel < 4; ++sel) @@ -2652,7 +2652,7 @@ namespace basisu for (uint32_t cluster_iter = 0; cluster_iter < total_clusters; cluster_iter++) { const uint32_t cluster_index = m_use_hierarchical_selector_codebooks ? (*pCluster_indices)[cluster_iter] : cluster_iter; - + const uint8_t* pSels = &unpacked_optimized_cluster_selectors[cluster_index * 16]; uint64_t trial_err = (uint64_t)trial_errors[pSels[0]][0] + trial_errors[pSels[1]][1] + trial_errors[pSels[2]][2] + trial_errors[pSels[3]][3]; @@ -2685,7 +2685,7 @@ namespace basisu m_block_selector_cluster_index[block_index] = best_cluster_index; prev_best_cluster_index = best_cluster_index; - + } // block_index } ); @@ -2693,7 +2693,7 @@ namespace basisu } // block_index_iter m_params.m_pJob_pool->wait_for_all(); - + for (uint32_t i = 0; i < m_selector_cluster_block_indices.size(); i++) { m_selector_cluster_block_indices[i].resize(0); @@ -2707,7 +2707,7 @@ namespace basisu vector_ensure_element_is_valid(m_selector_cluster_block_indices, best_cluster_index); m_selector_cluster_block_indices[best_cluster_index].push_back(block_index); } - + } // if (use_cpu) debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); @@ -2717,7 +2717,7 @@ namespace basisu uint32_t basisu_frontend::refine_block_endpoints_given_selectors() { debug_printf("refine_block_endpoints_given_selectors\n"); - + for (int block_index = 0; block_index < static_cast(m_total_blocks); block_index++) { //uint32_t selector_cluster = m_block_selector_cluster_index(block_x, block_y); @@ -2898,7 +2898,7 @@ namespace basisu if (m_params.m_debug_stats) debug_printf("Total subblock endpoints refined: %u (%3.1f%%)\n", total_subblocks_refined, total_subblocks_refined * 100.0f / total_subblocks_examined); - + return total_subblocks_refined; } @@ -2990,7 +2990,7 @@ namespace basisu } // The backend has remapped the block endpoints while optimizing the output symbols for better rate distortion performance, so let's go and reoptimize the endpoint codebook. - // This is currently the only place where the backend actually goes and changes the quantization and calls the frontend to fix things up. + // This is currently the only place where the backend actually goes and changes the quantization and calls the frontend to fix things up. // This is basically a bottom up clusterization stage, where some leaves can be combined. void basisu_frontend::reoptimize_remapped_endpoints(const uint_vec &new_block_endpoints, int_vec &old_to_new_endpoint_cluster_indices, bool optimize_final_codebook, uint_vec *pBlock_selector_indices) { @@ -3002,12 +3002,12 @@ namespace basisu basisu::vector cluster_valid(new_endpoint_cluster_block_indices.size()); basisu::vector cluster_improved(new_endpoint_cluster_block_indices.size()); - + const uint32_t N = 256; for (uint32_t cluster_index_iter = 0; cluster_index_iter < new_endpoint_cluster_block_indices.size(); cluster_index_iter += N) { - const uint32_t first_index = cluster_index_iter; - const uint32_t last_index = minimum((uint32_t)new_endpoint_cluster_block_indices.size(), cluster_index_iter + N); + const uint32_t first_index = cluster_index_iter; + const uint32_t last_index = minimum((uint32_t)new_endpoint_cluster_block_indices.size(), cluster_index_iter + N); m_params.m_pJob_pool->add_job( [this, first_index, last_index, &cluster_improved, &cluster_valid, &new_endpoint_cluster_block_indices, &pBlock_selector_indices ] { @@ -3027,13 +3027,13 @@ namespace basisu blk.set_block_color5_etc1s(get_endpoint_cluster_unscaled_color(cluster_index, false)); blk.set_inten_tables_etc1s(get_endpoint_cluster_inten_table(cluster_index, false)); blk.set_flip_bit(true); - + uint64_t cur_err = 0; for (uint32_t cluster_block_indices_iter = 0; cluster_block_indices_iter < cluster_block_indices.size(); cluster_block_indices_iter++) { const uint32_t block_index = cluster_block_indices[cluster_block_indices_iter]; - + const color_rgba *pBlock_pixels = get_source_pixel_block(block_index).get_ptr(); memcpy(&cluster_pixels[cluster_block_indices_iter * 16], pBlock_pixels, 16 * sizeof(color_rgba)); @@ -3045,14 +3045,14 @@ namespace basisu blk.set_raw_selector_bits(blk_selectors.get_raw_selector_bits()); cur_err += blk.evaluate_etc1_error(pBlock_pixels, m_params.m_perceptual); - + for (uint32_t y = 0; y < 4; y++) for (uint32_t x = 0; x < 4; x++) force_selectors[cluster_block_indices_iter * 16 + x + y * 4] = static_cast(blk_selectors.get_selector(x, y)); } endpoint_cluster_etc_params new_endpoint_cluster_etc_params; - + { etc1_optimizer optimizer; etc1_solution_coordinates solutions[2]; @@ -3091,7 +3091,7 @@ namespace basisu if (new_endpoint_cluster_etc_params.m_color_error[0] < cur_err) { m_endpoint_cluster_etc_params[cluster_index] = new_endpoint_cluster_etc_params; - + cluster_improved[cluster_index] = true; } @@ -3104,13 +3104,13 @@ namespace basisu } // cluster_index_iter m_params.m_pJob_pool->wait_for_all(); - + uint32_t total_unused_clusters = 0; uint32_t total_improved_clusters = 0; - + old_to_new_endpoint_cluster_indices.resize(m_endpoint_clusters.size()); vector_set_all(old_to_new_endpoint_cluster_indices, -1); - + int total_new_endpoint_clusters = 0; for (uint32_t old_cluster_index = 0; old_cluster_index < m_endpoint_clusters.size(); old_cluster_index++) @@ -3145,7 +3145,7 @@ namespace basisu for (uint32_t block_index = 0; block_index < new_block_endpoints.size(); block_index++) { const uint32_t old_endpoint_cluster_index = new_block_endpoints[block_index]; - + const int new_endpoint_cluster_index = old_to_new_endpoint_cluster_indices[old_endpoint_cluster_index]; BASISU_FRONTEND_VERIFY(new_endpoint_cluster_index >= 0); @@ -3158,13 +3158,13 @@ namespace basisu new_endpoint_cluster_etc_params[new_endpoint_cluster_index].m_subblocks.push_back(block_index * 2 + 0); new_endpoint_cluster_etc_params[new_endpoint_cluster_index].m_subblocks.push_back(block_index * 2 + 1); - + m_block_endpoint_clusters_indices[block_index][0] = new_endpoint_cluster_index; m_block_endpoint_clusters_indices[block_index][1] = new_endpoint_cluster_index; } debug_printf("basisu_frontend::reoptimize_remapped_endpoints: stage 2\n"); - + m_endpoint_clusters = new_endpoint_clusters; m_endpoint_cluster_etc_params = new_endpoint_cluster_etc_params; @@ -3200,7 +3200,7 @@ namespace basisu debug_printf("Final (post-RDO) endpoint clusters: %u\n", m_endpoint_clusters.size()); } - + //debug_printf("validate_output: %u\n", validate_output()); } @@ -3228,7 +3228,7 @@ namespace basisu // If the endpoint cluster lives in more than one parent node, that's wrong. if (subblock_parent_indices[subblock_index] != -1) return false; - + subblock_parent_indices[subblock_index] = parent_index; } } @@ -3252,7 +3252,7 @@ namespace basisu if (subblock_cluster_indices[subblock_index] != -1) return false; - + subblock_cluster_indices[subblock_index] = cluster_index; // There are transformations on the endpoint clusters that can break the strict tree requirement @@ -3266,7 +3266,7 @@ namespace basisu } } } - + // Make sure all endpoint clusters are present in the parent cluster. for (uint32_t i = 0; i < subblock_cluster_indices.size(); i++) { @@ -3291,7 +3291,7 @@ namespace basisu #define CHECK(x) BASISU_FRONTEND_VERIFY(x); CHECK(get_output_block(block_index).get_flip_bit() == true); - + const bool diff_flag = get_diff_flag(block_index); CHECK(diff_flag == true); @@ -3305,11 +3305,11 @@ namespace basisu // basisu only supports ETC1S, so these must be equal. CHECK(endpoint_cluster0_index == endpoint_cluster1_index); - + CHECK(blk.set_block_color5_check(get_endpoint_cluster_unscaled_color(endpoint_cluster0_index, false), get_endpoint_cluster_unscaled_color(endpoint_cluster1_index, false))); CHECK(get_endpoint_cluster_color_is_used(endpoint_cluster0_index, false)); - + blk.set_inten_table(0, get_endpoint_cluster_inten_table(endpoint_cluster0_index, false)); blk.set_inten_table(1, get_endpoint_cluster_inten_table(endpoint_cluster1_index, false)); @@ -3329,7 +3329,7 @@ namespace basisu CHECK(rdo_output_block.get_base5_color() == blk.get_base5_color()); CHECK(rdo_output_block.get_delta3_color() == blk.get_delta3_color()); CHECK(rdo_output_block.get_raw_selector_bits() == blk.get_raw_selector_bits()); - + #undef CHECK } @@ -3382,4 +3382,3 @@ namespace basisu } } // namespace basisu - diff --git a/encoder/basisu_frontend.h b/encoder/basisu_frontend.h index 69fc8d8e..18ff5b66 100644 --- a/encoder/basisu_frontend.h +++ b/encoder/basisu_frontend.h @@ -61,7 +61,7 @@ namespace basisu enum { cMaxEndpointClusters = 16128, - + cMaxSelectorClusters = 16128, }; @@ -101,12 +101,12 @@ namespace basisu bool m_validate; bool m_multithreaded; bool m_disable_hierarchical_endpoint_codebooks; - + basist::basis_texture_type m_tex_type; const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks; - + opencl_context_ptr m_pOpenCL_context; - + job_pool *m_pJob_pool; }; @@ -143,12 +143,12 @@ namespace basisu uint32_t get_total_selector_clusters() const { return static_cast(m_selector_cluster_block_indices.size()); } uint32_t get_block_selector_cluster_index(uint32_t block_index) const { return m_block_selector_cluster_index[block_index]; } const etc_block &get_selector_cluster_selector_bits(uint32_t cluster_index) const { return m_optimized_cluster_selectors[cluster_index]; } - + // Returns block indices using each selector cluster const uint_vec &get_selector_cluster_block_indices(uint32_t selector_cluster_index) const { return m_selector_cluster_block_indices[selector_cluster_index]; } void dump_debug_image(const char *pFilename, uint32_t first_block, uint32_t num_blocks_x, uint32_t num_blocks_y, bool output_blocks); - + void reoptimize_remapped_endpoints(const uint_vec &new_block_endpoints, int_vec &old_to_new_endpoint_cluster_indices, bool optimize_final_codebook, uint_vec *pBlock_selector_indices = nullptr); bool get_opencl_failed() const { return m_opencl_failed; } @@ -170,15 +170,15 @@ namespace basisu // The quantized ETC1S texture. etc_block_vec m_encoded_blocks; - + // Quantized blocks after endpoint quant, but before selector quant - etc_block_vec m_orig_encoded_blocks; - + etc_block_vec m_orig_encoded_blocks; + // Full quality ETC1S texture etc_block_vec m_etc1_blocks_etc1s; - + typedef vec<6, float> vec6F; - + // Endpoint clusterizer typedef tree_vector_quant vec6F_quantizer; vec6F_quantizer m_endpoint_clusterizer; @@ -187,16 +187,16 @@ namespace basisu basisu::vector m_endpoint_clusters; // Array of subblock indices for each parent endpoint cluster - // Note: Initially, each endpoint cluster will only live in a single parent cluster, in a shallow tree. + // Note: Initially, each endpoint cluster will only live in a single parent cluster, in a shallow tree. // As the endpoint clusters are manipulated this constraint gets broken. basisu::vector m_endpoint_parent_clusters; - + // Each block's parent endpoint cluster index - uint8_vec m_block_parent_endpoint_cluster; + uint8_vec m_block_parent_endpoint_cluster; // Array of endpoint cluster indices for each parent endpoint cluster basisu::vector m_endpoint_clusters_within_each_parent_cluster; - + struct endpoint_cluster_etc_params { endpoint_cluster_etc_params() @@ -266,13 +266,13 @@ namespace basisu }; typedef basisu::vector cluster_subblock_etc_params_vec; - - // Each endpoint cluster's ETC1S parameters + + // Each endpoint cluster's ETC1S parameters cluster_subblock_etc_params_vec m_endpoint_cluster_etc_params; // The endpoint cluster index used by each ETC1 subblock. basisu::vector m_block_endpoint_clusters_indices; - + // The block(s) within each selector cluster // Note: If you add anything here that uses selector cluster indicies, be sure to update optimize_selector_codebook()! basisu::vector m_selector_cluster_block_indices; @@ -282,13 +282,13 @@ namespace basisu // The block(s) within each parent selector cluster. basisu::vector m_selector_parent_cluster_block_indices; - + // Each block's parent selector cluster uint8_vec m_block_parent_selector_cluster; // Array of selector cluster indices for each parent selector cluster basisu::vector m_selector_clusters_within_each_parent_cluster; - + // Each block's selector cluster index basisu::vector m_block_selector_cluster_index; diff --git a/encoder/basisu_gpu_texture.cpp b/encoder/basisu_gpu_texture.cpp index 339218fc..329139c0 100644 --- a/encoder/basisu_gpu_texture.cpp +++ b/encoder/basisu_gpu_texture.cpp @@ -36,9 +36,9 @@ namespace basisu const eac_a8_block *pBlock = static_cast(pBlock_bits); const int8_t *pTable = g_etc2_eac_tables[pBlock->m_table]; - + const uint64_t selector_bits = pBlock->get_selector_bits(); - + const int32_t base = pBlock->m_base; const int32_t mul = pBlock->m_multiplier; @@ -72,16 +72,16 @@ namespace basisu uint8_t m_low_color[cTotalEndpointBytes]; uint8_t m_high_color[cTotalEndpointBytes]; uint8_t m_selectors[cTotalSelectorBytes]; - + inline uint32_t get_high_color() const { return m_high_color[0] | (m_high_color[1] << 8U); } inline uint32_t get_low_color() const { return m_low_color[0] | (m_low_color[1] << 8U); } - static void unpack_color(uint32_t c, uint32_t &r, uint32_t &g, uint32_t &b) + static void unpack_color(uint32_t c, uint32_t &r, uint32_t &g, uint32_t &b) { r = (c >> 11) & 31; g = (c >> 5) & 63; b = c & 31; - + r = (r << 3) | (r >> 2); g = (g << 2) | (g >> 4); b = (b << 3) | (b >> 2); @@ -127,9 +127,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0] = c[pBlock->get_selector(0, y)]; - pPixels[1] = c[pBlock->get_selector(1, y)]; - pPixels[2] = c[pBlock->get_selector(2, y)]; + pPixels[0] = c[pBlock->get_selector(0, y)]; + pPixels[1] = c[pBlock->get_selector(1, y)]; + pPixels[2] = c[pBlock->get_selector(2, y)]; pPixels[3] = c[pBlock->get_selector(3, y)]; } } @@ -137,9 +137,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); - pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); - pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); + pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); + pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); + pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); pPixels[3].set_rgb(c[pBlock->get_selector(3, y)]); } } @@ -206,9 +206,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0] = c[pBlock->get_selector(0, y)]; - pPixels[1] = c[pBlock->get_selector(1, y)]; - pPixels[2] = c[pBlock->get_selector(2, y)]; + pPixels[0] = c[pBlock->get_selector(0, y)]; + pPixels[1] = c[pBlock->get_selector(1, y)]; + pPixels[2] = c[pBlock->get_selector(2, y)]; pPixels[3] = c[pBlock->get_selector(3, y)]; } } @@ -216,9 +216,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); - pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); - pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); + pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); + pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); + pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); pPixels[3].set_rgb(c[pBlock->get_selector(3, y)]); } } @@ -244,7 +244,7 @@ namespace basisu c[0].set_noclamp_rgba(r0, g0, b0, 255); c[1].set_noclamp_rgba(r1, g1, b1, 255); - + bool used_punchthrough = false; if (l > h) @@ -263,9 +263,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0] = c[pBlock->get_selector(0, y)]; - pPixels[1] = c[pBlock->get_selector(1, y)]; - pPixels[2] = c[pBlock->get_selector(2, y)]; + pPixels[0] = c[pBlock->get_selector(0, y)]; + pPixels[1] = c[pBlock->get_selector(1, y)]; + pPixels[2] = c[pBlock->get_selector(2, y)]; pPixels[3] = c[pBlock->get_selector(3, y)]; } } @@ -273,9 +273,9 @@ namespace basisu { for (uint32_t y = 0; y < 4; y++, pPixels += 4) { - pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); - pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); - pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); + pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]); + pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]); + pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]); pPixels[3].set_rgb(c[pBlock->get_selector(3, y)]); } } @@ -298,7 +298,7 @@ namespace basisu inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); } inline uint64_t get_selector_bits() const - { + { return ((uint64_t)((uint32_t)m_selectors[0] | ((uint32_t)m_selectors[1] << 8U) | ((uint32_t)m_selectors[2] << 16U) | ((uint32_t)m_selectors[3] << 24U))) | (((uint64_t)m_selectors[4]) << 32U) | (((uint64_t)m_selectors[5]) << 40U); @@ -309,7 +309,7 @@ namespace basisu assert((x < 4U) && (y < 4U)); return (selector_bits >> (((y * 4) + x) * cBC4SelectorBits)) & (cMaxSelectorValues - 1); } - + static inline uint32_t get_block_values6(uint8_t *pDst, uint32_t l, uint32_t h) { pDst[0] = static_cast(l); @@ -364,7 +364,7 @@ namespace basisu pPixels[stride * 3] = sel_values[pBlock->get_selector(3, y, selector_bits)]; } } - + // Returns false if the block uses 3-color punchthrough alpha mode, which isn't supported on some GPU's for BC3. bool unpack_bc3(const void *pBlock_bits, color_rgba *pPixels) { @@ -374,7 +374,7 @@ namespace basisu success = false; unpack_bc4(pBlock_bits, &pPixels[0].a, sizeof(color_rgba)); - + return success; } @@ -384,7 +384,7 @@ namespace basisu unpack_bc4(pBlock_bits, &pPixels[0].r, sizeof(color_rgba)); unpack_bc4((const uint8_t *)pBlock_bits + sizeof(bc4_block), &pPixels[0].g, sizeof(color_rgba)); } - + //------------------------------------------------------------------------------------------------ // ATC isn't officially documented, so I'm assuming these references: // http://www.guildsoftware.com/papers/2012.Converting.DXTC.to.ATC.pdf @@ -432,9 +432,9 @@ namespace basisu for (uint32_t i = 0; i < 16; i++) { const uint32_t s = sels & 3; - + pPixels[i] = c[s]; - + sels >>= 2; } } @@ -457,12 +457,12 @@ namespace basisu case 2: return bc7_interp2(l, h, w); case 3: return bc7_interp3(l, h, w); case 4: return bc7_interp4(l, h, w); - default: + default: break; } return 0; } - + bool unpack_bc7_mode0_2(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels) { //const uint32_t SUBSETS = 3; @@ -472,7 +472,7 @@ namespace basisu const uint32_t ENDPOINT_BITS = (mode == 0) ? 4 : 5; const uint32_t PBITS = (mode == 0) ? 6 : 0; const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; - + uint32_t bit_offset = 0; const uint8_t* pBuf = static_cast(pBlock_bits); @@ -524,7 +524,7 @@ namespace basisu const uint32_t PBITS = (mode == 1) ? 2 : 4; const uint32_t SHARED_PBITS = (mode == 1) ? true : false; const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; - + uint32_t bit_offset = 0; const uint8_t* pBuf = static_cast(pBlock_bits); @@ -536,21 +536,21 @@ namespace basisu for (uint32_t c = 0; c < COMPS; c++) for (uint32_t e = 0; e < ENDPOINTS; e++) endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, ENDPOINT_BITS); - + uint32_t pbits[4]; for (uint32_t p = 0; p < PBITS; p++) pbits[p] = read_bits32(pBuf, bit_offset, 1); - + uint32_t weights[16]; for (uint32_t i = 0; i < 16; i++) weights[i] = read_bits32(pBuf, bit_offset, ((!i) || (i == basist::g_bc7_table_anchor_index_second_subset[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS); - + assert(bit_offset == 128); for (uint32_t e = 0; e < ENDPOINTS; e++) for (uint32_t c = 0; c < 4; c++) endpoints[e][c] = (uint8_t)((c == ((mode == 7U) ? 4U : 3U)) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS)); - + color_rgba block_colors[2][8]; for (uint32_t s = 0; s < 2; s++) for (uint32_t i = 0; i < WEIGHT_VALS; i++) @@ -589,11 +589,11 @@ namespace basisu for (uint32_t c = 0; c < COMPS; c++) for (uint32_t e = 0; e < ENDPOINTS; e++) endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS); - + const uint32_t weight_bits[2] = { index_mode ? A_WEIGHT_BITS : WEIGHT_BITS, index_mode ? WEIGHT_BITS : A_WEIGHT_BITS }; - + uint32_t weights[16], a_weights[16]; - + for (uint32_t i = 0; i < 16; i++) (index_mode ? a_weights : weights)[i] = read_bits32(pBuf, bit_offset, weight_bits[index_mode] - ((!i) ? 1 : 0)); @@ -695,10 +695,10 @@ namespace basisu { const uint32_t w = basist::g_bc7_weights4[i]; const uint32_t iw = 64 - w; - vals[i].set_noclamp_rgba( - (r0 * iw + r1 * w + 32) >> 6, - (g0 * iw + g1 * w + 32) >> 6, - (b0 * iw + b1 * w + 32) >> 6, + vals[i].set_noclamp_rgba( + (r0 * iw + r1 * w + 32) >> 6, + (g0 * iw + g1 * w + 32) >> 6, + (b0 * iw + b1 * w + 32) >> 6, (a0 * iw + a1 * w + 32) >> 6); } @@ -711,7 +711,7 @@ namespace basisu pPixels[5] = vals[block.m_hi.m_s11]; pPixels[6] = vals[block.m_hi.m_s21]; pPixels[7] = vals[block.m_hi.m_s31]; - + pPixels[8] = vals[block.m_hi.m_s02]; pPixels[9] = vals[block.m_hi.m_s12]; pPixels[10] = vals[block.m_hi.m_s22]; @@ -755,7 +755,7 @@ namespace basisu return false; } - + static inline int bc6h_sign_extend(int val, int bits) { assert((bits >= 1) && (bits < 32)); @@ -1105,7 +1105,7 @@ namespace basisu return false; if (pBlock->m_hi.m_alpha == 1) return false; - + color_rgba colors[4]; colors[0].r = pBlock->m_hi.m_r0; @@ -1155,7 +1155,7 @@ namespace basisu for (uint32_t i = 0; i < 16; i++) { const uint32_t sel = (pBlock->m_sels[4 + (i >> 2)] >> ((i & 3) * 2)) & 3; - + const uint32_t x = i & 3; const uint32_t y = i >> 2; pPixels[4 + x + y * 8] = block1_colors[sel]; @@ -1216,7 +1216,7 @@ namespace basisu { return color_rgba((col[0] << 3) | (col[0] >> 2), (col[1] << 3) | (col[1] >> 2), (col[2] << 3) | (col[2] >> 2), 255); } - + static color_rgba convert_rgba_5554_to_8888(const color_rgba& col) { return color_rgba((col[0] << 3) | (col[0] >> 2), (col[1] << 3) | (col[1] >> 2), (col[2] << 3) | (col[2] >> 2), (col[3] << 4) | col[3]); @@ -1239,10 +1239,10 @@ namespace basisu { // colora=554 color_rgba color_a(pBlock->m_opaque_color_data.m_red_a, pBlock->m_opaque_color_data.m_green_a, (pBlock->m_opaque_color_data.m_blue_a << 1) | (pBlock->m_opaque_color_data.m_blue_a >> 3), 255); - + // colora=555 color_rgba color_b(pBlock->m_opaque_color_data.m_red_b, pBlock->m_opaque_color_data.m_green_b, pBlock->m_opaque_color_data.m_blue_b, 255); - + colors[0] = convert_rgb_555_to_888(color_a); colors[3] = convert_rgb_555_to_888(color_b); @@ -1251,11 +1251,11 @@ namespace basisu } else { - // colora=4433 + // colora=4433 color_rgba color_a( - (pBlock->m_trans_color_data.m_red_a << 1) | (pBlock->m_trans_color_data.m_red_a >> 3), + (pBlock->m_trans_color_data.m_red_a << 1) | (pBlock->m_trans_color_data.m_red_a >> 3), (pBlock->m_trans_color_data.m_green_a << 1) | (pBlock->m_trans_color_data.m_green_a >> 3), - (pBlock->m_trans_color_data.m_blue_a << 2) | (pBlock->m_trans_color_data.m_blue_a >> 1), + (pBlock->m_trans_color_data.m_blue_a << 2) | (pBlock->m_trans_color_data.m_blue_a >> 1), pBlock->m_trans_color_data.m_alpha_a << 1); //colorb=4443 @@ -1331,9 +1331,9 @@ namespace basisu for (uint32_t x = 0; x < 4; x++) { const uint32_t shift = 45 - ((y + x * 4) * 3); - + const uint32_t sel = (uint32_t)((sels >> shift) & 7); - + int val = base + g_etc2_eac_tables[table][sel] * mul; val = clamp(val, 0, 2047); @@ -1362,7 +1362,7 @@ namespace basisu { basist::unpack_uastc(*static_cast(p), (basist::color32 *)pPixels, false); } - + // Unpacks to RGBA, R, RG, or A. LDR GPU texture formats only. bool unpack_block(texture_format fmt, const void* pBlock, color_rgba* pPixels) { @@ -1440,7 +1440,7 @@ namespace basisu if (!status) return false; - + break; } case texture_format::cATC_RGB: @@ -1532,7 +1532,7 @@ namespace basisu #else // Use our decoder basist::half_float half_block[16][4]; - + astc_helpers::log_astc_block log_blk; if (!astc_helpers::unpack_block(pBlock, log_blk, 4, 4)) return false; @@ -1577,7 +1577,7 @@ namespace basisu assert(0); return false; } - + bool gpu_image::unpack(image& img) const { img.resize(get_pixel_width(), get_pixel_height()); @@ -1589,10 +1589,10 @@ namespace basisu if ((m_fmt == texture_format::cPVRTC1_4_RGB) || (m_fmt == texture_format::cPVRTC1_4_RGBA)) { pvrtc4_image pi(m_width, m_height); - + if (get_total_blocks() != pi.get_total_blocks()) return false; - + memcpy(&pi.get_blocks()[0], get_ptr(), get_size_in_bytes()); pi.deswizzle(); @@ -1662,14 +1662,14 @@ namespace basisu return success; } - + // KTX1 texture file writing static const uint8_t g_ktx_file_id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; // KTX/GL enums enum { - KTX_ENDIAN = 0x04030201, + KTX_ENDIAN = 0x04030201, KTX_OPPOSITE_ENDIAN = 0x01020304, KTX_ETC1_RGB8_OES = 0x8D64, KTX_RED = 0x1903, @@ -1689,7 +1689,7 @@ namespace basisu KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F, KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00, KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02, - + KTX_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0, KTX_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1, KTX_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2, @@ -1731,7 +1731,7 @@ namespace basisu KTX_COMPRESSED_R11_EAC = 0x9270, KTX_COMPRESSED_RG11_EAC = 0x9272 }; - + struct ktx_header { uint8_t m_identifier[12]; @@ -1773,7 +1773,7 @@ namespace basisu return false; } } - + for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++) { const gpu_image_vec &levels = gpu_images[array_index]; @@ -1905,7 +1905,7 @@ namespace basisu { internal_fmt = KTX_COMPRESSED_RGBA_ASTC_6x6_KHR; // TODO: should we write RGB? We don't support generating HDR 6x6 with alpha. - base_internal_fmt = KTX_RGBA; + base_internal_fmt = KTX_RGBA; break; } // We use different enums for HDR vs. LDR ASTC, but internally they are both just ASTC. @@ -2169,7 +2169,7 @@ namespace basisu } // array_index } #endif - + // Write DDS file using tinydds TinyDDS_WriteCallbacks cbs; cbs.error = [](void* user, char const* msg) { BASISU_NOTE_UNUSED(user); fprintf(stderr, "tinydds: %s\n", msg); }; @@ -2179,7 +2179,7 @@ namespace basisu uint32_t mipmap_sizes[32]; const void* mipmap_ptrs[32]; - + clear_obj(mipmap_sizes); clear_obj(mipmap_ptrs); @@ -2197,7 +2197,7 @@ namespace basisu { case texture_format::cBC1_NV: case texture_format::cBC1_AMD: - case texture_format::cBC1: + case texture_format::cBC1: tinydds_fmt = use_srgb_format ? TDDS_BC1_RGBA_SRGB_BLOCK : TDDS_BC1_RGBA_UNORM_BLOCK; break; case texture_format::cBC3: @@ -2226,7 +2226,7 @@ namespace basisu } // DirectXTex's DDSView doesn't handle odd sizes textures correctly. RenderDoc loads them fine, however. - // Trying to work around this here results in invalid mipmaps. + // Trying to work around this here results in invalid mipmaps. //width = (width + 3) & ~3; //height = (height + 3) & ~3; @@ -2248,7 +2248,7 @@ namespace basisu fprintf(stderr, "write_dds_file: Failed creating DDS file\n"); return false; } - + return true; } @@ -2267,7 +2267,7 @@ namespace basisu return true; } - + bool read_uncompressed_dds_file(const char* pFilename, basisu::vector &ldr_mips, basisu::vector& hdr_mips) { const uint32_t MAX_IMAGE_DIM = 16384; @@ -2278,7 +2278,7 @@ namespace basisu cbs.allocFn = [](void* user, size_t size) -> void* { BASISU_NOTE_UNUSED(user); return malloc(size); }; cbs.freeFn = [](void* user, void* memory) { BASISU_NOTE_UNUSED(user); free(memory); }; cbs.readFn = [](void* user, void* buffer, size_t byteCount) -> size_t { return (size_t)fread(buffer, 1, byteCount, (FILE*)user); }; - + #ifdef _MSC_VER cbs.seekFn = [](void* user, int64_t ofs) -> bool { return _fseeki64((FILE*)user, ofs, SEEK_SET) == 0; }; cbs.tellFn = [](void* user) -> int64_t { return _ftelli64((FILE*)user); }; @@ -2318,7 +2318,7 @@ namespace basisu error_printf("Failed parsing DDS header in file \"%s\"\n", pFilename); goto failure; } - + if ((!TinyDDS_Is2D(ctx)) || (TinyDDS_ArraySlices(ctx) > 1) || (TinyDDS_IsCubemap(ctx))) { error_printf("Unsupported DDS texture type in file \"%s\"\n", pFilename); @@ -2327,7 +2327,7 @@ namespace basisu width = TinyDDS_Width(ctx); height = TinyDDS_Height(ctx); - + if (!width || !height) { error_printf("DDS texture dimensions invalid in file \"%s\"\n", pFilename); @@ -2339,7 +2339,7 @@ namespace basisu error_printf("DDS texture dimensions too large in file \"%s\"\n", pFilename); goto failure; } - + tfmt = TinyDDS_GetFormat(ctx); switch (tfmt) { @@ -2387,7 +2387,7 @@ namespace basisu } memcpy(ldr_mips[level].get_ptr(), pImage, image_size); - + if ((tfmt == TDDS_B8G8R8A8_SRGB) || (tfmt == TDDS_B8G8R8A8_UNORM)) { // Swap R and B components. @@ -2416,7 +2416,7 @@ namespace basisu else if (fmt == cRGBA_HALF) { hdr_mips[level].resize(level_width, level_height); - + if ((hdr_mips[level].get_total_pixels() * sizeof(basist::half_float) * 4 != image_size)) { assert(0); @@ -2426,7 +2426,7 @@ namespace basisu // Unpack half to float. const basist::half_float* pSrc_comps = static_cast(pImage); vec4F* pDst_texels = hdr_mips[level].get_ptr(); - + for (uint32_t i = 0; i < total_level_texels; i++) { (*pDst_texels)[0] = basist::half_to_float(pSrc_comps[0]); @@ -2500,7 +2500,7 @@ namespace basisu } //const uint32_t OUT_FILE_MAGIC = 'TEXC'; - struct out_file_header + struct out_file_header { packed_uint<4> m_magic; packed_uint<4> m_pad; @@ -2532,11 +2532,11 @@ namespace basisu fwrite(&hdr, sizeof(hdr), 1, pFile); fwrite(gi.get_ptr(), gi.get_size_in_bytes(), 1, pFile); - + return fclose(pFile) != EOF; } - // The .astc texture format is readable using ARM's astcenc, AMD Compressonator, and other engines/tools. It oddly doesn't support mipmaps, limiting + // The .astc texture format is readable using ARM's astcenc, AMD Compressonator, and other engines/tools. It oddly doesn't support mipmaps, limiting // its usefulness/relevance. // https://github.com/ARM-software/astc-encoder/blob/main/Docs/FileFormat.md bool write_astc_file(const char* pFilename, const void* pBlocks, uint32_t block_width, uint32_t block_height, uint32_t dim_x, uint32_t dim_y) @@ -2578,6 +2578,5 @@ namespace basisu return write_vec_to_file(pFilename, file_data); } - -} // basisu +} // basisu diff --git a/encoder/basisu_gpu_texture.h b/encoder/basisu_gpu_texture.h index 67c2a2bc..06f2cc09 100644 --- a/encoder/basisu_gpu_texture.h +++ b/encoder/basisu_gpu_texture.h @@ -49,11 +49,11 @@ namespace basisu inline texture_format get_format() const { return m_fmt; } inline bool is_hdr() const { return is_hdr_texture_format(m_fmt); } - + // Width/height in pixels inline uint32_t get_pixel_width() const { return m_width; } inline uint32_t get_pixel_height() const { return m_height; } - + // Width/height in blocks, row pitch is assumed to be m_blocks_x. inline uint32_t get_blocks_x() const { return m_blocks_x; } inline uint32_t get_blocks_y() const { return m_blocks_y; } @@ -68,7 +68,7 @@ namespace basisu inline uint32_t get_row_pitch_in_bytes() const { return get_bytes_per_block() * get_blocks_x(); } inline const uint64_vec &get_blocks() const { return m_blocks; } - + inline const uint64_t *get_ptr() const { return &m_blocks[0]; } inline uint64_t *get_ptr() { return &m_blocks[0]; } @@ -106,7 +106,7 @@ namespace basisu // Unpacks HDR textures only. bool unpack_hdr(imagef& img) const; - + inline void override_dimensions(uint32_t w, uint32_t h) { m_width = w; @@ -123,7 +123,7 @@ namespace basisu // KTX1 file writing bool create_ktx_texture_file(uint8_vec &ktx_data, const basisu::vector& gpu_images, bool cubemap_flag); - + bool does_dds_support_format(texture_format fmt); bool write_dds_file(uint8_vec& dds_data, const basisu::vector& gpu_images, bool cubemap_flag, bool use_srgb_format); bool write_dds_file(const char* pFilename, const basisu::vector& gpu_images, bool cubemap_flag, bool use_srgb_format); @@ -135,7 +135,7 @@ namespace basisu bool write_compressed_texture_file(const char *pFilename, const basisu::vector& g, bool cubemap_flag, bool use_srgb_format); bool write_compressed_texture_file(const char* pFilename, const gpu_image_vec& g, bool use_srgb_format); bool write_compressed_texture_file(const char *pFilename, const gpu_image &g, bool use_srgb_format); - + bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi); // GPU texture block unpacking @@ -155,7 +155,7 @@ namespace basisu bool unpack_pvrtc2(const void* p, color_rgba* pPixels); void unpack_etc2_eac_r(const void *p, color_rgba* pPixels, uint32_t c); void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels); - + // unpack_block() is primarily intended to unpack texture data created by the transcoder. // For some texture formats (like ETC2 RGB, PVRTC2, FXT1) it's not yet a complete implementation. // Unpacks LDR texture formats only. @@ -163,8 +163,7 @@ namespace basisu // Unpacks HDR texture formats only. bool unpack_block_hdr(texture_format fmt, const void* pBlock, vec4F* pPixels); - + bool write_astc_file(const char* pFilename, const void* pBlocks, uint32_t block_width, uint32_t block_height, uint32_t dim_x, uint32_t dim_y); - -} // namespace basisu +} // namespace basisu diff --git a/encoder/basisu_kernels_imp.h b/encoder/basisu_kernels_imp.h index 123862b1..0e362d3e 100644 --- a/encoder/basisu_kernels_imp.h +++ b/encoder/basisu_kernels_imp.h @@ -22,7 +22,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) void _call(int64_t* pDistance, const uint8_t* pSelectors, const color_rgba* pBlock_colors, - const color_rgba* pSrc_pixels, uint32_t n, + const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err) { assert(early_out_err >= 0); @@ -110,7 +110,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) void _call(int64_t* pDistance, const uint8_t* pSelectors, const color_rgba* pBlock_colors, - const color_rgba* pSrc_pixels, uint32_t n, + const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err) { assert(early_out_err >= 0); @@ -205,7 +205,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) void _call(int64_t* pDistance, uint8_t* pSelectors, const color_rgba* pBlock_colors, - const color_rgba* pSrc_pixels, uint32_t n, + const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err) { assert(early_out_err >= 0); @@ -301,7 +301,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) void _call(int64_t* pDistance, uint8_t* pSelectors, const color_rgba* pBlock_colors, - const color_rgba* pSrc_pixels, uint32_t n, + const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err) { assert(early_out_err >= 0); @@ -397,7 +397,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) void _call(int64_t* pDistance, const color_rgba* pBlock_colors, - const color_rgba* pSrc_pixels, uint32_t n, + const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_error) { assert(early_out_error >= 0); @@ -453,7 +453,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) int id = ((delta_l * delta_l) >> 7) + ((((delta_cr * delta_cr) >> 7) * 26) >> 7) + ((((delta_cb * delta_cb) >> 7) * 3) >> 7); - + if (id < best_err) { best_err = id; @@ -554,10 +554,10 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) uint32_t num_vecs, const void* pWeighted_vecs_void, const void* pOrigin_void, const uint32_t* pVec_indices, void* pMatrix16x16_void) { const std::pair* pWeighted_vecs = static_cast< const std::pair *>(pWeighted_vecs_void); - + const float* pOrigin = static_cast(pOrigin_void); vfloat org0 = loadu_linear_all(pOrigin), org1 = loadu_linear_all(pOrigin + 4), org2 = loadu_linear_all(pOrigin + 8), org3 = loadu_linear_all(pOrigin + 12); - + vfloat mat[16][4]; vfloat vzero(zero_vfloat()); @@ -577,7 +577,7 @@ namespace CPPSPMD_NAME(basisu_kernels_namespace) vfloat weight((float)pWeighted_vecs[vec_index].second); vfloat vec[4] = { loadu_linear_all(pW) - org0, loadu_linear_all(pW + 4) - org1, loadu_linear_all(pW + 8) - org2, loadu_linear_all(pW + 12) - org3 }; - + vfloat wvec0 = vec[0] * weight, wvec1 = vec[1] * weight, wvec2 = vec[2] * weight, wvec3 = vec[3] * weight; for (uint32_t j = 0; j < 16; j++) diff --git a/encoder/basisu_kernels_sse.cpp b/encoder/basisu_kernels_sse.cpp index 36a493d7..13e06a8d 100644 --- a/encoder/basisu_kernels_sse.cpp +++ b/encoder/basisu_kernels_sse.cpp @@ -142,4 +142,3 @@ void detect_sse41() } // namespace basisu #endif // #if BASISU_SUPPORT_SSE - diff --git a/encoder/basisu_math.h b/encoder/basisu_math.h index 3e56747b..66bb749a 100644 --- a/encoder/basisu_math.h +++ b/encoder/basisu_math.h @@ -8,10 +8,10 @@ namespace bu_math // Would prefer using SSE1 etc. but that would require implementing multiple versions and platform divergence (needing more testing). BASISU_FORCE_INLINE float inv_sqrt(float v) { - union - { - float flt; - uint32_t ui; + union + { + float flt; + uint32_t ui; } un; un.flt = v; @@ -1180,7 +1180,7 @@ namespace bu_math } return result; } - + template class matrix { @@ -2521,14 +2521,14 @@ namespace basisu FloatType m_mad; // mean absolute deviation FloatType m_min, m_max, m_range; // min and max values, and max-min FloatType m_len; // length of values as a vector (Euclidean norm or L2 norm) - FloatType m_coeff_of_var; // coefficient of variation (std_dev/mean), High CV: Indicates greater variability relative to the mean, meaning the data values are more spread out, + FloatType m_coeff_of_var; // coefficient of variation (std_dev/mean), High CV: Indicates greater variability relative to the mean, meaning the data values are more spread out, // Low CV : Indicates less variability relative to the mean, meaning the data values are more consistent. - - FloatType m_skewness; // Skewness = 0: The data is perfectly symmetric around the mean, - // Skewness > 0: The data is positively skewed (right-skewed), + + FloatType m_skewness; // Skewness = 0: The data is perfectly symmetric around the mean, + // Skewness > 0: The data is positively skewed (right-skewed), // Skewness < 0: The data is negatively skewed (left-skewed) // 0-.5 approx. symmetry, .5-1 moderate skew, >= 1 highly skewed - + FloatType m_kurtosis; // Excess Kurtosis: Kurtosis = 0: The distribution has normal kurtosis (mesokurtic) // Kurtosis > 0: The distribution is leptokurtic, with heavy tails and a sharp peak // Kurtosis < 0: The distribution is platykurtic, with light tails and a flatter peak @@ -2538,9 +2538,9 @@ namespace basisu FloatType m_median; uint32_t m_median_index; - stats() - { - clear(); + stats() + { + clear(); } void clear() @@ -2557,7 +2557,7 @@ namespace basisu m_skewness = 0; m_kurtosis = 0; m_any_zero = false; - + m_median = 0; m_median_index = 0; } @@ -2594,7 +2594,7 @@ namespace basisu void calc(uint32_t n, const T* pVals, uint32_t stride = 1, bool calc_median_flag = false) { clear(); - + if (!n) return; @@ -2609,10 +2609,10 @@ namespace basisu if (v == 0.0f) m_any_zero = true; - + m_total += v; m_total_sq += v * v; - + if (!i) { m_min = v; @@ -2634,12 +2634,12 @@ namespace basisu m_avg = m_total / nd; m_avg_sq = m_total_sq / nd; m_rms = sqrt(m_avg_sq); - + for (uint32_t i = 0; i < n; i++) { FloatType v = (FloatType)pVals[i * stride]; FloatType d = v - m_avg; - + const FloatType d2 = d * d; const FloatType d3 = d2 * d; const FloatType d4 = d3 * d; @@ -2680,7 +2680,7 @@ namespace basisu m_total += v; } - + const FloatType nd = (FloatType)n; m_avg = m_total / nd; @@ -2712,7 +2712,7 @@ namespace basisu FloatType m_euclidean_dist; // euclidean distance between values as vectors FloatType m_cosine_sim; // normalized dot products of values as vectors FloatType m_min_diff, m_max_diff; // minimum/maximum abs difference between values - + comparative_stats() { clear(); @@ -2738,7 +2738,7 @@ namespace basisu clear(); if (!n) return; - + stats temp_a_stats; if (!pA_stats) { @@ -2757,7 +2757,7 @@ namespace basisu { const FloatType fa = (FloatType)pA[i * a_stride]; const FloatType fb = (FloatType)pB[i * b_stride]; - + if ((pA_stats->m_min >= 0.0f) && (pB_stats->m_min >= 0.0f)) { const FloatType ld = log(fa + 1.0f) - log(fb + 1.0f); @@ -2766,7 +2766,7 @@ namespace basisu const FloatType diff = fa - fb; const FloatType abs_diff = fabs(diff); - + m_mse += diff * diff; m_mae += abs_diff; @@ -2781,7 +2781,7 @@ namespace basisu } const FloatType nd = (FloatType)n; - + m_euclidean_dist = sqrt(m_mse); m_mse /= nd; @@ -2790,7 +2790,7 @@ namespace basisu m_mae /= nd; m_cov /= nd; - + FloatType dv = (pA_stats->m_std_dev * pB_stats->m_std_dev); if (dv != 0.0f) m_pearson = m_cov / dv; @@ -2883,9 +2883,9 @@ namespace basisu const FloatType fb = (FloatType)pB[i * b_stride]; const FloatType diff = fa - fb; - + m_mse += diff * diff; - + const FloatType da = fa - pA_stats->m_avg; const FloatType db = fb - pB_stats->m_avg; m_cov += da * db; @@ -2897,7 +2897,7 @@ namespace basisu m_mse /= nd; m_rmse = sqrt(m_mse); - + m_cov /= nd; } @@ -2938,7 +2938,7 @@ namespace basisu m_cov /= nd; } }; - + class stat_history { public: @@ -3083,12 +3083,12 @@ namespace basisu uint32_t lowerBits = float_union.u & 0xFFFF; // Round to nearest or even - if ((lowerBits & 0x8000) && + if ((lowerBits & 0x8000) && ((lowerBits > 0x8000) || ((lowerBits == 0x8000) && (upperBits & 1))) ) { // Round up - upperBits += 1; + upperBits += 1; // Check for overflow in the exponent after rounding up if (((upperBits & 0x7F80) == 0x7F80) && ((upperBits & 0x007F) == 0)) @@ -3140,7 +3140,6 @@ namespace basisu return res; } - - -} // namespace basisu + +} // namespace basisu diff --git a/encoder/basisu_miniz.h b/encoder/basisu_miniz.h index dab38f9f..43d757fe 100644 --- a/encoder/basisu_miniz.h +++ b/encoder/basisu_miniz.h @@ -1,8 +1,8 @@ /* miniz.c v1.15 - deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Forked from the public domain/unlicense version at: https://code.google.com/archive/p/miniz/ - + + Forked from the public domain/unlicense version at: https://code.google.com/archive/p/miniz/ + Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); @@ -497,7 +497,7 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void // 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. +// 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). @@ -799,7 +799,7 @@ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) // 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.) mz_uint64 a = 128ULL + (source_len * 110ULL) / 100ULL; mz_uint64 b = 128ULL + (mz_uint64)source_len + ((source_len / (31 * 1024)) + 1ULL) * 5ULL; - + mz_uint64 t = MZ_MAX(a, b); if (((mz_ulong)t) != t) t = (mz_ulong)(-1); @@ -1377,8 +1377,8 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex 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)) + 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; @@ -2528,4 +2528,3 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, } // namespace buminiz #endif // MINIZ_HEADER_FILE_ONLY - diff --git a/encoder/basisu_opencl.cpp b/encoder/basisu_opencl.cpp index 200cff50..539e6cdc 100644 --- a/encoder/basisu_opencl.cpp +++ b/encoder/basisu_opencl.cpp @@ -54,10 +54,10 @@ namespace basisu class ocl { public: - ocl() + ocl() { memset(&m_dev_fp_config, 0, sizeof(m_dev_fp_config)); - + m_ocl_mutex.lock(); m_ocl_mutex.unlock(); } @@ -161,12 +161,12 @@ namespace basisu deinit(); return false; } - + printf("OpenCL init time: %3.3f secs\n", tm.get_elapsed_secs()); return true; } - + bool deinit() { if (m_program) @@ -364,7 +364,7 @@ namespace basisu return obj; } - + bool destroy_buffer(cl_mem buf) { if (buf) @@ -678,7 +678,7 @@ namespace basisu cl_command_queue m_command_queue = nullptr; cl_program m_program = nullptr; cl_device_fp_config m_dev_fp_config; - + bool m_use_mutex = false; std::mutex m_ocl_mutex; @@ -704,7 +704,7 @@ namespace basisu private: ocl* m_p; }; - + cl_image_format get_image_format(uint32_t bytes_per_pixel, bool normalized) { cl_image_format fmt; @@ -721,10 +721,10 @@ namespace basisu return fmt; } }; - + // Library blobal state ocl g_ocl; - + bool opencl_init(bool force_serialization) { if (g_ocl.is_initialized()) @@ -753,11 +753,11 @@ namespace basisu g_ocl.deinit(); return false; } - + pKernel_src = (char*)kernel_src.data(); kernel_src_size = kernel_src.size(); #endif - + if (!kernel_src_size) { ocl_error_printf("opencl_init: Invalid OpenCL kernel source file \"%s\"\n", BASISU_OCL_KERNELS_FILENAME); @@ -771,7 +771,7 @@ namespace basisu g_ocl.deinit(); return false; } - + printf("OpenCL support initialized successfully\n"); return true; @@ -816,10 +816,10 @@ namespace basisu opencl_context* pContext = static_cast(calloc(sizeof(opencl_context), 1)); if (!pContext) return nullptr; - + // To avoid driver bugs in some drivers - serialize this. Likely not necessary, we don't know. // https://community.intel.com/t5/OpenCL-for-CPU/Bug-report-clCreateKernelsInProgram-is-not-thread-safe/td-p/1159771 - + pContext->m_command_queue = g_ocl.create_command_queue(); if (!pContext->m_command_queue) { @@ -890,7 +890,7 @@ namespace basisu g_ocl.destroy_kernel(pContext->m_ocl_refine_endpoint_clusterization_kernel); g_ocl.destroy_command_queue(pContext->m_command_queue); - + memset(pContext, 0, sizeof(opencl_context)); free(pContext); @@ -940,7 +940,7 @@ namespace basisu return false; assert(pContext->m_ocl_total_pixel_blocks <= INT_MAX); - + cl_encode_etc1s_param_struct ps; ps.m_total_blocks = (int)pContext->m_ocl_total_pixel_blocks; ps.m_perceptual = perceptual; @@ -950,7 +950,7 @@ namespace basisu cl_mem vars = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue , &ps, sizeof(ps)); cl_mem block_buf = g_ocl.alloc_write_buffer(sizeof(etc_block) * pContext->m_ocl_total_pixel_blocks); - + if (!vars || !block_buf) goto exit; @@ -988,7 +988,7 @@ namespace basisu interval_timer tm; tm.start(); - + cl_encode_etc1s_param_struct ps; ps.m_total_blocks = total_clusters; ps.m_perceptual = perceptual; @@ -1005,7 +1005,7 @@ namespace basisu return false; } } - + cl_mem vars = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue , &ps, sizeof(ps)); cl_mem input_clusters = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue, pClusters, (size_t)(sizeof(cl_pixel_cluster) * total_clusters)); cl_mem input_pixels = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue, pPixels, (size_t)(sizeof(color_rgba) * total_pixels)); @@ -1066,7 +1066,7 @@ namespace basisu return false; assert(pContext->m_ocl_total_pixel_blocks <= INT_MAX); - + cl_rec_param_struct ps; ps.m_total_blocks = (int)pContext->m_ocl_total_pixel_blocks; ps.m_perceptual = perceptual; @@ -1077,7 +1077,7 @@ namespace basisu cl_mem cluster_info = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue, pCluster_info, sizeof(cl_endpoint_cluster_struct) * total_clusters); cl_mem sorted_block_indices = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue, pSorted_block_indices, sizeof(uint32_t) * pContext->m_ocl_total_pixel_blocks); cl_mem output_buf = g_ocl.alloc_write_buffer(sizeof(uint32_t) * pContext->m_ocl_total_pixel_blocks); - + if (!pixel_block_info || !cluster_info || !sorted_block_indices || !output_buf) goto exit; @@ -1091,7 +1091,7 @@ namespace basisu goto exit; debug_printf("opencl_refine_endpoint_clusterization: Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); - + status = true; exit: @@ -1127,7 +1127,7 @@ namespace basisu fosc_param_struct ps; ps.m_total_blocks = (int)pContext->m_ocl_total_pixel_blocks; ps.m_perceptual = perceptual; - + bool status = false; cl_mem input_block_info = g_ocl.alloc_and_init_read_buffer(pContext->m_command_queue, pInput_block_info, sizeof(fosc_block_struct) * pContext->m_ocl_total_pixel_blocks); @@ -1200,9 +1200,9 @@ namespace basisu goto exit; debug_printf("opencl_determine_selectors: Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); - + status = true; - + exit: g_ocl.destroy_buffer(input_etc_color5_intens); g_ocl.destroy_buffer(output_blocks); @@ -1210,7 +1210,7 @@ namespace basisu return status; } -#else +#else namespace basisu { // No OpenCL support - all dummy functions that return false; @@ -1277,7 +1277,7 @@ namespace basisu BASISU_NOTE_UNUSED(pPixel_weights); BASISU_NOTE_UNUSED(perceptual); BASISU_NOTE_UNUSED(total_perms); - + return false; } diff --git a/encoder/basisu_opencl.h b/encoder/basisu_opencl.h index b44f288b..d849d79d 100644 --- a/encoder/basisu_opencl.h +++ b/encoder/basisu_opencl.h @@ -59,7 +59,7 @@ namespace basisu bool opencl_encode_etc1s_pixel_clusters( opencl_context_ptr pContext, - etc_block* pOutput_blocks, + etc_block* pOutput_blocks, uint32_t total_clusters, const cl_pixel_cluster *pClusters, uint64_t total_pixels, @@ -92,7 +92,7 @@ namespace basisu uint32_t total_clusters, const cl_endpoint_cluster_struct *pCluster_info, const uint32_t *pSorted_block_indices, - uint32_t* pOutput_cluster_indices, + uint32_t* pOutput_cluster_indices, bool perceptual); // opencl_find_optimal_selector_clusters_for_each_block diff --git a/encoder/basisu_pvrtc1_4.cpp b/encoder/basisu_pvrtc1_4.cpp index 4bf9516f..9bceee37 100644 --- a/encoder/basisu_pvrtc1_4.cpp +++ b/encoder/basisu_pvrtc1_4.cpp @@ -131,7 +131,7 @@ namespace basisu uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y) { assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width)); - + uint32_t min_d = width, max_v = y; if (height < width) { @@ -148,7 +148,7 @@ namespace basisu } max_v >>= shift_ofs; - + // OR in the rest of the bits from the largest dimension swizzled |= (max_v << (2 * shift_ofs)); @@ -169,7 +169,7 @@ namespace basisu r = (packed >> 10) & 31; g = (packed >> 5) & 31; b = (packed >> 1) & 15; - + if (unpack) { b = (b << 1) | (b >> 3); @@ -198,7 +198,7 @@ namespace basisu { a = (a << 1); a = (a << 4) | a; - + r = (r << 1) | (r >> 3); g = (g << 1) | (g >> 3); b = (b << 2) | (b >> 1); @@ -272,7 +272,7 @@ namespace basisu b = (packed >> 1) & 7; a = a << 1; - + r = (r << 1) | (r >> 3); g = (g << 1) | (g >> 3); b = (b << 2) | (b >> 1); @@ -285,13 +285,13 @@ namespace basisu b = packed & 15; a = a << 1; - + r = (r << 1) | (r >> 3); g = (g << 1) | (g >> 3); b = (b << 1) | (b >> 3); } } - + assert((r < 32) && (g < 32) && (b < 32) && (a < 16)); return color_rgba(r, g, b, a); @@ -305,12 +305,12 @@ namespace basisu int block_x1 = block_x0 + 1; int block_y0 = (static_cast(y) - 2) >> 2; int block_y1 = block_y0 + 1; - + block_x0 = posmod(block_x0, m_block_width); block_x1 = posmod(block_x1, m_block_width); block_y0 = posmod(block_y0, m_block_height); block_y1 = posmod(block_y1, m_block_height); - + pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)); pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)); @@ -334,7 +334,7 @@ namespace basisu return false; } - + color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const { assert((x < m_width) && (y < m_height)); @@ -343,12 +343,12 @@ namespace basisu int block_x1 = block_x0 + 1; int block_y0 = (static_cast(y) - 2) >> 2; int block_y1 = block_y0 + 1; - + block_x0 = posmod(block_x0, m_block_width); block_x1 = posmod(block_x1, m_block_width); block_y0 = posmod(block_y0, m_block_height); block_y1 = posmod(block_y1, m_block_height); - + if (get_block_uses_transparent_modulation(x >> 2, y >> 2)) { if (m == 0) @@ -471,7 +471,7 @@ namespace basisu color_rgba color_1((int)colors[1][0], (int)colors[1][1], (int)colors[1][2], 0); pvrtc4_block cur_blocks[3][3]; - + for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) diff --git a/encoder/basisu_pvrtc1_4.h b/encoder/basisu_pvrtc1_4.h index a9fe6b27..de912c28 100644 --- a/encoder/basisu_pvrtc1_4.h +++ b/encoder/basisu_pvrtc1_4.h @@ -17,14 +17,14 @@ namespace basisu { - enum - { - PVRTC2_MIN_WIDTH = 16, - PVRTC2_MIN_HEIGHT = 8, - PVRTC4_MIN_WIDTH = 8, - PVRTC4_MIN_HEIGHT = 8 + enum + { + PVRTC2_MIN_WIDTH = 16, + PVRTC2_MIN_HEIGHT = 8, + PVRTC4_MIN_WIDTH = 8, + PVRTC4_MIN_HEIGHT = 8 }; - + struct pvrtc4_block { uint32_t m_modulation; @@ -56,9 +56,9 @@ namespace basisu // Returns raw endpoint or 8888 color_rgba get_endpoint(uint32_t endpoint_index, bool unpack) const; - + color_rgba get_endpoint_5554(uint32_t endpoint_index) const; - + static uint32_t get_component_precision_in_bits(uint32_t c, uint32_t endpoint_index, bool opaque_endpoint) { static const uint32_t s_comp_prec[4][4] = @@ -80,7 +80,7 @@ namespace basisu }; return s_color_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)]; } - + inline uint32_t get_modulation(uint32_t x, uint32_t y) const { assert((x < 4) && (y < 4)); @@ -121,7 +121,7 @@ namespace basisu assert(endpoint_index < 2); const uint32_t m = m_endpoints & 1; uint32_t r = c[0], g = c[1], b = c[2], a = c[3]; - + uint32_t packed; if (opaque_endpoint) @@ -234,14 +234,14 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif #endif memset(m_blocks.get_ptr(), 0, m_blocks.size_in_bytes()); #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } @@ -254,7 +254,7 @@ namespace basisu { return m_blocks(bx, by).is_endpoint_opaque(endpoint_index); } - + color_rgba get_endpoint(uint32_t bx, uint32_t by, uint32_t endpoint_index, bool unpack) const { assert((bx < m_block_width) && (by < m_block_height)); @@ -266,12 +266,12 @@ namespace basisu assert((x < m_width) && (y < m_height)); return m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3); } - + // Returns true if the block uses transparent modulation. bool get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const; - + color_rgba get_pixel(uint32_t x, uint32_t y, uint32_t m) const; - + inline color_rgba get_pixel(uint32_t x, uint32_t y) const { assert((x < m_width) && (y < m_height)); @@ -456,12 +456,12 @@ namespace basisu return total_error; } - - public: + + public: uint32_t m_width, m_height; pvrtc4_block_vector2D m_blocks; uint32_t m_block_width, m_block_height; - + bool m_uses_alpha; }; diff --git a/encoder/basisu_resample_filters.cpp b/encoder/basisu_resample_filters.cpp index 11c7ec2f..ce79e34e 100644 --- a/encoder/basisu_resample_filters.cpp +++ b/encoder/basisu_resample_filters.cpp @@ -28,7 +28,7 @@ namespace basisu else return 0.0f; } - + float tent_filter(float t) /* box (*) box, bilinear/triangle */ { if (t < 0.0f) @@ -307,20 +307,20 @@ namespace basisu const resample_filter g_resample_filters[] = { { "box", box_filter, BASISU_BOX_FILTER_SUPPORT }, - { "tent", tent_filter, BASISU_TENT_FILTER_SUPPORT }, - { "bell", bell_filter, BASISU_BELL_FILTER_SUPPORT }, + { "tent", tent_filter, BASISU_TENT_FILTER_SUPPORT }, + { "bell", bell_filter, BASISU_BELL_FILTER_SUPPORT }, { "b-spline", B_spline_filter, B_SPLINE_SUPPORT }, - { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, - { "blackman", blackman_filter, BLACKMAN_SUPPORT }, + { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, + { "blackman", blackman_filter, BLACKMAN_SUPPORT }, { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT }, { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT }, - { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, - { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, - { "kaiser", kaiser_filter, KAISER_SUPPORT }, + { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, + { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, + { "kaiser", kaiser_filter, KAISER_SUPPORT }, { "gaussian", gaussian_filter, BASISU_GAUSSIAN_FILTER_SUPPORT }, - { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, - { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, - { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, + { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, + { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, + { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT }, }; diff --git a/encoder/basisu_resampler.cpp b/encoder/basisu_resampler.cpp index fa062985..e8778b5d 100644 --- a/encoder/basisu_resampler.cpp +++ b/encoder/basisu_resampler.cpp @@ -139,7 +139,7 @@ namespace basisu n += (right - left + 1); } - // Allocate memory for contributors. + // Allocate memory for contributors. if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL)) { @@ -840,5 +840,5 @@ namespace basisu else return g_resample_filters[filter_num].name; } - + } // namespace basisu diff --git a/encoder/basisu_resampler_filters.h b/encoder/basisu_resampler_filters.h index c96416b1..9d21f950 100644 --- a/encoder/basisu_resampler_filters.h +++ b/encoder/basisu_resampler_filters.h @@ -29,7 +29,7 @@ namespace basisu extern const resample_filter g_resample_filters[]; extern const int g_num_resample_filters; - + const float BASISU_BOX_FILTER_SUPPORT = 0.5f; float box_filter(float t); /* pulse/Fourier window */ diff --git a/encoder/basisu_ssim.cpp b/encoder/basisu_ssim.cpp index 4cdf3a48..827a5b15 100644 --- a/encoder/basisu_ssim.cpp +++ b/encoder/basisu_ssim.cpp @@ -26,7 +26,7 @@ namespace basisu float g = (1.0f / (sqrtf((float)(2.0f * M_PI * sigma_sqr)))) * pow; return g; } - + // size_x/y should be odd void compute_gaussian_kernel(float *pDst, int size_x, int size_y, float sigma_sqr, uint32_t flags) { @@ -318,14 +318,14 @@ namespace basisu return avg; } - + // Reference: https://ece.uwaterloo.ca/~z70wang/research/ssim/index.html vec4F compute_ssim(const imagef &a, const imagef &b) { imagef axb, a_sq, b_sq, mu1, mu2, mu1_sq, mu2_sq, mu1_mu2, s1_sq, s2_sq, s12, smap, t1, t2, t3; const float C1 = 6.50250f, C2 = 58.52250f; - + pow_image(a, a_sq, vec4F(2)); pow_image(b, b_sq, vec4F(2)); mul_image(a, b, axb, vec4F(1.0f)); diff --git a/encoder/basisu_uastc_enc.cpp b/encoder/basisu_uastc_enc.cpp index 7e0a2b1d..701534cc 100644 --- a/encoder/basisu_uastc_enc.cpp +++ b/encoder/basisu_uastc_enc.cpp @@ -223,7 +223,7 @@ namespace basisu default: break; } -#endif +#endif uint32_t total_planes = 1; switch (result.m_uastc_mode) @@ -456,7 +456,7 @@ namespace basisu printf("Total bits: %u, endpoint bits: %u, weight bits: %u\n", block_bit_offset, total_endpoint_bits, total_weight_bits); #endif } - + // MODE 0 // 0. DualPlane: 0, WeightRange: 8 (16), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 19 (192) MODE6 RGB // 18. DualPlane: 0, WeightRange: 11 (32), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 11 (32) MODE6 RGB @@ -507,7 +507,7 @@ namespace basisu astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1]; astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2]; astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2]; - + bool invert = false; if (pForce_selectors == nullptr) @@ -1128,7 +1128,7 @@ namespace basisu } // common_pattern } - // MODE 5 + // MODE 5 // DualPlane: 0, WeightRange: 5 (8), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 20 (256) BC7 MODE 6 (or MODE 1 1-subset) static void astc_mode5(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params) { @@ -1259,7 +1259,7 @@ namespace basisu ccell_results_rgb.m_pSelectors_temp = &ccell_result_selectors_temp[0]; uint64_t part_err_rgb = color_cell_compression(255, &ccell_params_rgb, &ccell_results_rgb, &comp_params); - + color_cell_compressor_params ccell_params_a; memset(&ccell_params_a, 0, sizeof(ccell_params_a)); @@ -1416,9 +1416,9 @@ namespace basisu for (uint32_t x = 0; x < 4; x++) { const uint32_t astc_part = bc7_convert_partition_index_3_to_2(g_bc7_partition3[16 * bc7_pattern + x + y * 4], common_pattern_k); -#ifdef _DEBUG +#ifdef _DEBUG assert((int)astc_part == astc_compute_texel_partition(astc_pattern, x, y, 0, 2, true)); -#endif +#endif part_pixel_index[y][x] = num_part_pixels[astc_part]; part_pixels[astc_part][num_part_pixels[astc_part]++] = block[y][x]; @@ -1583,7 +1583,7 @@ namespace basisu } #endif } - + // 9. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 12 (RGBA Direct), EndpointRange: 8 (16) - BC7 MODE 7 // 16. DualPlane: 0, WeightRange : 2 (4), Subsets : 2, CEM: 4 (LA Direct), EndpointRange : 20 (256) - BC7 MODE 7 static void astc_mode9_or_16(uint32_t mode, const color_rgba source_block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, uint32_t estimate_partition_list_size) @@ -2499,7 +2499,7 @@ namespace basisu total_results++; } } - + static void compute_block_error(const color_rgba block[4][4], const color_rgba decoded_block[4][4], uint64_t &total_rgb_err, uint64_t &total_rgba_err, uint64_t &total_la_err) { uint64_t total_err_r = 0, total_err_g = 0, total_err_b = 0, total_err_a = 0; @@ -2546,14 +2546,14 @@ namespace basisu color_rgba tblock_hint0_bc1[4][4]; color_rgba tblock_hint1_bc1[4][4]; - + etc_block etc1_blk; memset(&etc1_blk, 0, sizeof(etc1_blk)); eac_a8_block etc2_blk; memset(&etc2_blk, 0, sizeof(etc2_blk)); etc2_blk.m_multiplier = 1; - + // Pack to UASTC, then unpack, because the endpoints may be swapped. uastc_block temp_ublock; @@ -2561,7 +2561,7 @@ namespace basisu unpacked_uastc_block temp_ublock_unpacked; unpack_uastc(temp_ublock, temp_ublock_unpacked, false); - + unpacked_uastc_block ublock; memset(&ublock, 0, sizeof(ublock)); ublock.m_mode = best_results.m_uastc_mode; @@ -2590,7 +2590,7 @@ namespace basisu else { transcode_uastc_to_bc1_hint0(ublock, &b); - + unpack_block(texture_format::cBC1, &b, &tblock_hint0_bc1[0][0]); } @@ -2612,7 +2612,7 @@ namespace basisu const float err_thresh0 = 1.075f; const float err_thresh1 = 1.075f; - + if ((g_uastc_mode_has_bc1_hint0[best_mode]) && (t_err_hint0 <= t_err * err_thresh0)) bc1_hint0 = true; @@ -2779,7 +2779,7 @@ namespace basisu uint32_t first_flip = 0, last_flip = 2; uint32_t first_individ = 0, last_individ = 2; - + if (flags & cPackUASTCETC1DisableFlipAndIndividual) { last_flip = 1; @@ -2791,7 +2791,7 @@ namespace basisu first_flip = 1; last_flip = first_flip + 1; } - + for (uint32_t flip = first_flip; flip < last_flip; flip++) { trial_block.set_flip_bit(flip != 0); @@ -2799,7 +2799,7 @@ namespace basisu for (uint32_t individ = first_individ; individ < last_individ; individ++) { const uint32_t mul = individ ? 15 : 31; - + trial_block.set_diff_bit(individ == 0); color_rgba unbiased_block_colors[2]; @@ -2815,7 +2815,7 @@ namespace basisu { const etc_coord2 &c = g_etc1_pixel_coords[flip][subset][j]; const color_rgba& p = decoded_uastc_block[c.m_y][c.m_x]; - + avg_color[0] += p.r; avg_color[1] += p.g; avg_color[2] += p.b; @@ -2833,13 +2833,13 @@ namespace basisu unbiased_block_colors[subset][1] = (uint8_t)((avg_color[1] * mul + 1020) / (8 * 255)); unbiased_block_colors[subset][2] = (uint8_t)((avg_color[2] * mul + 1020) / (8 * 255)); unbiased_block_colors[subset][3] = 0; - + } // subset - + for (uint32_t bias_iter = 0; bias_iter < last_bias; bias_iter++) { const uint32_t bias = use_faster_bias_mode_table ? s_sorted_bias_modes[bias_iter] : bias_iter; - + color_rgba block_colors[2]; for (uint32_t subset = 0; subset < 2; subset++) block_colors[subset] = has_bias ? apply_etc1_bias((color32&)unbiased_block_colors[subset], bias, mul, subset) : unbiased_block_colors[subset]; @@ -2873,7 +2873,7 @@ namespace basisu uint64_t best_subset_err = UINT64_MAX; const uint32_t inten_table_limit = (level == cPackUASTCLevelVerySlow) ? 8 : ((range[subset] > 51) ? 8 : (range[subset] >= 7 ? 4 : 2)); - + for (uint32_t inten_table = 0; inten_table < inten_table_limit; inten_table++) { trial_block.set_inten_table(subset, inten_table); @@ -3008,7 +3008,7 @@ namespace basisu uint32_t m_table; uint32_t m_multiplier; }; - + static uint64_t uastc_pack_eac_a8(uastc_pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask) { assert(num_pixels <= 16); @@ -3152,7 +3152,7 @@ namespace basisu solid_results.m_common_pattern = 0; solid_results.m_solid_color = first_color; memset(&solid_results.m_astc, 0, sizeof(solid_results.m_astc)); - + etc_block etc1_blk; uint32_t etc1_bias = 0; @@ -3168,17 +3168,17 @@ namespace basisu return; } - + int level = flags & 7; const bool favor_uastc_error = (flags & cPackUASTCFavorUASTCError) != 0; const bool favor_bc7_error = !favor_uastc_error && ((flags & cPackUASTCFavorBC7Error) != 0); //const bool etc1_perceptual = true; - + // TODO: This uses 64KB of stack space! uastc_encode_results results[MAX_ENCODE_RESULTS]; - + level = clampi(level, cPackUASTCLevelFastest, cPackUASTCLevelVerySlow); - + // Set all options to slowest, then configure from there depending on the selected level. uint32_t mode_mask = UINT32_MAX; uint32_t uber_level = 6; @@ -3189,12 +3189,12 @@ namespace basisu uint32_t least_squares_passes = 2; bool bc1_hints = true; bool only_use_la_on_transparent_blocks = false; - + switch (level) { case cPackUASTCLevelFastest: { - mode_mask = (1 << 0) | (1 << 8) | + mode_mask = (1 << 0) | (1 << 8) | (1 << 11) | (1 << 12) | (1 << 15); always_try_alpha_modes = false; @@ -3220,7 +3220,7 @@ namespace basisu estimate_partition = true; break; } - case cPackUASTCLevelDefault: + case cPackUASTCLevelDefault: { mode_mask = (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | @@ -3258,9 +3258,9 @@ namespace basisu // HACK HACK //mode_mask &= ~(1 << 18); //mode_mask = (1 << 18)| (1 << 10); - + uint32_t total_results = 0; - + if (only_use_la_on_transparent_blocks) { if ((is_la) && (!has_alpha)) @@ -3268,7 +3268,7 @@ namespace basisu } const bool try_alpha_modes = has_alpha || always_try_alpha_modes; - + bc7enc_compress_block_params comp_params; memset(&comp_params, 0, sizeof(comp_params)); comp_params.m_max_partitions_mode1 = 64; @@ -3343,7 +3343,7 @@ namespace basisu } assert(total_results); - + // Fix up the errors so we consistently have LA, RGB, or RGBA error. for (uint32_t i = 0; i < total_results; i++) { @@ -3377,7 +3377,7 @@ namespace basisu } } } - + unpacked_uastc_block unpacked_ublock; memset(&unpacked_ublock, 0, sizeof(unpacked_ublock)); @@ -3544,7 +3544,7 @@ namespace basisu const uastc_encode_results& best_results = results[best_index]; const uint32_t best_mode = best_results.m_uastc_mode; const astc_block_desc& best_astc_results = best_results.m_astc; - + color_rgba decoded_uastc_block[4][4]; bool success = unpack_uastc(best_mode, best_results.m_common_pattern, best_results.m_solid_color.get_color32(), best_astc_results, (basist::color32 *)&decoded_uastc_block[0][0], false); (void)success; @@ -3562,14 +3562,14 @@ namespace basisu basist::uastc_block temp_block; pack_uastc(temp_block, best_results, etc1_blk, 0, etc_eac_a8_blk, false, false); - + basist::color32 temp_block_unpacked[4][4]; success = basist::unpack_uastc(temp_block, (basist::color32 *)temp_block_unpacked, false); VALIDATE(success); // Now round trip to packed ASTC and back, then decode to pixels. uint32_t astc_data[4]; - + if (best_results.m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR) pack_astc_solid_block(astc_data, (color32 &)best_results.m_solid_color); else @@ -3587,7 +3587,7 @@ namespace basisu for (uint32_t x = 0; x < 4; x++) { VALIDATE(decoded_astc_block[y][x] == decoded_uastc_block[y][x]); - + VALIDATE(temp_block_unpacked[y][x].c[0] == decoded_uastc_block[y][x].r); VALIDATE(temp_block_unpacked[y][x].c[1] == decoded_uastc_block[y][x].g); VALIDATE(temp_block_unpacked[y][x].c[2] == decoded_uastc_block[y][x].b); @@ -3601,7 +3601,7 @@ namespace basisu bool bc1_hint0 = false, bc1_hint1 = false; if (bc1_hints) compute_bc1_hints(bc1_hint0, bc1_hint1, best_results, block, decoded_uastc_block); - + eac_a8_block eac_a8_blk; if ((g_uastc_mode_has_alpha[best_mode]) && (best_mode != UASTC_MODE_INDEX_SOLID_COLOR)) { @@ -3613,7 +3613,7 @@ namespace basisu uastc_pack_eac_a8_results eac8_a8_results; memset(&eac8_a8_results, 0, sizeof(eac8_a8_results)); uastc_pack_eac_a8(eac8_a8_results, decoded_uastc_block_alpha, 16, 0, eac_a8_mul_search_rad, eac_a8_table_mask); - + // All we care about for hinting is the table and multiplier. eac_a8_blk.m_table = eac8_a8_results.m_table; eac_a8_blk.m_multiplier = eac8_a8_results.m_multiplier; @@ -3813,8 +3813,8 @@ namespace basisu return hash_hsieh((const uint8_t*)&s, sizeof(s)); } }; - - static bool uastc_rdo_blocks(uint32_t first_index, uint32_t last_index, basist::uastc_block* pBlocks, const color_rgba* pBlock_pixels, const uastc_rdo_params& params, uint32_t flags, + + static bool uastc_rdo_blocks(uint32_t first_index, uint32_t last_index, basist::uastc_block* pBlocks, const color_rgba* pBlock_pixels, const uastc_rdo_params& params, uint32_t flags, uint32_t &total_skipped, uint32_t &total_refined, uint32_t &total_modified, uint32_t &total_smooth) { debug_printf("uastc_rdo_blocks: Processing blocks %u to %u\n", first_index, last_index); @@ -3823,7 +3823,7 @@ namespace basisu const bool perceptual = false; std::unordered_map selector_history; - + for (uint32_t block_index = first_index; block_index < last_index; block_index++) { const basist::uastc_block& blk = pBlocks[block_index]; @@ -3873,7 +3873,7 @@ namespace basisu color_rgba decoded_b7_blk[4][4]; unpack_block(texture_format::cBC7, &b7_block, &decoded_b7_blk[0][0]); - + uint64_t bc7_err = 0; for (uint32_t i = 0; i < 16; i++) bc7_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_b7_blk)[i], true); @@ -3928,7 +3928,7 @@ namespace basisu float best_t = cur_ms_err * smooth_block_error_scale + cur_bits * params.m_lambda; - // Now scan through previous blocks, insert their selector bit patterns into the current block, and find + // Now scan through previous blocks, insert their selector bit patterns into the current block, and find // selector bit patterns which don't increase the overall block error too much. for (int prev_block_index = last_block_to_check; prev_block_index >= first_block_to_check; --prev_block_index) { @@ -4050,7 +4050,7 @@ namespace basisu color_rgba decoded_trial_uastc_block[4][4]; bool success = unpack_uastc(results.m_uastc_mode, results.m_common_pattern, results.m_solid_color.get_color32(), results.m_astc, (basist::color32*) & decoded_trial_uastc_block[0][0], false); assert(success); - + BASISU_NOTE_UNUSED(success); uint64_t trial_uastc_err = 0; @@ -4077,7 +4077,7 @@ namespace basisu // Write the modified block pBlocks[block_index] = best_block; - + } // if (best_block_index != block_index) { @@ -4093,8 +4093,8 @@ namespace basisu return true; } - - // This function implements a basic form of rate distortion optimization (RDO) for UASTC. + + // This function implements a basic form of rate distortion optimization (RDO) for UASTC. // It only changes selectors and then updates the hints. It uses very approximate LZ bitprice estimation. // There's A LOT that can be done better in here, but it's a start. // One nice advantage of the method used here is that it works for any input, no matter which or how many modes it uses. @@ -4133,7 +4133,7 @@ namespace basisu { std::lock_guard lck(stat_mutex); - + all_succeeded = all_succeeded && status; total_skipped += job_skipped; total_modified += job_modified; @@ -4152,12 +4152,7 @@ namespace basisu } debug_printf("uastc_rdo: Total modified: %3.2f%%, total skipped: %3.2f%%, total refined: %3.2f%%, total smooth: %3.2f%%\n", total_modified * 100.0f / num_blocks, total_skipped * 100.0f / num_blocks, total_refined * 100.0f / num_blocks, total_smooth * 100.0f / num_blocks); - + return status; } } // namespace basisu - - - - - diff --git a/encoder/basisu_uastc_enc.h b/encoder/basisu_uastc_enc.h index 54d39380..7cd3c622 100644 --- a/encoder/basisu_uastc_enc.h +++ b/encoder/basisu_uastc_enc.h @@ -25,15 +25,15 @@ namespace basisu { // Fastest is the lowest quality, although it's stil substantially higher quality vs. BC1/ETC1. It supports 5 modes. // The output may be somewhat blocky because this setting doesn't support 2/3-subset UASTC modes, but it should be less blocky vs. BC1/ETC1. - // This setting doesn't write BC1 hints, so BC1 transcoding will be slower. + // This setting doesn't write BC1 hints, so BC1 transcoding will be slower. // Transcoded ETC1 quality will be lower because it only considers 2 hints out of 32. // Avg. 43.45 dB cPackUASTCLevelFastest = 0, - + // Faster is ~3x slower than fastest. It supports 9 modes. // Avg. 46.49 dB cPackUASTCLevelFaster = 1, - + // Default is ~5.5x slower than fastest. It supports 14 modes. // Avg. 47.47 dB cPackUASTCLevelDefault = 2, @@ -42,7 +42,7 @@ namespace basisu // Avg. 48.01 dB cPackUASTCLevelSlower = 3, - // VerySlow is ~200x slower than fastest. + // VerySlow is ~200x slower than fastest. // The best quality the codec is capable of, but you'll need to be patient or have a lot of cores. // Avg. 48.24 dB cPackUASTCLevelVerySlow = 4, @@ -53,13 +53,13 @@ namespace basisu // These flags allow you to favor only optimizing for lowest UASTC error, or lowest BC7 error. cPackUASTCFavorUASTCError = 8, cPackUASTCFavorBC7Error = 16, - + cPackUASTCETC1FasterHints = 64, cPackUASTCETC1FastestHints = 128, cPackUASTCETC1DisableFlipAndIndividual = 256, - + // Favor UASTC modes 0 and 10 more than the others (this is experimental, it's useful for RDO compression) - cPackUASTCFavorSimplerModes = 512, + cPackUASTCFavorSimplerModes = 512, }; // pRGBAPixels: Pointer to source 4x4 block of RGBA pixels (R first in memory). @@ -75,18 +75,18 @@ namespace basisu color_rgba m_solid_color; uint64_t m_astc_err; }; - + void pack_uastc(basist::uastc_block& blk, const uastc_encode_results& result, const etc_block& etc1_blk, uint32_t etc1_bias, const eac_a8_block& etc_eac_a8_blk, bool bc1_hint0, bool bc1_hint1); const uint32_t UASCT_RDO_DEFAULT_LZ_DICT_SIZE = 4096; const float UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO = 10.0f; const float UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH = 8.0f; - + // The RDO encoder computes a smoothness factor, from [0,1], for each block. To do this it computes each block's maximum component variance, then it divides this by this factor and clamps the result. // Larger values will result in more blocks being protected from too much distortion. const float UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV = 18.0f; - + // The RDO encoder can artifically boost the error of smooth blocks, in order to suppress distortions on smooth areas of the texture. // The encoder will use this value as the maximum error scale to use on smooth blocks. The larger this value, the better smooth bocks will look. Set to 1.0 to disable this completely. const float UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE = 10.0f; @@ -106,30 +106,30 @@ namespace basisu m_skip_block_rms_thresh = UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH; m_endpoint_refinement = true; m_lz_literal_cost = 100; - + m_max_smooth_block_std_dev = UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV; m_smooth_block_max_error_scale = UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE; } - + // m_lz_dict_size: Size of LZ dictionary to simulate in bytes. The larger this value, the slower the encoder but the higher the quality per LZ compressed bit. uint32_t m_lz_dict_size; // m_lambda: The post-processor tries to reduce distortion+rate*lambda (rate is approximate LZ bits and distortion is scaled MS error). // Larger values push the postprocessor towards optimizing more for lower rate, and smaller values more for distortion. 0=minimal distortion. float m_lambda; - + // m_max_allowed_rms_increase_ratio: How much the RMS error of a block is allowed to increase before a trial is rejected. 1.0=no increase allowed, 1.05=5% increase allowed, etc. float m_max_allowed_rms_increase_ratio; - - // m_skip_block_rms_thresh: Blocks with this much RMS error or more are completely skipped by the RDO encoder. + + // m_skip_block_rms_thresh: Blocks with this much RMS error or more are completely skipped by the RDO encoder. float m_skip_block_rms_thresh; - // m_endpoint_refinement: If true, the post-process will attempt to refine the endpoints of blocks with modified selectors. + // m_endpoint_refinement: If true, the post-process will attempt to refine the endpoints of blocks with modified selectors. bool m_endpoint_refinement; float m_max_smooth_block_std_dev; float m_smooth_block_max_error_scale; - + uint32_t m_lz_literal_cost; }; diff --git a/encoder/basisu_uastc_hdr_4x4_enc.cpp b/encoder/basisu_uastc_hdr_4x4_enc.cpp index dd9d6fbb..4fb9f00c 100644 --- a/encoder/basisu_uastc_hdr_4x4_enc.cpp +++ b/encoder/basisu_uastc_hdr_4x4_enc.cpp @@ -21,10 +21,10 @@ uastc_hdr_4x4_codec_options::uastc_hdr_4x4_codec_options() : void uastc_hdr_4x4_codec_options::init() { astc_hdr_codec_base_options::init(); - + // This was the log bias we used on the initial release. It's too low. //m_q_log_bias = Q_LOG_BIAS_4x4; - + m_q_log_bias = Q_LOG_BIAS_6x6; m_bc6h_err_weight = .85f; @@ -35,7 +35,7 @@ void uastc_hdr_4x4_codec_options::init() m_take_first_non_clamping_mode11_submode = false; m_take_first_non_clamping_mode7_submode = false; #endif - + // Must set the quality level at least once to reset this struct. set_quality_level(cDefaultLevel); } @@ -300,11 +300,11 @@ static void pack_mode11( clear_obj(trial_endpoints); clear_obj(trial_weights); - + for (uint32_t weight_ise_range = first_weight_ise_range; weight_ise_range <= last_weight_ise_range; weight_ise_range++) { const bool direct_only = coptions.m_mode11_direct_only; - + uint32_t endpoint_ise_range = astc_helpers::BISE_256_LEVELS; if (weight_ise_range == astc_helpers::BISE_16_LEVELS) endpoint_ise_range = astc_helpers::BISE_192_LEVELS; @@ -312,7 +312,7 @@ static void pack_mode11( { assert(weight_ise_range < astc_helpers::BISE_16_LEVELS); } - + double trial_error = encode_astc_hdr_block_mode_11(16, pBlock_pixels_half, pBlock_pixels_q16, weight_ise_range, trial_submode11, BIG_FLOAT_VAL, trial_endpoints, trial_weights, coptions, direct_only, endpoint_ise_range, coptions.m_mode11_uber_mode && (weight_ise_range >= astc_helpers::BISE_4_LEVELS) && coptions.m_allow_uber_mode, constrain_ise_weight_selectors, coptions.m_first_mode11_submode, coptions.m_last_mode11_submode, false, cOrdinaryLeastSquares); @@ -325,12 +325,12 @@ static void pack_mode11( results.m_best_submodes[0] = trial_submode11; results.m_constrained_weights = constrain_ise_weight_selectors; - + results.m_best_blk.m_num_partitions = 1; results.m_best_blk.m_color_endpoint_modes[0] = 11; results.m_best_blk.m_weight_ise_range = (uint8_t)weight_ise_range; results.m_best_blk.m_endpoint_ise_range = (uint8_t)endpoint_ise_range; - + memcpy(results.m_best_blk.m_endpoints, trial_endpoints, NUM_MODE11_ENDPOINTS); memcpy(results.m_best_blk.m_weights, trial_weights, 16); @@ -338,14 +338,14 @@ static void pack_mode11( // Sanity checking { half_float block_pixels_half[16][3]; - + for (uint32_t i = 0; i < 16; i++) { block_pixels_half[i][0] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][0]); block_pixels_half[i][1] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][1]); block_pixels_half[i][2] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][2]); } - + half_float unpacked_astc_blk_rgba[4][4][4]; bool res = astc_helpers::decode_block(results.m_best_blk, unpacked_astc_blk_rgba, 4, 4, astc_helpers::cDecodeModeHDR16); assert(res); @@ -363,7 +363,7 @@ static void pack_mode11( // transcode to BC6H assert(results.m_best_blk.m_color_endpoint_modes[0] == 11); - + // Get qlog12 endpoints int e[2][3]; bool success = decode_mode11_to_qlog12(results.m_best_blk.m_endpoints, e, results.m_best_blk.m_endpoint_ise_range); @@ -416,18 +416,18 @@ static void pack_mode7_single_part( results.m_best_block_error = trial_error; results.m_best_submodes[0] = trial_submode7; - + results.m_best_blk.m_num_partitions = 1; results.m_best_blk.m_color_endpoint_modes[0] = 7; results.m_best_blk.m_weight_ise_range = (uint8_t)weight_ise_range; results.m_best_blk.m_endpoint_ise_range = (uint8_t)ise_endpoint_range; - + memcpy(results.m_best_blk.m_endpoints, trial_endpoints, NUM_MODE7_ENDPOINTS); memcpy(results.m_best_blk.m_weights, trial_weights, 16); // transcode to BC6H assert(results.m_best_blk.m_color_endpoint_modes[0] == 7); - + // Get qlog12 endpoints int e[2][3]; if (!decode_mode7_to_qlog12(results.m_best_blk.m_endpoints, e, nullptr, results.m_best_blk.m_endpoint_ise_range)) @@ -581,13 +581,13 @@ static void pack_mode7_2part( trial_blk.m_color_endpoint_modes[1] = 7; uint32_t first_part_index = 0, last_part_index = basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2; - + if (num_estimated_partitions) { first_part_index = 0; last_part_index = num_estimated_partitions; } - + for (uint32_t part_index_iter = first_part_index; part_index_iter < last_part_index; ++part_index_iter) { uint32_t part_index; @@ -602,11 +602,11 @@ static void pack_mode7_2part( if (((1U << part_index) & coptions.m_mode7_part2_part_masks) == 0) continue; } - + const uint32_t astc_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_astc; const uint32_t bc7_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_bc7; const bool invert_flag = basist::g_astc_bc7_common_partitions2[part_index].m_invert; - + half_float part_pixels_half[2][16][3]; vec4F part_pixels_q16[2][16]; @@ -623,7 +623,7 @@ static void pack_mode7_2part( part = 1 - part; pixel_part_index[y][x] = part; - + const uint32_t n = num_part_pixels[part]; part_pixels_half[part][n][0] = pBlock_pixels_half[x + y * 4][0]; @@ -636,7 +636,7 @@ static void pack_mode7_2part( } trial_blk.m_partition_id = (uint16_t)astc_pattern; - + for (uint32_t weight_ise_range = first_weight_ise_range; weight_ise_range <= last_weight_ise_range; weight_ise_range++) { assert(weight_ise_range <= astc_helpers::BISE_8_LEVELS); @@ -683,7 +683,7 @@ static void pack_mode7_2part( trial_blk.m_weights[x + y * 4] = trial_weights[p][src_pixel_index[p]++]; } } - + astc_hdr_4x4_pack_results results; results.clear(); @@ -723,7 +723,7 @@ static void pack_mode11_2part( trial_blk.m_num_partitions = 2; trial_blk.m_color_endpoint_modes[0] = 11; trial_blk.m_color_endpoint_modes[1] = 11; - + uint32_t first_part_index = 0, last_part_index = basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2; if (num_estimated_partitions) @@ -767,7 +767,7 @@ static void pack_mode11_2part( part = 1 - part; pixel_part_index[y][x] = part; - + const uint32_t n = num_part_pixels[part]; part_pixels_half[part][n][0] = pBlock_pixels_half[x + y * 4][0]; @@ -778,9 +778,9 @@ static void pack_mode11_2part( num_part_pixels[part] = n + 1; } } - + trial_blk.m_partition_id = (uint16_t)astc_pattern; - + for (uint32_t weight_ise_range = coptions.m_first_mode11_part2_weight_ise_range; weight_ise_range <= coptions.m_last_mode11_part2_weight_ise_range; weight_ise_range++) { bool direct_only = false; @@ -791,7 +791,7 @@ static void pack_mode11_2part( uint8_t trial_endpoints[2][NUM_MODE11_ENDPOINTS], trial_weights[2][16]; uint32_t trial_submode11[2]; - clear_obj(trial_endpoints); + clear_obj(trial_endpoints); clear_obj(trial_weights); clear_obj(trial_submode11); @@ -824,7 +824,7 @@ static void pack_mode11_2part( trial_blk.m_weights[x + y * 4] = trial_weights[p][src_pixel_index[p]++]; } } - + astc_hdr_4x4_pack_results results; results.clear(); @@ -865,12 +865,12 @@ bool astc_hdr_4x4_enc_block( all_results.resize(0); const half_float (*pBlock_pixels_half)[16][3] = reinterpret_cast(pRGBPixelsHalf); - + vec4F block_linear_colors[16]; vec4F block_pixels_q16[16]; bool is_greyscale = true; - + for (uint32_t i = 0; i < 16; i++) { const float fr = pRGBPixels[i * 3 + 0], fg = pRGBPixels[i * 3 + 1], fb = pRGBPixels[i * 3 + 2]; @@ -893,13 +893,13 @@ bool astc_hdr_4x4_enc_block( const half_float hb = (*pBlock_pixels_half)[i][2]; assert(hb == basist::float_to_half(fb)); block_pixels_q16[i][2] = (float)half_to_qlog16(hb); - + block_pixels_q16[i][3] = 0.0f; if ((hr != hg) || (hr != hb)) is_greyscale = false; } // i - + bool is_solid = false; if (coptions.m_use_solid) is_solid = pack_solid(block_linear_colors, all_results, coptions); @@ -919,14 +919,14 @@ bool astc_hdr_4x4_enc_block( const size_t cur_num_results = all_results.size(); pack_mode11(block_linear_colors, *pBlock_pixels_half, block_pixels_q16, all_results, coptions, coptions.m_first_mode11_weight_ise_range, coptions.m_last_mode11_weight_ise_range, false); - + if (coptions.m_last_mode11_weight_ise_range >= astc_helpers::BISE_12_LEVELS) { // Try constrained weights if we're allowed to use 12/16 level ISE weight modes pack_mode11(block_linear_colors, *pBlock_pixels_half, block_pixels_q16, all_results, coptions, maximum(coptions.m_first_mode11_weight_ise_range, astc_helpers::BISE_12_LEVELS), coptions.m_last_mode11_weight_ise_range, true); } - // If we couldn't get any mode 11 results at all, and we were restricted to just trying weight ISE range 8 (which required endpoint quantization) then + // If we couldn't get any mode 11 results at all, and we were restricted to just trying weight ISE range 8 (which required endpoint quantization) then // fall back to weight ISE range 7 (which doesn't need any endpoint quantization). // This is to guarantee we always get at least 1 non-solid result. if (all_results.size() == cur_num_results) @@ -950,7 +950,7 @@ bool astc_hdr_4x4_enc_block( pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, UHDR_MODE7_PART1_LAST_ISE_RANGE, UHDR_MODE7_PART1_LAST_ISE_RANGE); } } - + bool have_est = false; int best_parts[basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2]; @@ -965,22 +965,22 @@ bool astc_hdr_4x4_enc_block( const size_t cur_num_results = all_results.size(); pack_mode7_2part(*pBlock_pixels_half, block_pixels_q16, - all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, + all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, coptions.m_first_mode7_part2_weight_ise_range, coptions.m_last_mode7_part2_weight_ise_range); - // If we couldn't find any packable 2-subset mode 7 results at weight levels >= 5 levels (which always requires endpoint quant), then try falling back to + // If we couldn't find any packable 2-subset mode 7 results at weight levels >= 5 levels (which always requires endpoint quant), then try falling back to // 5 levels which doesn't require endpoint quantization. if (all_results.size() == cur_num_results) { if (coptions.m_first_mode7_part2_weight_ise_range >= astc_helpers::BISE_5_LEVELS) { pack_mode7_2part(*pBlock_pixels_half, block_pixels_q16, - all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, + all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, astc_helpers::BISE_4_LEVELS, astc_helpers::BISE_4_LEVELS); } } } - + if (coptions.m_use_mode11_part2) { // This always requires endpoint quant, so it could fail to find any usable solutions. @@ -1027,7 +1027,7 @@ bool astc_hdr_4x4_pack_results_to_block(astc_blk& dst_blk, const astc_hdr_4x4_pa } // Refines a block's chosen weight indices, balancing BC6H and ASTC HDR error. -bool astc_hdr_4x4_refine_weights(const half_float *pSource_block, +bool astc_hdr_4x4_refine_weights(const half_float *pSource_block, astc_hdr_4x4_pack_results& cur_results, const uastc_hdr_4x4_codec_options& coptions, float bc6h_weight, bool *pImproved_flag) { if (pImproved_flag) @@ -1059,7 +1059,7 @@ bool astc_hdr_4x4_refine_weights(const half_float *pSource_block, temp_results = cur_results; for (uint32_t i = 0; i < 16; i++) temp_results.m_best_blk.m_weights[i] = (uint8_t)weight_index; - + half_float unpacked_astc_blk_rgba[4][4][4]; bool res = astc_helpers::decode_block(temp_results.m_best_blk, unpacked_astc_blk_rgba, 4, 4, astc_helpers::cDecodeModeHDR16); assert(res); @@ -1067,7 +1067,7 @@ bool astc_hdr_4x4_refine_weights(const half_float *pSource_block, basist::bc6h_block trial_bc6h_blk; res = basist::astc_hdr_transcode_to_bc6h(temp_results.m_best_blk, trial_bc6h_blk); assert(res); - + half_float unpacked_bc6h_blk[4][4][3]; res = unpack_bc6h(&trial_bc6h_blk, unpacked_bc6h_blk, false); assert(res); @@ -1083,11 +1083,11 @@ bool astc_hdr_4x4_refine_weights(const half_float *pSource_block, { const half_float orig_c = pSource_block[(x + y * 4) * 3 + c]; const double orig_c_q = q(orig_c, Q_LOG_BIAS_4x4); - + const half_float astc_c = unpacked_astc_blk_rgba[y][x][c]; const double astc_c_q = q(astc_c, Q_LOG_BIAS_4x4); const double astc_e = square(astc_c_q - orig_c_q) * c_weights[c]; - + const half_float bc6h_c = unpacked_bc6h_blk[y][x][c]; const double bc6h_c_q = q(bc6h_c, Q_LOG_BIAS_4x4); const double bc6h_e = square(bc6h_c_q - orig_c_q) * c_weights[c]; @@ -1274,4 +1274,3 @@ void astc_hdr_4x4_block_stats::print() } } // namespace basisu - diff --git a/encoder/basisu_uastc_hdr_4x4_enc.h b/encoder/basisu_uastc_hdr_4x4_enc.h index 390520a8..e0a121c5 100644 --- a/encoder/basisu_uastc_hdr_4x4_enc.h +++ b/encoder/basisu_uastc_hdr_4x4_enc.h @@ -62,21 +62,21 @@ namespace basisu struct astc_hdr_4x4_pack_results { double m_best_block_error; - double m_bc6h_block_error; // note this is not used/set by the encoder, here for convienance + double m_bc6h_block_error; // note this is not used/set by the encoder, here for convienance // Encoder results (logical ASTC block) astc_helpers::log_astc_block m_best_blk; - + // For statistical use uint32_t m_best_submodes[2]; uint32_t m_best_pat_index; bool m_constrained_weights; bool m_improved_via_refinement_flag; - + // Only valid if the block is solid basist::astc_blk m_solid_blk; - + // The BC6H transcoded block basist::bc6h_block m_bc6h_block; @@ -97,29 +97,29 @@ namespace basisu m_best_pat_index = 0; m_constrained_weights = false; - + clear_obj(m_bc6h_block); - + m_is_solid = false; m_improved_via_refinement_flag = false; } }; - + // Encodes a 4x4 ASTC HDR block given a 4x4 array of source block pixels/texels. - // Supports solid color blocks, mode 11 (all submodes), mode 7/1 partition (all submodes), + // Supports solid color blocks, mode 11 (all submodes), mode 7/1 partition (all submodes), // and mode 7/2 partitions (all submodes) - 30 patterns, only the ones also in common with the BC6H format. // The packed ASTC weight grid dimensions are currently always 4x4 texels, but may be also 3x3 in the future. // This function is thread safe, i.e. it may be called from multiple encoding threads simultanously with different blocks. - // + // // Parameters: // pRGBPixels - An array of 48 (16 RGB) floats: the 4x4 block to pack // pPacked_block - A pointer to the packed ASTC HDR block // coptions - Codec options // pInternal_results - An optional pointer to details about how the block was packed, for statistics/debugging purposes. May be nullptr. - // - // Requirements: + // + // Requirements: // astc_hdr_enc_init() MUST have been called first to initialized the codec. - // Input pixels are checked and cannot be NaN's, Inf's, signed, or too large (greater than MAX_HALF_FLOAT, or 65504). + // Input pixels are checked and cannot be NaN's, Inf's, signed, or too large (greater than MAX_HALF_FLOAT, or 65504). // Normal values and denormals are okay. bool astc_hdr_4x4_enc_block( const float* pRGBPixels, const basist::half_float *pRGBPixelsHalf, @@ -127,7 +127,7 @@ namespace basisu basisu::vector &all_results); bool astc_hdr_4x4_pack_results_to_block(basist::astc_blk& dst_blk, const astc_hdr_4x4_pack_results& results); - + bool astc_hdr_4x4_refine_weights(const basist::half_float* pSource_block, astc_hdr_4x4_pack_results& cur_results, const uastc_hdr_4x4_codec_options& coptions, float bc6h_weight, bool* pImproved_flag); struct astc_hdr_4x4_block_stats @@ -147,11 +147,11 @@ namespace basisu uint32_t m_weight_range_hist_11[11]; uint32_t m_weight_range_hist_11_2part[11]; uint32_t m_mode11_submode_hist[9]; - + uint32_t m_part_hist[32]; uint32_t m_total_refined; - + astc_hdr_4x4_block_stats() { clear(); } void clear() @@ -173,9 +173,8 @@ namespace basisu } void update(const astc_hdr_4x4_pack_results& log_blk); - + void print(); }; - -} // namespace basisu +} // namespace basisu diff --git a/encoder/cppspmd_flow.h b/encoder/cppspmd_flow.h index 93934173..07b59245 100644 --- a/encoder/cppspmd_flow.h +++ b/encoder/cppspmd_flow.h @@ -48,7 +48,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_return() m_kernel_exec = andnot(m_exec, m_kernel_exec); m_exec = exec_mask::all_off(); } - + template CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_unmasked(const UnmaskedBody& unmaskedBody) { @@ -61,7 +61,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_unmasked(const UnmaskedBody& unmaske m_kernel_exec = m_kernel_exec & orig_kernel_exec; m_exec = m_exec & orig_exec; - + check_masks(); } @@ -69,9 +69,9 @@ struct scoped_unmasked_restorer { spmd_kernel *m_pKernel; exec_mask m_orig_exec, m_orig_kernel_exec; - - CPPSPMD_FORCE_INLINE scoped_unmasked_restorer(spmd_kernel *pKernel) : - m_pKernel(pKernel), + + CPPSPMD_FORCE_INLINE scoped_unmasked_restorer(spmd_kernel *pKernel) : + m_pKernel(pKernel), m_orig_exec(pKernel->m_exec), m_orig_kernel_exec(pKernel->m_kernel_exec) { @@ -79,15 +79,15 @@ struct scoped_unmasked_restorer pKernel->m_exec = exec_mask::all_on(); } - CPPSPMD_FORCE_INLINE ~scoped_unmasked_restorer() - { + CPPSPMD_FORCE_INLINE ~scoped_unmasked_restorer() + { m_pKernel->m_kernel_exec = m_pKernel->m_kernel_exec & m_orig_kernel_exec; m_pKernel->m_exec = m_pKernel->m_exec & m_orig_exec; m_pKernel->check_masks(); } }; -#define SPMD_UNMASKED_BEGIN { scoped_unmasked_restorer _unmasked_restorer(this); +#define SPMD_UNMASKED_BEGIN { scoped_unmasked_restorer _unmasked_restorer(this); #define SPMD_UNMASKED_END } #if 0 @@ -113,9 +113,9 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if_break(const vbool& cond) #ifdef _DEBUG assert(m_in_loop); #endif - + exec_mask cond_exec(cond); - + m_exec = andnot(m_exec & cond_exec, m_exec); check_masks(); @@ -157,7 +157,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_sifelse(const vbool& cond, const IfB m_exec = em; elseBody(); } - + m_exec = orig_exec; } @@ -165,7 +165,7 @@ template CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if(const vbool& cond, const IfBody& ifBody) { exec_mask cond_exec(cond); - + exec_mask pre_if_exec = cond_exec & m_exec; if (any(pre_if_exec)) @@ -188,7 +188,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_ifelse(const vbool& cond, const IfBo bool all_flag = false; exec_mask cond_exec(cond); - + { exec_mask pre_if_exec = cond_exec & m_exec; @@ -290,17 +290,17 @@ struct scoped_exec_restorer2 { spmd_kernel *m_pKernel; exec_mask m_unexecuted_lanes; - - CPPSPMD_FORCE_INLINE scoped_exec_restorer2(spmd_kernel *pKernel, const vbool &cond) : + + CPPSPMD_FORCE_INLINE scoped_exec_restorer2(spmd_kernel *pKernel, const vbool &cond) : m_pKernel(pKernel) - { + { exec_mask cond_exec(cond); m_unexecuted_lanes = andnot(cond_exec, pKernel->m_exec); pKernel->m_exec = cond_exec & pKernel->m_exec; } - CPPSPMD_FORCE_INLINE ~scoped_exec_restorer2() - { + CPPSPMD_FORCE_INLINE ~scoped_exec_restorer2() + { m_pKernel->m_exec = m_pKernel->m_exec | m_unexecuted_lanes; m_pKernel->check_masks(); } @@ -327,17 +327,17 @@ class scoped_exec_saver inline scoped_exec_saver(spmd_kernel *pKernel) : m_exec(pKernel->m_exec), m_kernel_exec(pKernel->m_kernel_exec), m_continue_mask(pKernel->m_continue_mask), m_pKernel(pKernel) - { + { #ifdef _DEBUG m_in_loop = pKernel->m_in_loop; #endif } - + inline ~scoped_exec_saver() - { - m_pKernel->m_exec = m_exec; - m_pKernel->m_continue_mask = m_continue_mask; - m_pKernel->m_kernel_exec = m_kernel_exec; + { + m_pKernel->m_exec = m_exec; + m_pKernel->m_continue_mask = m_continue_mask; + m_pKernel->m_kernel_exec = m_kernel_exec; #ifdef _DEBUG m_pKernel->m_in_loop = m_in_loop; m_pKernel->check_masks(); @@ -353,7 +353,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_foreach(int begin, int end, const Fo { if (begin == end) return; - + if (!any(m_exec)) return; @@ -362,12 +362,12 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_foreach(int begin, int end, const Fo std::swap(begin, end); exec_mask prev_continue_mask = m_continue_mask, prev_exec = m_exec; - + int total_full = (end - begin) / PROGRAM_COUNT; int total_partial = (end - begin) % PROGRAM_COUNT; lint_t loop_index = begin + program_index; - + const int total_loops = total_full + (total_partial ? 1 : 0); m_continue_mask = exec_mask::all_off(); @@ -390,7 +390,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_foreach(int begin, int end, const Fo m_continue_mask = exec_mask::all_off(); check_masks(); - + store_all(loop_index, loop_index + PROGRAM_COUNT); } @@ -443,9 +443,9 @@ struct scoped_while_restorer #ifdef _DEBUG bool m_prev_in_loop; #endif - - CPPSPMD_FORCE_INLINE scoped_while_restorer(spmd_kernel *pKernel) : - m_pKernel(pKernel), + + CPPSPMD_FORCE_INLINE scoped_while_restorer(spmd_kernel *pKernel) : + m_pKernel(pKernel), m_orig_exec(pKernel->m_exec), m_orig_continue_mask(pKernel->m_continue_mask) { @@ -457,8 +457,8 @@ struct scoped_while_restorer #endif } - CPPSPMD_FORCE_INLINE ~scoped_while_restorer() - { + CPPSPMD_FORCE_INLINE ~scoped_while_restorer() + { m_pKernel->m_exec = m_orig_exec & m_pKernel->m_kernel_exec; m_pKernel->m_continue_mask = m_orig_continue_mask; #ifdef _DEBUG @@ -514,7 +514,7 @@ struct scoped_simple_while_restorer m_pKernel(pKernel), m_orig_exec(pKernel->m_exec) { - + #ifdef _DEBUG m_prev_in_loop = pKernel->m_in_loop; pKernel->m_in_loop = true; @@ -536,18 +536,18 @@ struct scoped_simple_while_restorer #define SPMD_SWHILE(cond) { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \ while(true) { \ exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; -#define SPMD_SWEND } } +#define SPMD_SWEND } } // Cannot use SPMD break, continue, or return inside simple do #define SPMD_SDO { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { -#define SPMD_SEND_DO(cond) exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; } } +#define SPMD_SEND_DO(cond) exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; } } #undef SPMD_FOR #undef SPMD_END_FOR #define SPMD_FOR(for_init, for_cond) { for_init; scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(for_cond)); \ m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; #define SPMD_END_FOR(for_inc) m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); for_inc; } } - + template CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_for(const ForInitBody& forInitBody, const ForCondBody& forCondBody, const ForIncrBody& forIncrBody, const ForBody& forBody) { @@ -576,7 +576,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_for(const ForInitBody& forInitBody, m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); - + forIncrBody(); } diff --git a/encoder/cppspmd_math.h b/encoder/cppspmd_math.h index 3032df86..40403240 100644 --- a/encoder/cppspmd_math.h +++ b/encoder/cppspmd_math.h @@ -15,21 +15,21 @@ // limitations under the License. // The general goal of these vectorized estimated math functions is scalability/performance. -// There are explictly no checks NaN's/Inf's on the input arguments. There are no assertions either. -// These are fast estimate functions - if you need more than that, use stdlib. Please do a proper +// There are explictly no checks NaN's/Inf's on the input arguments. There are no assertions either. +// These are fast estimate functions - if you need more than that, use stdlib. Please do a proper // engineering analysis before relying on them. // I have chosen functions written by others, ported them to CppSPMD, then measured their abs/rel errors. // I compared each to the ones in DirectXMath and stdlib's for accuracy/performance. -CPPSPMD_FORCE_INLINE vfloat fmod_inv(const vfloat& a, const vfloat& b, const vfloat& b_inv) -{ - vfloat c = frac(abs(a * b_inv)) * abs(b); - return spmd_ternaryf(a < 0, -c, c); +CPPSPMD_FORCE_INLINE vfloat fmod_inv(const vfloat& a, const vfloat& b, const vfloat& b_inv) +{ + vfloat c = frac(abs(a * b_inv)) * abs(b); + return spmd_ternaryf(a < 0, -c, c); } -CPPSPMD_FORCE_INLINE vfloat fmod_inv_p(const vfloat& a, const vfloat& b, const vfloat& b_inv) -{ - return frac(a * b_inv) * b; +CPPSPMD_FORCE_INLINE vfloat fmod_inv_p(const vfloat& a, const vfloat& b, const vfloat& b_inv) +{ + return frac(a * b_inv) * b; } // Avoids dividing by zero or very small values. @@ -87,13 +87,13 @@ inline vfloat spmd_kernel::log2_est(vfloat v) vint greater = ux1_i & 0x00400000; // true if signif > 1.5 SPMD_SIF(greater != 0) { - // signif >= 1.5 so need to divide by 2. Accomplish this by stuffing exp = 126 which corresponds to an exponent of -1 + // signif >= 1.5 so need to divide by 2. Accomplish this by stuffing exp = 126 which corresponds to an exponent of -1 store_all(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f000000); store_all(ux2_f, cast_vint_to_vfloat(ux2_i)); // 126 instead of 127 compensates for division by 2 - store_all(fexp, vfloat(exp - 126)); + store_all(fexp, vfloat(exp - 126)); } SPMD_SELSE(greater != 0) { @@ -113,9 +113,9 @@ inline vfloat spmd_kernel::log2_est(vfloat v) vfloat xm1 = signif; vfloat xm1sqr = xm1 * xm1; - + return fexp + ((a * (xm1sqr * xm1) + b * xm1sqr + c * xm1) / (xm1sqr + d * xm1 + e)); - + // fma lowers accuracy for SSE4.1 - no idea why (compiler reordering?) //return fexp + ((vfma(a, (xm1sqr * xm1), vfma(b, xm1sqr, c * xm1))) / (xm1sqr + vfma(d, xm1, e))); } @@ -130,15 +130,15 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::reduce_expb(vfloat& arg, vfloat& two_int_ { // Assume we're using equation (2) store_all(adjustment, 0); - + // integer part of the input argument vint int_arg = (vint)arg; - + // if frac(arg) is in [0.5, 1.0]... - SPMD_SIF((arg - int_arg) > 0.5f) + SPMD_SIF((arg - int_arg) > 0.5f) { store(adjustment, 1); - + // then change it to [0.0, 0.5] store(arg, arg - 0.5f); } @@ -146,17 +146,17 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::reduce_expb(vfloat& arg, vfloat& two_int_ // arg == just the fractional part store_all(arg, arg - (vfloat)int_arg); - - // Now compute 2** (int) arg. + + // Now compute 2** (int) arg. store_all(int_arg, min(int_arg + 127, 254)); - + store_all(two_int_a, cast_vint_to_vfloat(VINT_SHIFT_LEFT(int_arg, 23))); } /* clang 9.0.0 for win /fp:precise release f range : -50.0000000000000000 49.9999940395355225, vals : 16777216 - + exp2_est(): Total passed near - zero check : 16777216 Total sign diffs : 0 @@ -164,7 +164,7 @@ CPPSPMD_FORCE_INLINE void spmd_kernel::reduce_expb(vfloat& arg, vfloat& two_int_ max rel err: 0.0000015642030031 avg abs err: 10793794.4007573910057545 avg rel err: 0.0000003890893282 - + XMVectorExp2(): Total passed near-zero check: 16777216 Total sign diffs: 0 @@ -191,11 +191,11 @@ inline vfloat spmd_kernel::exp2_est(vfloat arg) const vfloat P01 = +0.0576900723731f; const vfloat Q00 = +20.8189237930062f; const vfloat Q01 = +1.0f; - const vfloat sqrt2 = 1.4142135623730950488f; // sqrt(2) for scaling + const vfloat sqrt2 = 1.4142135623730950488f; // sqrt(2) for scaling vfloat result = 0.0f; - // Return 0 if arg is too large. + // Return 0 if arg is too large. // We're not introducing inf/nan's into calculations, or risk doing so by returning huge default values. SPMD_IF(abs(arg) > 126.0f) { @@ -204,13 +204,13 @@ inline vfloat spmd_kernel::exp2_est(vfloat arg) SPMD_END_IF // 2**(int(a)) - vfloat two_int_a; - + vfloat two_int_a; + // set to 1 by reduce_expb vint adjustment; - + // 0 if arg is +; 1 if negative - vint negative = 0; + vint negative = 0; // If the input is negative, invert it. At the end we'll take the reciprocal, since n**(-1) = 1/(n**x). SPMD_SIF(arg < 0.0f) @@ -232,15 +232,15 @@ inline vfloat spmd_kernel::exp2_est(vfloat arg) // Q(x**2) vfloat Q = vfma(Q01, (arg * arg), Q00); - + // x*P(x**2) vfloat x_P = arg * (vfma(P01, arg * arg, P00)); - + vfloat answer = (Q + x_P) / (Q - x_P); // Now correct for the scaling factor of 2**(int(a)) store_all(answer, answer * two_int_a); - + // If the result had a fractional part > 0.5, correct for that store_all(answer, spmd_ternaryf(adjustment != 0, answer * sqrt2, answer)); @@ -295,35 +295,35 @@ inline vfloat spmd_kernel::sincos_est_a(vfloat a, bool sin_flag) store_all(r1_x, sin_flag ? vfms(c1_w, a, c1_x) : c1_w * a); - store_all(r1_y, frac(r1_x)); - - store_all(r2_x, (vfloat)(r1_y < c1_x)); + store_all(r1_y, frac(r1_x)); + + store_all(r2_x, (vfloat)(r1_y < c1_x)); - store_all(r2_y, (vfloat)(r1_y >= c1_y)); - store_all(r2_z, (vfloat)(r1_y >= c1_z)); + store_all(r2_y, (vfloat)(r1_y >= c1_y)); + store_all(r2_z, (vfloat)(r1_y >= c1_z)); store_all(r2_y, vfma(r2_x, c4_z, vfma(r2_y, c4_w, r2_z * c4_z))); - store_all(r0_x, c0_x - r1_y); - store_all(r0_y, c0_y - r1_y); - store_all(r0_z, c0_z - r1_y); - + store_all(r0_x, c0_x - r1_y); + store_all(r0_y, c0_y - r1_y); + store_all(r0_z, c0_z - r1_y); + store_all(r0_x, r0_x * r0_x); store_all(r0_y, r0_y * r0_y); store_all(r0_z, r0_z * r0_z); - store_all(r1_x, vfma(c2_x, r0_x, c2_z)); - store_all(r1_y, vfma(c2_y, r0_y, c2_w)); - store_all(r1_z, vfma(c2_x, r0_z, c2_z)); - + store_all(r1_x, vfma(c2_x, r0_x, c2_z)); + store_all(r1_y, vfma(c2_y, r0_y, c2_w)); + store_all(r1_z, vfma(c2_x, r0_z, c2_z)); + store_all(r1_x, vfma(r1_x, r0_x, c3_x)); store_all(r1_y, vfma(r1_y, r0_y, c3_y)); store_all(r1_z, vfma(r1_z, r0_z, c3_x)); - + store_all(r1_x, vfma(r1_x, r0_x, c3_z)); store_all(r1_y, vfma(r1_y, r0_y, c3_w)); store_all(r1_z, vfma(r1_z, r0_z, c3_z)); - + store_all(r1_x, vfma(r1_x, r0_x, c4_x)); store_all(r1_y, vfma(r1_y, r0_y, c4_y)); store_all(r1_z, vfma(r1_z, r0_z, c4_x)); @@ -347,9 +347,9 @@ CPPSPMD_FORCE_INLINE vfloat spmd_kernel::recip_est1(const vfloat& q) vfloat l = spmd_ternaryf(q >= fMinThresh, q, cast_vint_to_vfloat(vint(mag))); vint x_l = vint(mag) - cast_vfloat_to_vint(l); - + vfloat rcp_l = cast_vint_to_vfloat(x_l); - + return rcp_l * vfnma(rcp_l, q, 2.0f); } @@ -395,12 +395,12 @@ CPPSPMD_FORCE_INLINE vfloat spmd_kernel::atan2_est(vfloat y, vfloat x) { vfloat t1 = abs(y); vfloat t3 = abs(x); - + vfloat t0 = max(t3, t1); store_all(t1, min(t3, t1)); store_all(t3, t1 / t0); - + vfloat t4 = t3 * t3; store_all(t0, vfma(-0.013480470f, t4, 0.057477314f)); store_all(t0, vfms(t0, t4, 0.121239071f)); @@ -452,7 +452,7 @@ CPPSPMD_FORCE_INLINE vfloat spmd_kernel::atan2_est(vfloat y, vfloat x) max abs err: 0.8989131818294709 max rel err: 0.0573181403173166 avg rel err: 0.0000030791301203 - + Originally from: http://www.ganssle.com/approx.htm */ @@ -495,7 +495,7 @@ inline vfloat spmd_kernel::tan_est(vfloat x) vfloat z = tan82(y); vfloat r; - + vbool octant_one_or_two = (octant == 1) || (octant == 2); // SPMD optimization - skip costly divide if we can @@ -503,7 +503,7 @@ inline vfloat spmd_kernel::tan_est(vfloat x) { const float fDivThresh = .4371e-7f; vfloat one_over_z = 1.0f / spmd_ternaryf(abs(z) > fDivThresh, z, spmd_ternaryf(z < 0.0f, -fDivThresh, fDivThresh)); - + vfloat b = spmd_ternaryf(octant_one_or_two, one_over_z, z); store_all(r, spmd_ternaryf((octant & 2) != 0, -b, b)); } @@ -511,7 +511,7 @@ inline vfloat spmd_kernel::tan_est(vfloat x) { store_all(r, spmd_ternaryf(octant == 0, z, -z)); } - + // Small angle approximation, to decrease the max rel error near Pi. SPMD_SIF(x >= (1.0f - .0003125f*4.0f)) { @@ -523,25 +523,25 @@ inline vfloat spmd_kernel::tan_est(vfloat x) } inline void spmd_kernel::seed_rand(rand_context& x, vint seed) -{ - store(x.a, 0xf1ea5eed); - store(x.b, seed ^ 0xd8487b1f); - store(x.c, seed ^ 0xdbadef9a); - store(x.d, seed); - for (int i = 0; i < 20; ++i) - (void)get_randu(x); +{ + store(x.a, 0xf1ea5eed); + store(x.b, seed ^ 0xd8487b1f); + store(x.c, seed ^ 0xdbadef9a); + store(x.d, seed); + for (int i = 0; i < 20; ++i) + (void)get_randu(x); } // https://burtleburtle.net/bob/rand/smallprng.html // Returns 32-bit unsigned random numbers. inline vint spmd_kernel::get_randu(rand_context& x) -{ - vint e = x.a - VINT_ROT(x.b, 27); - store(x.a, x.b ^ VINT_ROT(x.c, 17)); - store(x.b, x.c + x.d); - store(x.c, x.d + e); - store(x.d, e + x.a); - return x.d; +{ + vint e = x.a - VINT_ROT(x.b, 27); + store(x.a, x.b ^ VINT_ROT(x.c, 17)); + store(x.b, x.c + x.d); + store(x.c, x.d + e); + store(x.d, e + x.a); + return x.d; } // Returns random numbers between [low, high), or low if low >= high @@ -552,7 +552,7 @@ inline vint spmd_kernel::get_randi(rand_context& x, vint low, vint high) vint range = high - low; vint rnd_range = mulhiu(rnd, range); - + return spmd_ternaryi(low < high, low + rnd_range, low); } @@ -637,25 +637,25 @@ CPPSPMD_FORCE_INLINE vint spmd_kernel::count_trailing_zeros(vint x) { // cast the least significant bit in v to a float vfloat f = (vfloat)(x & -x); - + // extract exponent and adjust return VUINT_SHIFT_RIGHT(cast_vfloat_to_vint(f), 23) - 0x7F; } CPPSPMD_FORCE_INLINE vint spmd_kernel::count_set_bits(vint x) { - vint v = x - (VUINT_SHIFT_RIGHT(x, 1) & 0x55555555); - vint v1 = (v & 0x33333333) + (VUINT_SHIFT_RIGHT(v, 2) & 0x33333333); + vint v = x - (VUINT_SHIFT_RIGHT(x, 1) & 0x55555555); + vint v1 = (v & 0x33333333) + (VUINT_SHIFT_RIGHT(v, 2) & 0x33333333); return VUINT_SHIFT_RIGHT(((v1 + (VUINT_SHIFT_RIGHT(v1, 4) & 0xF0F0F0F)) * 0x1010101), 24); } -CPPSPMD_FORCE_INLINE vint cmple_epu16(const vint &a, const vint &b) -{ - return cmpeq_epi16(subs_epu16(a, b), vint(0)); +CPPSPMD_FORCE_INLINE vint cmple_epu16(const vint &a, const vint &b) +{ + return cmpeq_epi16(subs_epu16(a, b), vint(0)); } -CPPSPMD_FORCE_INLINE vint cmpge_epu16(const vint &a, const vint &b) -{ +CPPSPMD_FORCE_INLINE vint cmpge_epu16(const vint &a, const vint &b) +{ return cmple_epu16(b, a); } @@ -679,29 +679,29 @@ CPPSPMD_FORCE_INLINE vint cmple_epi16(const vint &a, const vint &b) return cmpge_epi16(b, a); } -void spmd_kernel::print_vint(vint v) -{ - for (uint32_t i = 0; i < PROGRAM_COUNT; i++) - printf("%i ", extract(v, i)); - printf("\n"); +void spmd_kernel::print_vint(vint v) +{ + for (uint32_t i = 0; i < PROGRAM_COUNT; i++) + printf("%i ", extract(v, i)); + printf("\n"); } -void spmd_kernel::print_vbool(vbool v) -{ - for (uint32_t i = 0; i < PROGRAM_COUNT; i++) - printf("%i ", extract(v, i) ? 1 : 0); - printf("\n"); +void spmd_kernel::print_vbool(vbool v) +{ + for (uint32_t i = 0; i < PROGRAM_COUNT; i++) + printf("%i ", extract(v, i) ? 1 : 0); + printf("\n"); } - -void spmd_kernel::print_vint_hex(vint v) -{ - for (uint32_t i = 0; i < PROGRAM_COUNT; i++) - printf("0x%X ", extract(v, i)); - printf("\n"); + +void spmd_kernel::print_vint_hex(vint v) +{ + for (uint32_t i = 0; i < PROGRAM_COUNT; i++) + printf("0x%X ", extract(v, i)); + printf("\n"); } -void spmd_kernel::print_active_lanes(const char *pPrefix) -{ +void spmd_kernel::print_active_lanes(const char *pPrefix) +{ CPPSPMD_DECL(int, flags[PROGRAM_COUNT]); memset(flags, 0, sizeof(flags)); storeu_linear(flags, vint(1)); @@ -709,17 +709,17 @@ void spmd_kernel::print_active_lanes(const char *pPrefix) if (pPrefix) printf("%s", pPrefix); - for (uint32_t i = 0; i < PROGRAM_COUNT; i++) + for (uint32_t i = 0; i < PROGRAM_COUNT; i++) { if (flags[i]) printf("%u ", i); } printf("\n"); } - -void spmd_kernel::print_vfloat(vfloat v) -{ - for (uint32_t i = 0; i < PROGRAM_COUNT; i++) - printf("%f ", extract(v, i)); - printf("\n"); + +void spmd_kernel::print_vfloat(vfloat v) +{ + for (uint32_t i = 0; i < PROGRAM_COUNT; i++) + printf("%f ", extract(v, i)); + printf("\n"); } diff --git a/encoder/cppspmd_math_declares.h b/encoder/cppspmd_math_declares.h index f76c9b7e..592e0b95 100644 --- a/encoder/cppspmd_math_declares.h +++ b/encoder/cppspmd_math_declares.h @@ -54,7 +54,7 @@ CPPSPMD_FORCE_INLINE vfloat atan2_est(vfloat y, vfloat x); CPPSPMD_FORCE_INLINE vfloat atan_est(vfloat x) { return atan2_est(x, vfloat(1.0f)); } -// Don't call this for angles close to 90/270! +// Don't call this for angles close to 90/270! inline vfloat tan_est(vfloat x); // https://burtleburtle.net/bob/rand/smallprng.html @@ -86,4 +86,3 @@ void print_vbool(vbool v); void print_vint_hex(vint v); void print_active_lanes(const char *pPrefix); void print_vfloat(vfloat v); - diff --git a/encoder/cppspmd_sse.h b/encoder/cppspmd_sse.h index 79dfa156..339e3c4a 100644 --- a/encoder/cppspmd_sse.h +++ b/encoder/cppspmd_sse.h @@ -131,8 +131,8 @@ CPPSPMD_DECL(const uint32_t, g_x_128[4]) = { UINT32_MAX, 0, 0, 0 }; CPPSPMD_DECL(const float, g_onef_128[4]) = { 1.0f, 1.0f, 1.0f, 1.0f }; CPPSPMD_DECL(const uint32_t, g_oneu_128[4]) = { 1, 1, 1, 1 }; -CPPSPMD_DECL(const uint32_t, g_lane_masks_128[4][4]) = -{ +CPPSPMD_DECL(const uint32_t, g_lane_masks_128[4][4]) = +{ { UINT32_MAX, 0, 0, 0 }, { 0, UINT32_MAX, 0, 0 }, { 0, 0, UINT32_MAX, 0 }, @@ -237,7 +237,7 @@ inline __m128i shuffle_epi8(const __m128i& a, const __m128i& b) // Just emulate _mm_shuffle_epi8. This is very slow, but what else can we do? CPPSPMD_ALIGN(16) uint8_t av[16]; _mm_store_si128((__m128i*)av, a); - + CPPSPMD_ALIGN(16) uint8_t bvi[16]; _mm_store_ps((float*)bvi, _mm_and_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(_mm_set1_epi32(0x0F0F0F0F)))); @@ -247,7 +247,7 @@ inline __m128i shuffle_epi8(const __m128i& a, const __m128i& b) result[1] = av[bvi[1]]; result[2] = av[bvi[2]]; result[3] = av[bvi[3]]; - + result[4] = av[bvi[4]]; result[5] = av[bvi[5]]; result[6] = av[bvi[6]]; @@ -266,9 +266,9 @@ inline __m128i shuffle_epi8(const __m128i& a, const __m128i& b) return _mm_andnot_si128(_mm_cmplt_epi8(b, _mm_setzero_si128()), _mm_load_si128((__m128i*)result)); } #else -CPPSPMD_FORCE_INLINE __m128i shuffle_epi8(const __m128i& a, const __m128i& b) -{ - return _mm_shuffle_epi8(a, b); +CPPSPMD_FORCE_INLINE __m128i shuffle_epi8(const __m128i& a, const __m128i& b) +{ + return _mm_shuffle_epi8(a, b); } #endif @@ -387,7 +387,7 @@ struct spmd_kernel typedef int int_t; typedef vint vint_t; typedef lint lint_t; - + // Exec mask struct exec_mask { @@ -399,7 +399,7 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE explicit exec_mask(const __m128i& mask) : m_mask(mask) { } CPPSPMD_FORCE_INLINE void enable_lane(uint32_t lane) { m_mask = _mm_load_si128((const __m128i *)&g_lane_masks_128[lane][0]); } - + static CPPSPMD_FORCE_INLINE exec_mask all_on() { return exec_mask{ _mm_load_si128((const __m128i*)g_allones_128) }; } static CPPSPMD_FORCE_INLINE exec_mask all_off() { return exec_mask{ _mm_setzero_si128() }; } @@ -422,20 +422,20 @@ struct spmd_kernel friend CPPSPMD_FORCE_INLINE exec_mask operator^ (const exec_mask& a, const exec_mask& b); friend CPPSPMD_FORCE_INLINE exec_mask operator& (const exec_mask& a, const exec_mask& b); friend CPPSPMD_FORCE_INLINE exec_mask operator| (const exec_mask& a, const exec_mask& b); - + exec_mask m_exec; exec_mask m_kernel_exec; exec_mask m_continue_mask; #ifdef _DEBUG bool m_in_loop; #endif - + CPPSPMD_FORCE_INLINE uint32_t get_movemask() const { return m_exec.get_movemask(); } - + void init(const exec_mask& kernel_exec); - + // Varying bool - + struct vbool { __m128i m_value; @@ -448,25 +448,25 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE explicit operator vfloat() const; CPPSPMD_FORCE_INLINE explicit operator vint() const; - + private: //vbool& operator=(const vbool&); }; friend vbool operator!(const vbool& v); - + CPPSPMD_FORCE_INLINE vbool& store(vbool& dst, const vbool& src) { dst.m_value = blendv_mask_epi32(dst.m_value, src.m_value, m_exec.m_mask); return dst; } - + CPPSPMD_FORCE_INLINE vbool& store_all(vbool& dst, const vbool& src) { dst.m_value = src.m_value; return dst; } - + // Varying float struct vfloat { @@ -495,7 +495,7 @@ struct spmd_kernel dst.m_value = blendv_mask_ps(dst.m_value, src.m_value, _mm_castsi128_ps(m_exec.m_mask)); return dst; } - + CPPSPMD_FORCE_INLINE vfloat& store_all(vfloat& dst, const vfloat& src) { dst.m_value = src.m_value; @@ -536,7 +536,7 @@ struct spmd_kernel _mm_storeu_ps(dst.m_pValue, blendv_mask_ps(_mm_loadu_ps(dst.m_pValue), src.m_value, _mm_castsi128_ps(m_exec.m_mask))); return dst; } - + CPPSPMD_FORCE_INLINE const float_lref& store_all(const float_lref& dst, const vfloat& src) { _mm_storeu_ps(dst.m_pValue, src.m_value); @@ -553,13 +553,13 @@ struct spmd_kernel { return vfloat{ _mm_and_ps(_mm_loadu_ps(src.m_pValue), _mm_castsi128_ps(m_exec.m_mask)) }; } - + // Varying ref to floats struct float_vref { __m128i m_vindex; float* m_pValue; - + private: //float_vref& operator=(const float_vref&); }; @@ -569,7 +569,7 @@ struct spmd_kernel { __m128i m_vindex; vfloat* m_pValue; - + private: //vfloat_vref& operator=(const vfloat_vref&); }; @@ -579,14 +579,14 @@ struct spmd_kernel { __m128i m_vindex; vint* m_pValue; - + private: //vint_vref& operator=(const vint_vref&); }; CPPSPMD_FORCE_INLINE const float_vref& store(const float_vref& dst, const vfloat& src); CPPSPMD_FORCE_INLINE const float_vref& store(const float_vref&& dst, const vfloat& src); - + CPPSPMD_FORCE_INLINE const float_vref& store_all(const float_vref& dst, const vfloat& src); CPPSPMD_FORCE_INLINE const float_vref& store_all(const float_vref&& dst, const vfloat& src); @@ -626,7 +626,7 @@ struct spmd_kernel private: //int_lref& operator=(const int_lref&); }; - + CPPSPMD_FORCE_INLINE const int_lref& store(const int_lref& dst, const vint& src) { int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask)); @@ -689,7 +689,7 @@ struct spmd_kernel dst.m_pValue[i] = static_cast(stored[i]); return dst; } - + CPPSPMD_FORCE_INLINE vint load(const int16_lref& src) { CPPSPMD_ALIGN(16) int values[4]; @@ -713,7 +713,7 @@ struct spmd_kernel return vint{ t }; } - + // Linear ref to constant ints struct cint_lref { @@ -734,7 +734,7 @@ struct spmd_kernel { return vint{ _mm_loadu_si128((const __m128i *)src.m_pValue) }; } - + // Varying ref to ints struct int_vref { @@ -774,7 +774,7 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE explicit vint(const vfloat& other) : m_value(_mm_cvttps_epi32(other.m_value)) { } - CPPSPMD_FORCE_INLINE explicit operator vbool() const + CPPSPMD_FORCE_INLINE explicit operator vbool() const { return vbool{ _mm_xor_si128( _mm_load_si128((const __m128i*)g_allones_128), _mm_cmpeq_epi32(m_value, _mm_setzero_si128())) }; } @@ -837,7 +837,7 @@ struct spmd_kernel { _mm_store_si128((__m128i*)pDst, src.m_value); } - + CPPSPMD_FORCE_INLINE vint loadu_linear(const int *pSrc) { __m128i v = _mm_loadu_si128((const __m128i*)pSrc); @@ -882,7 +882,7 @@ struct spmd_kernel { _mm_store_ps((float*)pDst, src.m_value); } - + CPPSPMD_FORCE_INLINE vfloat loadu_linear(const float *pSrc) { __m128 v = _mm_loadu_ps((const float*)pSrc); @@ -901,7 +901,7 @@ struct spmd_kernel { return vfloat{ _mm_load_ps((float*)pSrc) }; } - + CPPSPMD_FORCE_INLINE vint& store(vint& dst, const vint& src) { dst.m_value = blendv_mask_epi32(dst.m_value, src.m_value, m_exec.m_mask); @@ -924,13 +924,13 @@ struct spmd_kernel } return dst; } - + CPPSPMD_FORCE_INLINE vint& store_all(vint& dst, const vint& src) { dst.m_value = src.m_value; return dst; } - + CPPSPMD_FORCE_INLINE const int_vref& store_all(const int_vref& dst, const vint& src) { CPPSPMD_ALIGN(16) int vindex[4]; @@ -961,7 +961,7 @@ struct spmd_kernel return vint{ _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(m_exec.m_mask), _mm_load_ps((const float*)values))) }; } - + CPPSPMD_FORCE_INLINE vint load_all(const int_vref& src) { CPPSPMD_ALIGN(16) int values[4]; @@ -974,7 +974,7 @@ struct spmd_kernel return vint{ _mm_castps_si128( _mm_load_ps((const float*)values)) }; } - + CPPSPMD_FORCE_INLINE vint load(const cint_vref& src) { CPPSPMD_ALIGN(16) int values[4]; @@ -991,7 +991,7 @@ struct spmd_kernel return vint{ _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(m_exec.m_mask), _mm_load_ps((const float*)values))) }; } - + CPPSPMD_FORCE_INLINE vint load_all(const cint_vref& src) { CPPSPMD_ALIGN(16) int values[4]; @@ -1034,7 +1034,7 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE void store_strided(int *pDst, uint32_t stride, const vint &v) { int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask)); - + if (mask & 1) pDst[0] = extract_x(v.m_value); if (mask & 2) pDst[stride] = extract_y(v.m_value); if (mask & 4) pDst[stride*2] = extract_z(v.m_value); @@ -1070,7 +1070,7 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE vint load_strided(const int *pSrc, uint32_t stride) { int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask)); - + #if CPPSPMD_SSE2 CPPSPMD_ALIGN(16) int vals[4] = { 0, 0, 0, 0 }; if (mask & 1) vals[0] = pSrc[0]; @@ -1119,7 +1119,7 @@ struct spmd_kernel vals[2] = pSrc[stride * 2]; vals[3] = pSrc[stride * 3]; return vint{ _mm_load_si128((__m128i*)vals) }; -#else +#else const float* pSrcF = (const float*)pSrc; __m128 v = _mm_load_ss(pSrcF); v = _mm_insert_ps(v, _mm_load_ss(pSrcF + stride), 0x10); @@ -1151,7 +1151,7 @@ struct spmd_kernel { // TODO: There's surely a better way int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask)); - + if (mask & 1) ((int *)(&dst.m_pValue[extract_x(dst.m_vindex)]))[0] = extract_x(_mm_castps_si128(src.m_value)); if (mask & 2) ((int *)(&dst.m_pValue[extract_y(dst.m_vindex)]))[1] = extract_y(_mm_castps_si128(src.m_value)); if (mask & 4) ((int *)(&dst.m_pValue[extract_z(dst.m_vindex)]))[2] = extract_z(_mm_castps_si128(src.m_value)); @@ -1179,7 +1179,7 @@ struct spmd_kernel { // TODO: There's surely a better way int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask)); - + if (mask & 1) ((int *)(&dst.m_pValue[extract_x(dst.m_vindex)]))[0] = extract_x(src.m_value); if (mask & 2) ((int *)(&dst.m_pValue[extract_y(dst.m_vindex)]))[1] = extract_y(src.m_value); if (mask & 4) ((int *)(&dst.m_pValue[extract_z(dst.m_vindex)]))[2] = extract_z(src.m_value); @@ -1215,7 +1215,7 @@ struct spmd_kernel return vint{ k }; } - + // Linear integer struct lint { @@ -1235,7 +1235,7 @@ struct spmd_kernel return vint{ m_value }; } - CPPSPMD_FORCE_INLINE int get_first_value() const + CPPSPMD_FORCE_INLINE int get_first_value() const { return _mm_cvtsi128_si32(m_value); } @@ -1269,9 +1269,9 @@ struct spmd_kernel dst.m_value = src.m_value; return dst; } - + const lint program_index = lint{ _mm_set_epi32( 3, 2, 1, 0 ) }; - + // SPMD condition helpers template @@ -1298,7 +1298,7 @@ struct spmd_kernel template CPPSPMD_FORCE_INLINE void spmd_foreach(int begin, int end, const ForeachBody& foreachBody); - + #ifdef _DEBUG CPPSPMD_FORCE_INLINE void check_masks(); #else @@ -1307,9 +1307,9 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE void spmd_break(); CPPSPMD_FORCE_INLINE void spmd_continue(); - + CPPSPMD_FORCE_INLINE void spmd_return(); - + template CPPSPMD_FORCE_INLINE void spmd_unmasked(const UnmaskedBody& unmaskedBody); @@ -1321,8 +1321,8 @@ struct spmd_kernel CPPSPMD_FORCE_INLINE void swap(vfloat &a, vfloat &b) { vfloat temp = a; store(a, b); store(b, temp); } CPPSPMD_FORCE_INLINE void swap(vbool &a, vbool &b) { vbool temp = a; store(a, b); store(b, temp); } - CPPSPMD_FORCE_INLINE float reduce_add(vfloat v) - { + CPPSPMD_FORCE_INLINE float reduce_add(vfloat v) + { __m128 k3210 = _mm_castsi128_ps(blendv_mask_epi32(_mm_setzero_si128(), _mm_castps_si128(v.m_value), m_exec.m_mask)); __m128 temp = _mm_add_ps(_mm_shuffle_ps(k3210, k3210, _MM_SHUFFLE(0, 1, 2, 3)), k3210); return _mm_cvtss_f32(_mm_add_ss(_mm_movehl_ps(temp, temp), temp)); @@ -1353,14 +1353,14 @@ using float_vref = spmd_kernel::float_vref; using vfloat_vref = spmd_kernel::vfloat_vref; using vint_vref = spmd_kernel::vint_vref; -CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vfloat() const -{ - return vfloat { _mm_and_ps( _mm_castsi128_ps(m_value), *(const __m128 *)g_onef_128 ) }; +CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vfloat() const +{ + return vfloat { _mm_and_ps( _mm_castsi128_ps(m_value), *(const __m128 *)g_onef_128 ) }; } - + // Returns UINT32_MAX's for true, 0 for false. (Should it return 1's?) -CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vint() const -{ +CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vint() const +{ return vint { m_value }; } @@ -1441,9 +1441,9 @@ CPPSPMD_FORCE_INLINE vfloat round_truncate(const vfloat& a) { __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU) ); __m128i has_fractional = _mm_cmplt_epi32(abs_a, _mm_castps_si128(_mm_set1_ps(8388608.0f))); - + __m128i ai = _mm_cvttps_epi32(a.m_value); - + __m128 af = _mm_cvtepi32_ps(ai); return vfloat{ blendv_mask_ps(a.m_value, af, _mm_castsi128_ps(has_fractional)) }; } @@ -1466,11 +1466,11 @@ CPPSPMD_FORCE_INLINE vfloat ceil(const vfloat& a) { __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU)); __m128i has_fractional = _mm_cmplt_epi32(abs_a, _mm_castps_si128(_mm_set1_ps(8388608.0f))); - + __m128i ai = _mm_cvtps_epi32(a.m_value); __m128 af = _mm_cvtepi32_ps(ai); __m128 changed = _mm_cvtepi32_ps(_mm_castps_si128(_mm_cmplt_ps(af, a.m_value))); - + af = _mm_sub_ps(af, changed); return vfloat{ blendv_mask_ps(a.m_value, af, _mm_castsi128_ps(has_fractional)) }; @@ -1503,12 +1503,12 @@ CPPSPMD_FORCE_INLINE vfloat round_nearest(const vfloat& a) __m128i sign_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x80000000U)); __m128 force_int = _mm_castsi128_ps(_mm_or_si128(no_fract_fp_bits, sign_a)); - + // Can't use individual _mm_add_ps/_mm_sub_ps - this will be optimized out with /fp:fast by clang and probably other compilers. //__m128 temp1 = _mm_add_ps(a.m_value, force_int); //__m128 temp2 = _mm_sub_ps(temp1, force_int); __m128 temp2 = add_sub(a.m_value, force_int); - + __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU)); __m128i has_fractional = _mm_cmplt_epi32(abs_a, no_fract_fp_bits); return vfloat{ blendv_mask_ps(a.m_value, temp2, _mm_castsi128_ps(has_fractional)) }; @@ -1824,7 +1824,7 @@ CPPSPMD_FORCE_INLINE vint vuint_shift_right(const vint& a, const vint& b) #else //vint inv_shift = 32 - b; //vfloat f = cast_vint_to_vfloat(vint(_mm_slli_epi32(inv_shift.m_value, 23)) + cast_vfloat_to_vint(vfloat(1.0f))); - + // Take float rep of 1.0f (0x3f800000), subtract (32<<23), subtract (shift<<23), cast to float. vfloat f = cast_vint_to_vfloat(vint(_mm_sub_epi32(_mm_set1_epi32(0x4f800000), _mm_slli_epi32(b.m_value, 23)))); @@ -1843,7 +1843,7 @@ CPPSPMD_FORCE_INLINE vint vuint_shift_right_not_zero(const vint& a, const vint& { //vint inv_shift = 32 - b; //vfloat f = cast_vint_to_vfloat(vint(_mm_slli_epi32(inv_shift.m_value, 23)) + cast_vfloat_to_vint(vfloat(1.0f))); - + // Take float rep of 1.0f (0x3f800000), subtract (32<<23), subtract (shift<<23), cast to float. vfloat f = cast_vint_to_vfloat(vint(_mm_sub_epi32(_mm_set1_epi32(0x4f800000), _mm_slli_epi32(b.m_value, 23)))); @@ -1887,7 +1887,7 @@ CPPSPMD_FORCE_INLINE vint operator>> (const vint& a, const vint& b) // Shift left/right by a uniform immediate constant #define VINT_SHIFT_LEFT(a, b) vint(_mm_slli_epi32( (a).m_value, (b) ) ) -#define VINT_SHIFT_RIGHT(a, b) vint( _mm_srai_epi32( (a).m_value, (b) ) ) +#define VINT_SHIFT_RIGHT(a, b) vint( _mm_srai_epi32( (a).m_value, (b) ) ) #define VUINT_SHIFT_RIGHT(a, b) vint( _mm_srli_epi32( (a).m_value, (b) ) ) #define VINT_ROT(x, k) (VINT_SHIFT_LEFT((x), (k)) | VUINT_SHIFT_RIGHT((x), 32 - (k))) @@ -2102,4 +2102,3 @@ CPPSPMD_FORCE_INLINE const float_vref& spmd_kernel::store_all(const float_vref&& #include "cppspmd_math.h" } // namespace cppspmd_sse41 - diff --git a/encoder/jpgd.cpp b/encoder/jpgd.cpp index f375ba20..57c7ec7b 100644 --- a/encoder/jpgd.cpp +++ b/encoder/jpgd.cpp @@ -3,7 +3,7 @@ // Supports box and linear chroma upsampling. // // Released under two licenses. You are free to choose which license you want: -// License 1: +// License 1: // Public Domain // // License 2: @@ -138,7 +138,7 @@ namespace jpgd { { static void idct(int* pTemp, const jpgd_block_t* pSrc) { - (void)pTemp; + (void)pTemp; (void)pSrc; } }; @@ -253,10 +253,10 @@ namespace jpgd { 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8, }; - static const uint8 s_idct_col_table[] = - { - 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 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 + static const uint8 s_idct_col_table[] = + { + 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 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 }; // Scalar "fast pathing" IDCT. diff --git a/encoder/jpgd.h b/encoder/jpgd.h index 86a7814c..92e53335 100644 --- a/encoder/jpgd.h +++ b/encoder/jpgd.h @@ -10,7 +10,7 @@ #include #ifdef _MSC_VER -#define JPGD_NORETURN __declspec(noreturn) +#define JPGD_NORETURN __declspec(noreturn) #elif defined(__GNUC__) #define JPGD_NORETURN __attribute__ ((noreturn)) #else @@ -140,7 +140,7 @@ namespace jpgd int begin_decoding(); // Returns the next scan line. - // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1). + // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1). // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4). // Returns JPGD_SUCCESS if a scan line has been returned. // Returns JPGD_DONE if all scan lines have been returned. diff --git a/encoder/pvpngreader.cpp b/encoder/pvpngreader.cpp index 6b32f66c..1f708983 100644 --- a/encoder/pvpngreader.cpp +++ b/encoder/pvpngreader.cpp @@ -1,12 +1,12 @@ // pngreader.cpp - Public Domain - see unlicense at bottom of file. // -// Notes: -// This is ancient code from ~1995 ported to C++. It was originally written for a -// DOS app with very limited memory. It's not as fast as it should be, but it works. -// The low-level PNG reader class was written assuming the PNG file could not fit +// Notes: +// This is ancient code from ~1995 ported to C++. It was originally written for a +// DOS app with very limited memory. It's not as fast as it should be, but it works. +// The low-level PNG reader class was written assuming the PNG file could not fit // entirely into memory, which dictated how it was written/structured. // It has been modified to use either zlib or miniz. -// It supports all PNG color types/bit depths/interlacing, however 16-bit/component +// It supports all PNG color types/bit depths/interlacing, however 16-bit/component // images are converted to 8-bit. // TRNS chunks are converted to alpha as needed. // GAMA chunk is read, but not applied. @@ -109,20 +109,20 @@ class png_memory_file : public png_file public: std::vector m_buf; uint64_t m_ofs; - - png_memory_file() : + + png_memory_file() : png_file(), m_ofs(0) - { + { } - + virtual ~png_memory_file() - { + { } std::vector& get_buf() { return m_buf; } const std::vector& get_buf() const { return m_buf; } - + void init() { m_ofs = 0; @@ -269,8 +269,8 @@ class png_cfile : public png_file { public: FILE* m_pFile; - - png_cfile() : + + png_cfile() : png_file(), m_pFile(nullptr) { @@ -284,9 +284,9 @@ class png_cfile : public png_file bool init(const char *pFilename, const char *pMode) { close(); - + m_pFile = nullptr; - + #ifdef _MSC_VER fopen_s(&m_pFile, pFilename, pMode); #else @@ -333,17 +333,17 @@ class png_cfile : public png_file int64_t cur_ofs = ftell64(m_pFile); if (cur_ofs < 0) return 0; - + if (fseek64(m_pFile, 0, SEEK_END) != 0) return 0; - + const int64_t cur_size = ftell64(m_pFile); if (cur_size < 0) return 0; if (fseek64(m_pFile, cur_ofs, SEEK_SET) != 0) return 0; - + return cur_size; } @@ -379,13 +379,13 @@ class png_decoder png_decoder(); ~png_decoder(); - // Scans the PNG file, but doesn't decode the IDAT data. + // Scans the PNG file, but doesn't decode the IDAT data. // Returns 0 on success, or an error code. // If the returned status is non-zero, or m_img_supported_flag==FALSE the image either the image is corrupted/not PNG or is unsupported in some way. int png_scan(png_file *pFile); // Decodes a single scanline of PNG image data. - // Returns a pointer to the scanline's pixel data and its size in bytes. + // Returns a pointer to the scanline's pixel data and its size in bytes. // This data is only minimally processed from the internal PNG pixel data. // The caller must use the ihdr, trns_flag and values, and the palette to actually decode the pixel data. // @@ -397,21 +397,21 @@ class png_decoder // // Returns 0 on success, a non-zero error code, or PNG_ALLDONE. int png_decode(void** ppImg_ptr, uint32_t* pImg_len); - + // Starts decoding. Returns 0 on success, otherwise an error code. int png_decode_start(); - + // Deinitializes the decoder, freeing all allocations. void png_decode_end(); png_file* m_pFile; - + // Image's 24bpp palette - 3 bytes per entry uint8_t m_plte_flag; uint8_t m_img_pal[768]; - + int m_img_supported_flag; - + ihdr_struct m_ihdr; uint8_t m_chunk_flag; @@ -442,7 +442,7 @@ class png_decoder uint8_t m_gama_flag; uint32_t m_gama_value; - + uint8_t m_trns_flag; uint32_t m_trns_value[256]; @@ -455,7 +455,7 @@ class png_decoder uint32_t m_inflate_dst_buf_ofs; int m_inflate_eof_flag; - + uint8_t m_gamma_table[256]; int m_pass_x_size; @@ -467,16 +467,16 @@ class png_decoder int m_adam7_pass_size_y[7]; std::vector m_adam7_image_buf; - + int m_adam7_decoded_flag; - + bool m_scanned_flag; - + int m_terminate_status; - + #define TEMP_BUF_SIZE (384) uint8_t m_temp_buf[TEMP_BUF_SIZE * 4]; - + void clear(); void uninitialize(); int terminate(int status); @@ -516,7 +516,7 @@ class png_decoder void png_decoder::uninitialize() { m_pFile = nullptr; - + for (int i = 0; i < PNG_MAX_ALLOC_BLOCKS; i++) { free(m_pMalloc_blocks[i]); @@ -600,7 +600,7 @@ int png_decoder::fetch_next_chunk_data(uint8_t* buf, int bytes) int status = block_read(buf, bytes); if (status != 0) return status; - + #if PVPNG_IDAT_CRC_CHECKING bool check_crc32 = true; #else @@ -680,7 +680,7 @@ int png_decoder::fetch_next_chunk_init() if (status != 0) return status; } - + int64_t n = block_read_dword(); if (n < 0) return (int)n; @@ -776,7 +776,7 @@ static void PixelDePack2(void* src, void* dst, int numbytes) while (numbytes) { uint8_t v = *src8++; - + for (uint32_t i = 0; i < 8; i++) dst8[7 - i] = (v >> i) & 1; @@ -933,7 +933,7 @@ static int unpack_true_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pw uint8_t r = src[i * 3 + 0]; uint8_t g = src[i * 3 + 1]; uint8_t b = src[i * 3 + 2]; - + dst[i * 4 + 0] = r; dst[i * 4 + 1] = g; dst[i * 4 + 2] = b; @@ -982,7 +982,7 @@ static int unpack_true_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* p dst[1] = src[2]; dst[2] = src[4]; dst[3] = 255; - + dst += 4; src += 6; } @@ -1180,15 +1180,15 @@ int png_decoder::decompress_line(uint32_t* bytes_decoded) m_inflator.next_in = inflate_src_buf + m_inflate_src_buf_ofs; m_inflator.avail_in = src_bytes_left; - + m_inflator.next_out = m_pCur_line_buf + m_inflate_dst_buf_ofs; m_inflator.avail_out = dst_bytes_left; - + status = buminiz::mz_inflate2(&m_inflator, buminiz::MZ_NO_FLUSH, PVPNG_ADLER32_CHECKING); const uint32_t src_bytes_consumed = src_bytes_left - m_inflator.avail_in; const uint32_t dst_bytes_written = dst_bytes_left - m_inflator.avail_out; - + m_inflate_src_buf_ofs += src_bytes_consumed; m_inflate_dst_buf_ofs += dst_bytes_written; @@ -1255,10 +1255,10 @@ int png_decoder::png_decode(void** ppImg_ptr, uint32_t* pImg_len) { if (m_pass_y_left == 0) return PNG_ALLDONE; - + *ppImg_ptr = &m_adam7_image_buf[(m_ihdr.m_height - m_pass_y_left) * m_dst_bytes_per_line]; *pImg_len = m_dst_bytes_per_line; - + m_pass_y_left--; return 0; @@ -1282,7 +1282,7 @@ int png_decoder::png_decode(void** ppImg_ptr, uint32_t* pImg_len) status = find_iend_chunk(); if (status < 0) return status; - + return PNG_ALLDONE; } @@ -1398,7 +1398,7 @@ int png_decoder::png_decode(void** ppImg_ptr, uint32_t* pImg_len) if ((*m_pProcess_func)(m_pCur_line_buf + 1, m_pPro_line_buf, m_pass_x_size, this)) decoded_line = m_pPro_line_buf; } - + if (m_ihdr.m_ilace_type == 0) { *ppImg_ptr = decoded_line; @@ -1499,17 +1499,17 @@ void png_decoder::png_decode_end() int png_decoder::png_decode_start() { int status; - + if (m_img_supported_flag != TRUE) return terminate(m_img_supported_flag); - + switch (m_ihdr.m_color_type) { case PNG_COLOR_TYPE_GREYSCALE: { if (m_ihdr.m_bit_depth == 16) { - // This is a special case. We can't pass back 8-bit samples and let the caller decide on transparency because the PNG is 16-bits. + // This is a special case. We can't pass back 8-bit samples and let the caller decide on transparency because the PNG is 16-bits. // So we expand to 8-bit Gray-Alpha and handle transparency during decoding. // We don't do this with all grayscale cases because that would require more code to deal with 1/2/4bpp expansion. m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8; @@ -1534,7 +1534,7 @@ int png_decoder::png_decode_start() m_pProcess_func = unpack_grey_2; else if (m_ihdr.m_bit_depth == 4) m_pProcess_func = unpack_grey_4; - else + else m_pProcess_func = unpack_grey_8; } @@ -1644,9 +1644,9 @@ int png_decoder::png_decode_start() m_adam7_pass_size_y[4] = adam7_pass_size(m_ihdr.m_height, 2, 4); m_adam7_pass_size_y[5] = adam7_pass_size(m_ihdr.m_height, 0, 2); m_adam7_pass_size_y[6] = adam7_pass_size(m_ihdr.m_height, 1, 2); - + m_adam7_image_buf.resize(m_dst_bytes_per_line * m_ihdr.m_height); - + m_adam7_pass_num = -1; m_pass_y_left = 0; @@ -1688,7 +1688,7 @@ int png_decoder::png_decode_start() m_pass_x_size = m_ihdr.m_width; m_pass_y_left = m_ihdr.m_height; } - + return 0; } @@ -1781,13 +1781,13 @@ int png_decoder::read_ihdr_chunk() if ((m_ihdr.m_height == 0) || (m_ihdr.m_height > MAX_SUPPORTED_RES)) return terminate(PNG_BAD_HEIGHT); - int v = fetch_next_chunk_byte(); - if (v < 0) + int v = fetch_next_chunk_byte(); + if (v < 0) return v; m_ihdr.m_bit_depth = (uint8_t)v; - v = fetch_next_chunk_byte(); - if (v < 0) + v = fetch_next_chunk_byte(); + if (v < 0) return v; m_ihdr.m_color_type = (uint8_t)v; @@ -1814,7 +1814,7 @@ int png_decoder::read_ihdr_chunk() if (m_ihdr.m_ilace_type > 1) m_img_supported_flag = PNG_UNS_ILACE; - + switch (m_ihdr.m_color_type) { case PNG_COLOR_TYPE_GREYSCALE: @@ -1905,7 +1905,7 @@ int png_decoder::read_bkgd_chunk() if (v < 0) return v; m_bkgd_value[1] = v; - + v = fetch_next_chunk_word(); if (v < 0) return v; @@ -1924,7 +1924,7 @@ int png_decoder::read_gama_chunk() return (int)v; m_gama_value = (uint32_t)v; - + return 0; } @@ -1964,12 +1964,12 @@ int png_decoder::read_trns_chunk() if (v < 0) return v; m_trns_value[0] = v; - + v = fetch_next_chunk_word(); if (v < 0) return v; m_trns_value[1] = v; - + v = fetch_next_chunk_word(); if (v < 0) return v; @@ -2015,7 +2015,7 @@ int png_decoder::read_plte_chunk() if (v < 0) return v; *p++ = (uint8_t)v; - + v = fetch_next_chunk_byte(); if (v < 0) return v; @@ -2026,7 +2026,7 @@ int png_decoder::read_plte_chunk() return v; *p++ = (uint8_t)v; } - + return 0; } @@ -2144,7 +2144,7 @@ void png_decoder::clear() m_inflate_dst_buf_ofs = 0; m_inflate_eof_flag = FALSE; - + clear_obj(m_trns_value); m_pass_x_size = 0; @@ -2154,18 +2154,18 @@ void png_decoder::clear() m_adam7_pass_y = 0; clear_obj(m_adam7_pass_size_x); clear_obj(m_adam7_pass_size_y); - + m_adam7_decoded_flag = FALSE; - + m_scanned_flag = false; - + m_terminate_status = 0; } int png_decoder::png_scan(png_file *pFile) { m_pFile = pFile; - + m_img_supported_flag = TRUE; m_terminate_status = 0; @@ -2176,11 +2176,11 @@ int png_decoder::png_scan(png_file *pFile) res = read_ihdr_chunk(); if (res != 0) return res; - + res = find_idat_chunk(); if (res != 0) return res; - + if (m_gama_flag) calc_gamma_table(); @@ -2200,14 +2200,14 @@ int png_decoder::png_scan(png_file *pFile) } static inline uint8_t get_709_luma(uint32_t r, uint32_t g, uint32_t b) -{ +{ return (uint8_t)((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U); } bool get_png_info(const void* pImage_buf, size_t buf_size, png_info &info) { memset(&info, 0, sizeof(info)); - + if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE)) return false; @@ -2256,7 +2256,7 @@ void* load_png(const void* pImage_buf, size_t buf_size, uint32_t desired_chans, width = 0; height = 0; num_chans = 0; - + if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE)) { assert(0); @@ -2273,7 +2273,7 @@ void* load_png(const void* pImage_buf, size_t buf_size, uint32_t desired_chans, mf.init(pImage_buf, buf_size); png_decoder dec; - + int status = dec.png_scan(&mf); if ((status != 0) || (dec.m_img_supported_flag != TRUE)) return nullptr; @@ -2320,11 +2320,11 @@ void* load_png(const void* pImage_buf, size_t buf_size, uint32_t desired_chans, uint64_t total_size = (uint64_t)pitch * height; if (total_size > 0x7FFFFFFFULL) return nullptr; - + uint8_t* pBuf = (uint8_t*)malloc((size_t)total_size); if (!pBuf) return nullptr; - + if (dec.png_decode_start() != 0) { free(pBuf); diff --git a/encoder/pvpngreader.h b/encoder/pvpngreader.h index 4f3fe46b..b1850f1b 100644 --- a/encoder/pvpngreader.h +++ b/encoder/pvpngreader.h @@ -19,7 +19,7 @@ namespace pv_png { uint32_t m_width; uint32_t m_height; - + uint32_t m_num_chans; // The number of channels, factoring in transparency. Ranges from [1-4]. uint32_t m_bit_depth; // PNG ihdr bit depth: 1, 2, 4, 8 or 16 diff --git a/encoder_lib/encoder_lib.vcxproj b/encoder_lib/encoder_lib.vcxproj index 7ac43112..3ffa09af 100644 --- a/encoder_lib/encoder_lib.vcxproj +++ b/encoder_lib/encoder_lib.vcxproj @@ -313,4 +313,4 @@ - \ No newline at end of file + diff --git a/encoder_lib/encoder_lib.vcxproj.filters b/encoder_lib/encoder_lib.vcxproj.filters index a69edd36..aaee9d98 100644 --- a/encoder_lib/encoder_lib.vcxproj.filters +++ b/encoder_lib/encoder_lib.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -257,4 +257,4 @@ Source Files\encoder - \ No newline at end of file + diff --git a/example/example.cpp b/example/example.cpp index 9cf6de51..cde7b268 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -1,7 +1,7 @@ // File: example.cpp // This minimal LDR/HDR encoding/transcoder example relies on encoder_lib. It shows how to use the encoder in a few different ways, and the transcoder. -// -// It should be compiled with the preprocessor macros BASISU_SUPPORT_SSE (typically 1) and BASISU_SUPPORT_OPENCL (typically 1). +// +// It should be compiled with the preprocessor macros BASISU_SUPPORT_SSE (typically 1) and BASISU_SUPPORT_OPENCL (typically 1). // They should be set to the same preprocesor options as the encoder. // If OpenCL is enabled, the "..\OpenCL" directory should be in your compiler's include path. Additionally, link against "..\OpenCL\lib\opencl64.lib". #include "../encoder/basisu_comp.h" @@ -17,7 +17,7 @@ const bool USE_OPENCL = false; using namespace basisu; // Quick function to create a visualization of the Mandelbrot set as an float HDR image. -static void create_mandelbrot(imagef& img) +static void create_mandelbrot(imagef& img) { const int width = 256; const int height = 256; @@ -25,30 +25,30 @@ static void create_mandelbrot(imagef& img) // Create a more interesting color palette uint8_t palette[256][3]; - for (int i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) { - if (i < 64) + if (i < 64) { // Blue to cyan transition palette[i][0] = static_cast(0); // Red component palette[i][1] = static_cast(i * 4); // Green component palette[i][2] = static_cast(255); // Blue component } - else if (i < 128) + else if (i < 128) { // Cyan to green transition palette[i][0] = static_cast(0); // Red component palette[i][1] = static_cast(255); // Green component palette[i][2] = static_cast(255 - (i - 64) * 4); // Blue component } - else if (i < 192) + else if (i < 192) { // Green to yellow transition palette[i][0] = static_cast((i - 128) * 4); // Red component palette[i][1] = static_cast(255); // Green component palette[i][2] = static_cast(0); // Blue component } - else + else { // Yellow to red transition palette[i][0] = static_cast(255); // Red component @@ -58,9 +58,9 @@ static void create_mandelbrot(imagef& img) } // Iterate over each pixel in the image - for (int px = 0; px < width; px++) + for (int px = 0; px < width; px++) { - for (int py = 0; py < height; py++) + for (int py = 0; py < height; py++) { double x0 = (px - width / 2.0) * 4.0 / width; double y0 = (py - height / 2.0) * 4.0 / height; @@ -71,7 +71,7 @@ static void create_mandelbrot(imagef& img) double x_temp; int iter; - for (iter = 0; iter < max_iter; iter++) + for (iter = 0; iter < max_iter; iter++) { zx_squared = zx * zx; zy_squared = zy * zy; @@ -173,7 +173,7 @@ static bool encode_uastc_ldr() static bool encode_uastc_hdr() { const uint32_t W = 256, H = 256; - + imagef img(W, H); #if 1 @@ -196,7 +196,7 @@ static bool encode_uastc_hdr() params.m_write_output_basis_or_ktx2_files = true; params.m_out_filename = "test_uastc_hdr.ktx2"; params.m_perceptual = true; - + #if 1 // Create a job pool containing 7 total threads (the calling thread plus 6 additional threads). // A job pool must be created, even if threading is disabled. It's fine to pass in 0 for NUM_THREADS. @@ -219,13 +219,13 @@ static bool encode_uastc_hdr() basisu::basis_compressor::error_code ec = comp.process(); if (ec != basisu::basis_compressor::cECSuccess) return false; - + return true; } // This example function loads a .KTX2 file and then transcodes it to various compressed/uncompressed texture formats. -// It writes .DDS and .ASTC files. -// ARM's astcenc tool can be used to unpack the .ASTC file: +// It writes .DDS and .ASTC files. +// ARM's astcenc tool can be used to unpack the .ASTC file: // astcenc-avx2.exe -dh test_uastc_hdr_astc.astc out.exr static bool transcode_hdr() { @@ -252,10 +252,10 @@ static bool transcode_hdr() // This example only transcodes UASTC HDR textures. if (!transcoder.is_hdr()) return false; - + // Begin transcoding (this will be a no-op with UASTC HDR textures, but you still need to do it. For ETC1S it'll unpack the global codebooks.) transcoder.start_transcoding(); - + // Transcode to BC6H and write a BC6H .DDS file. { gpu_image tex(texture_format::cBC6HUnsigned, width, height); @@ -423,7 +423,7 @@ const uint32_t NUM_TEST_BLOCKS = (sizeof(g_test_blocks) / sizeof(g_test_blocks[0 static bool block_unpack_and_transcode_example(void) { printf("block_unpack_and_transcode_example:\n"); - + for (uint32_t test_block_iter = 0; test_block_iter < NUM_TEST_BLOCKS; test_block_iter++) { printf("-- Test block %u:\n", test_block_iter); @@ -431,7 +431,7 @@ static bool block_unpack_and_transcode_example(void) const uint8_t* pASTC_blk = &g_test_blocks[test_block_iter * 2 + 0][0]; const uint8_t* pBC6H_blk = &g_test_blocks[test_block_iter * 2 + 1][0]; - // Unpack the physical ASTC block to logical. + // Unpack the physical ASTC block to logical. // Note this is a full ASTC block unpack, and is not specific to UASTC. It does not verify that the block follows the UASTC HDR spec, only ASTC. astc_helpers::log_astc_block log_blk; bool status = astc_helpers::unpack_block(pASTC_blk, log_blk, 4, 4); @@ -470,7 +470,7 @@ static bool block_unpack_and_transcode_example(void) return false; } } // test_block_iter - + printf("Transcode test OK\n"); return true; @@ -492,7 +492,7 @@ static void fuzz_uastc_hdr_transcoder_test() for (uint32_t t = 0; t < NUM_TRIES; t++) { basist::astc_blk astc_blk; - + if (rg.frand(0.0f, 1.0f) < .3f) { // Fully random block @@ -568,7 +568,7 @@ int main(int arg_c, char* arg_v[]) { BASISU_NOTE_UNUSED(arg_c); BASISU_NOTE_UNUSED(arg_v); - + #if USE_ENCODER basisu_encoder_init(USE_OPENCL, false); @@ -576,7 +576,7 @@ int main(int arg_c, char* arg_v[]) return EXIT_FAILURE; fuzz_uastc_hdr_transcoder_test(); - + if (!encode_etc1s()) { fprintf(stderr, "encode_etc1s() failed!\n"); diff --git a/example/example.manifest b/example/example.manifest index b4baf6b9..324aa6d6 100644 --- a/example/example.manifest +++ b/example/example.manifest @@ -7,4 +7,3 @@ - diff --git a/example/example.vcxproj b/example/example.vcxproj index f5be5957..bd107722 100644 --- a/example/example.vcxproj +++ b/example/example.vcxproj @@ -243,4 +243,4 @@ - \ No newline at end of file + diff --git a/example/example.vcxproj.filters b/example/example.vcxproj.filters index 5058935a..367a91ed 100644 --- a/example/example.vcxproj.filters +++ b/example/example.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -22,4 +22,4 @@ - \ No newline at end of file + diff --git a/test_files/license.txt b/test_files/license.txt index a344042f..bf9e7b14 100644 --- a/test_files/license.txt +++ b/test_files/license.txt @@ -1,2 +1 @@ The test images in the "test_files" directory are not required to build or use the Basis Universal codec. They are not copyrighted or owned by Binomial LLC. - diff --git a/transcoder/basisu.h b/transcoder/basisu.h index 44fb9a30..e3e46804 100644 --- a/transcoder/basisu.h +++ b/transcoder/basisu.h @@ -20,7 +20,7 @@ #pragma warning (disable : 4201) #pragma warning (disable : 4127) // warning C4127: conditional expression is constant #pragma warning (disable : 4530) // C++ exception handler used, but unwind semantics are not enabled. - + #endif // _MSC_VER #include @@ -110,16 +110,16 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif #endif - + template inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); } #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif constexpr double cPiD = 3.14159265358979323846264338327950288; @@ -128,7 +128,7 @@ namespace basisu constexpr float BIG_FLOAT_VAL = 1e+30f; template inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; } - + inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; } inline float saturate(float value) { return clampf(value, 0, 1.0f); } inline uint8_t minimumub(uint8_t a, uint8_t b) { return (a < b) ? a : b; } @@ -144,7 +144,7 @@ namespace basisu inline double squared(double i) { return i * i; } template inline T square(T a) { return a * a; } template inline T sign(T a) { return (a < 0) ? (T)-1 : ((a == 0) ? (T)0 : (T)1); } - + inline bool equal_tol(float a, float b, float t) { return fabsf(a - b) <= ((maximum(fabsf(a), fabsf(b)) + 1.0f) * t); } inline bool equal_tol(double a, double b, double t) { return fabs(a - b) <= ((maximum(fabs(a), fabs(b)) + 1.0f) * t); } @@ -165,11 +165,11 @@ namespace basisu temp = 0; return temp; } - + inline uint32_t iabs(int32_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } inline uint64_t iabs64(int64_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } - template inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); } + template inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); } template inline typename T::value_type *enlarge_vector(T &vec, size_t n) { size_t cs = vec.size(); vec.resize(cs + n); return &vec[cs]; } inline bool is_pow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); } @@ -217,8 +217,8 @@ namespace basisu return val; } - template inline void append_vector(T &vec, const R *pObjs, size_t n) - { + template inline void append_vector(T &vec, const R *pObjs, size_t n) + { if (n) { if (vec.size()) @@ -269,7 +269,7 @@ namespace basisu for (size_t i = 0; i < vec.size(); i++) vec[i] = obj; } - + inline uint64_t read_be64(const void *p) { uint64_t val = 0; @@ -335,7 +335,7 @@ namespace basisu pBytes[2] = (uint8_t)(val >> 16U); pBytes[3] = (uint8_t)(val >> 24U); } - + // Always little endian 1-8 byte unsigned int template struct packed_uint @@ -345,42 +345,42 @@ namespace basisu inline packed_uint() { static_assert(NumBytes <= sizeof(uint64_t), "Invalid NumBytes"); } inline packed_uint(uint64_t v) { *this = v; } inline packed_uint(const packed_uint& other) { *this = other; } - - inline packed_uint& operator= (uint64_t v) - { - for (uint32_t i = 0; i < NumBytes; i++) - m_bytes[i] = static_cast(v >> (i * 8)); - return *this; + + inline packed_uint& operator= (uint64_t v) + { + for (uint32_t i = 0; i < NumBytes; i++) + m_bytes[i] = static_cast(v >> (i * 8)); + return *this; } - inline packed_uint& operator= (const packed_uint& rhs) - { - memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes)); + inline packed_uint& operator= (const packed_uint& rhs) + { + memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes)); return *this; } #if 0 #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" -#endif +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif inline operator uint32_t() const { switch (NumBytes) { - case 1: + case 1: { return m_bytes[0]; } - case 2: + case 2: { return (m_bytes[1] << 8U) | m_bytes[0]; } - case 3: + case 3: { return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0]; } - case 4: + case 4: { return read_le_dword(m_bytes); } @@ -402,13 +402,13 @@ namespace basisu uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4]; return static_cast(l) | (static_cast(h) << 32U); } - case 8: + case 8: { uint32_t l = read_le_dword(m_bytes); uint32_t h = read_le_dword(m_bytes + 4); return static_cast(l) | (static_cast(h) << 32U); } - default: + default: { assert(0); return 0; @@ -473,14 +473,14 @@ namespace basisu enum eZero { cZero }; enum eNoClamp { cNoClamp }; - + // Rice/Huffman entropy coding - + // This is basically Deflate-style canonical Huffman, except we allow for a lot more symbols. enum { - cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31, - cHuffmanFastLookupBits = 10, + cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31, + cHuffmanFastLookupBits = 10, cHuffmanMaxSymsLog2 = 14, cHuffmanMaxSyms = 1 << cHuffmanMaxSymsLog2, // Small zero runs @@ -506,13 +506,13 @@ namespace basisu enum class texture_format { cInvalidTextureFormat = -1, - + // Block-based formats cETC1, // ETC1 cETC1S, // ETC1 (subset: diff colors only, no subblocks) cETC2_RGB, // ETC2 color block (basisu doesn't support ETC2 planar/T/H modes - just basic ETC1) cETC2_RGBA, // ETC2 EAC alpha block followed by ETC2 color block - cETC2_ALPHA, // ETC2 EAC alpha block + cETC2_ALPHA, // ETC2 EAC alpha block cBC1, // DXT1 cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block) cBC4, // DXT5A @@ -531,11 +531,11 @@ namespace basisu cPVRTC2_4_RGBA, cETC2_R11_EAC, cETC2_RG11_EAC, - cUASTC4x4, + cUASTC4x4, cUASTC_HDR_4x4, cBC1_NV, cBC1_AMD, - + // Uncompressed/raw pixels cRGBA32, cRGB565, @@ -607,7 +607,7 @@ namespace basisu default: break; } - + // Everything else is 16 bytes/block. return 16; } @@ -675,6 +675,5 @@ namespace basisu { return !is_hdr_texture_format(fmt); } - -} // namespace basisu +} // namespace basisu diff --git a/transcoder/basisu_astc_hdr_core.h b/transcoder/basisu_astc_hdr_core.h index f17271a7..8e63f727 100644 --- a/transcoder/basisu_astc_hdr_core.h +++ b/transcoder/basisu_astc_hdr_core.h @@ -181,7 +181,7 @@ namespace basist bool m_hq_ls; bool m_brute_force_weight4_assignment; - + fast_bc6h_params() { init(); @@ -203,4 +203,3 @@ namespace basist } // namespace astc_6x6_hdr } // namespace basist - diff --git a/transcoder/basisu_astc_helpers.h b/transcoder/basisu_astc_helpers.h index 1f78a702..36412d56 100644 --- a/transcoder/basisu_astc_helpers.h +++ b/transcoder/basisu_astc_helpers.h @@ -84,7 +84,7 @@ namespace astc_helpers // The ISE range table. extern const int8_t g_ise_range_table[TOTAL_ISE_RANGES][3]; // 0=bits (0 to 8), 1=trits (0 or 1), 2=quints (0 or 1) - // Possible Color Component Select values, used in dual plane mode. + // Possible Color Component Select values, used in dual plane mode. // The CCS component will be interpolated using the 2nd weight plane. enum ccs { @@ -93,7 +93,7 @@ namespace astc_helpers CCS_RGA_B = 2, CCS_RGB_A = 3 }; - + struct astc_block { uint32_t m_vals[4]; @@ -107,14 +107,14 @@ namespace astc_helpers struct log_astc_block { bool m_error_flag; - + bool m_solid_color_flag_ldr, m_solid_color_flag_hdr; uint8_t m_user_mode; // user defined value, not used in this module - + // Rest is only valid if !m_solid_color_flag_ldr && !m_solid_color_flag_hdr uint8_t m_grid_width, m_grid_height; // weight grid dimensions, not the dimension of the block - + bool m_dual_plane; uint8_t m_weight_ise_range; // 0-11 @@ -124,16 +124,16 @@ namespace astc_helpers uint8_t m_num_partitions; // or the # of subsets, 1-4 (1-3 if dual plane mode) uint16_t m_partition_id; // 10-bits, must be 0 if m_num_partitions==1 - + uint8_t m_color_endpoint_modes[MAX_PARTITIONS]; // each subset's CEM's - + union { // ISE weight grid values. In dual plane mode, the order is p0,p1, p0,p1, etc. uint8_t m_weights[MAX_GRID_WEIGHTS]; uint16_t m_solid_color[4]; }; - + // ISE endpoint values // Endpoint order examples: // 1 subset LA : LL0 LH0 AL0 AH0 @@ -143,7 +143,7 @@ namespace astc_helpers // 2 subset RGB : RL0 RH0 GL0 GH0 BL0 BH0 RL1 RH1 GL1 GH1 BL1 BH1 // 2 subset RGBA : RL0 RH0 GL0 GH0 BL0 BH0 AL0 AH0 RL1 RH1 GL1 GH1 BL1 BH1 AL1 AH1 uint8_t m_endpoints[MAX_ENDPOINTS]; - + void clear() { memset(this, 0, sizeof(*this)); @@ -167,8 +167,8 @@ namespace astc_helpers } // Returns the number of levels in the given ISE range. - inline uint32_t get_ise_levels(uint32_t ise_range) - { + inline uint32_t get_ise_levels(uint32_t ise_range) + { assert(ise_range < TOTAL_ISE_RANGES); return (1 + 2 * g_ise_range_table[ise_range][1] + 4 * g_ise_range_table[ise_range][2]) << g_ise_range_table[ise_range][0]; } @@ -181,7 +181,7 @@ namespace astc_helpers total_bits += (g_ise_range_table[range][2] * 7 * count + 2) / 3; return total_bits; } - + inline uint32_t weight_interpolate(uint32_t l, uint32_t h, uint32_t w) { assert(w <= MAX_WEIGHT_VALUE); @@ -210,10 +210,10 @@ namespace astc_helpers void pack_void_extent_hdr(astc_block& blk, uint16_t rh, uint16_t gh, uint16_t bh, uint16_t ah, pack_stats* pStats = nullptr); // These helpers are all quite slow, but are useful for table preparation. - + // Dequantizes ISE encoded endpoint val to [0,255] uint32_t dequant_bise_endpoint(uint32_t val, uint32_t ise_range); // ISE ranges 4-11 - + // Dequantizes ISE encoded weight val to [0,64] uint32_t dequant_bise_weight(uint32_t val, uint32_t ise_range); // ISE ranges 0-10 @@ -237,7 +237,7 @@ namespace astc_helpers bool block_has_any_hdr_cems(const log_astc_block& log_blk); bool block_has_any_ldr_cems(const log_astc_block& log_blk); - + // Returns the # of endpoint values for the given CEM. inline uint32_t get_num_cem_values(uint32_t cem) { assert(cem <= 15); return 2 + 2 * (cem >> 2); } @@ -246,7 +246,7 @@ namespace astc_helpers basisu::vector m_val_to_ise; // [0-255] or [0-64] value to nearest ISE symbol, array size is [256] or [65] basisu::vector m_ISE_to_val; // ASTC encoded ISE symbol to [0,255] or [0,64] value, [levels] basisu::vector m_ISE_to_rank; // returns the level rank index given an ISE symbol, [levels] - basisu::vector m_rank_to_ISE; // returns the ISE symbol given a level rank, inverse of pISE_to_rank, [levels] + basisu::vector m_rank_to_ISE; // returns the ISE symbol given a level rank, inverse of pISE_to_rank, [levels] void init(bool weight_flag, uint32_t num_levels, bool init_rank_tabs) { @@ -333,10 +333,10 @@ namespace astc_helpers uint32_t wx, uint32_t wy, // source/from dimension const uint8_t* pSrc_weights, // these are dequantized [0,64] weights, NOT ISE symbols, [wy][wx] uint8_t* pDst_weights); // [by][bx] - + // Procedurally returns the texel partition/subset index given the block coordinate and config. int compute_texel_partition(uint32_t seedIn, uint32_t xIn, uint32_t yIn, uint32_t zIn, int num_partitions, bool small_block); - + void blue_contract( int r, int g, int b, int a, int& dr, int& dg, int& db, int& da); @@ -373,7 +373,7 @@ namespace astc_helpers const int MAX_RGB9E5 = 0xff80; void unpack_rgb9e5(uint32_t packed, float& r, float& g, float& b); uint32_t pack_rgb9e5(float r, float g, float b); - + enum decode_mode { cDecodeModeSRGB8 = 0, // returns uint8_t's, not valid on HDR blocks @@ -390,7 +390,7 @@ namespace astc_helpers // Unpack a physical ASTC encoded GPU texture block to a logical block description. bool unpack_block(const void* pASTC_block, log_astc_block& log_blk, uint32_t blk_width, uint32_t blk_height); - + } // namespace astc_helpers #endif // BASISU_ASTC_HELPERS_HEADER @@ -404,11 +404,11 @@ namespace astc_helpers template inline T my_min(T a, T b) { return (a < b) ? a : b; } template inline T my_max(T a, T b) { return (a > b) ? a : b; } - const uint8_t g_astc_block_sizes[NUM_ASTC_BLOCK_SIZES][2] = { - { 4, 4 }, { 5, 4 }, { 5, 5 }, { 6, 5 }, - { 6, 6 }, { 8, 5 }, { 8, 6 }, { 10, 5 }, - { 10, 6 }, { 8, 8 }, { 10, 8 }, { 10, 10 }, - { 12, 10 }, { 12, 12 } + const uint8_t g_astc_block_sizes[NUM_ASTC_BLOCK_SIZES][2] = { + { 4, 4 }, { 5, 4 }, { 5, 5 }, { 6, 5 }, + { 6, 6 }, { 8, 5 }, { 8, 6 }, { 10, 5 }, + { 10, 6 }, { 8, 8 }, { 10, 8 }, { 10, 10 }, + { 12, 10 }, { 12, 12 } }; const int8_t g_ise_range_table[TOTAL_ISE_RANGES][3] = @@ -437,7 +437,7 @@ namespace astc_helpers { 6, 1, 0 }, // 0..191 19 { 8, 0, 0 }, // 0..255 20 }; - + static inline void astc_set_bits_1_to_9(uint32_t* pDst, uint32_t& bit_offset, uint32_t code, uint32_t codesize) { uint8_t* pBuf = reinterpret_cast(pDst); @@ -552,10 +552,10 @@ namespace astc_helpers // Now interleave the 8 encoded trit bits with the bits to form the encoded output. See table 94. astc_set_bits(pOutput, bit_pos, bits[0] | (astc_extract_bits(T, 0, 1) << n) | (bits[1] << (2 + n)), n * 2 + 2); - + astc_set_bits(pOutput, bit_pos, astc_extract_bits(T, 2, 3) | (bits[2] << 2) | (astc_extract_bits(T, 4, 4) << (2 + n)) | (bits[3] << (3 + n)) | (astc_extract_bits(T, 5, 6) << (3 + n * 2)) | (bits[4] << (5 + n * 2)) | (astc_extract_bits(T, 7, 7) << (5 + n * 3)), n * 3 + 6); - + if (pStats) *pStats += n * 5 + 8; } @@ -583,7 +583,7 @@ namespace astc_helpers if (group_size) { - // Range has trits or quints - pack each group of 5 or 3 values + // Range has trits or quints - pack each group of 5 or 3 values const int total_groups = (group_size == 5) ? ((num_vals + 4) / 5) : ((num_vals + 2) / 3); for (int group_index = 0; group_index < total_groups; group_index++) @@ -594,7 +594,7 @@ namespace astc_helpers for (int i = 0; i < limit; i++) vals[i] = pSrc_vals[group_index * group_size + i]; - // Note this always writes a group of 3 or 5 bits values, even for incomplete groups. So it can write more than needed. + // Note this always writes a group of 3 or 5 bits values, even for incomplete groups. So it can write more than needed. // get_ise_sequence_bits() returns the # of bits that must be written for proper decoding. if (group_size == 5) astc_encode_trits(temp, vals, bit_pos, num_bits, pStats); @@ -633,14 +633,14 @@ namespace astc_helpers const uint32_t P = log_block.m_weight_ise_range >= 6; // high precision const uint32_t Dp_P = (log_block.m_dual_plane << 1) | P; // pack dual plane+high precision bits - + // See Tables 81-82 // Compute p from weight range uint32_t p = 2 + log_block.m_weight_ise_range - (P ? 6 : 0); - + // Rearrange p's bits to p0 p2 p1 p = (p >> 1) + ((p & 1) << 2); - + // Try encoding each row of table 82. // W+4 H+2 @@ -677,7 +677,7 @@ namespace astc_helpers config_bits = (Dp_P << 9) | ((W) << 7) | ((H - 2) << 5) | ((p & 4) << 2) | 12 | (p & 3); return true; } - + // 12 H+2 if ((W == 12) && is_packable(H - 2, 2)) { @@ -705,7 +705,7 @@ namespace astc_helpers config_bits = (Dp_P << 9) | (0b1101 << 5) | (p << 2); return true; } - + // W+6 H+6 (no dual plane or high prec) if ((!Dp_P) && is_packable(W - 6, 2) && is_packable(H - 6, 2)) { @@ -727,7 +727,7 @@ namespace astc_helpers assert(!log_block.m_error_flag); if (log_block.m_error_flag) return false; - + if (log_block.m_solid_color_flag_ldr) { pack_void_extent_ldr(phys_block, log_block.m_solid_color[0], log_block.m_solid_color[1], log_block.m_solid_color[2], log_block.m_solid_color[3], pStats); @@ -738,7 +738,7 @@ namespace astc_helpers pack_void_extent_hdr(phys_block, log_block.m_solid_color[0], log_block.m_solid_color[1], log_block.m_solid_color[2], log_block.m_solid_color[3], pStats); return true; } - + if ((log_block.m_num_partitions < 1) || (log_block.m_num_partitions > MAX_PARTITIONS)) return false; @@ -754,7 +754,7 @@ namespace astc_helpers return false; // TODO: sanity check grid width/height vs. block's physical width/height - + uint32_t config_bits = 0; if (!get_config_bits(log_block, config_bits)) return false; @@ -795,7 +795,7 @@ namespace astc_helpers if (highest_cem > 15) return false; - + // Ensure CEM range is contiguous if (((highest_cem >> 2) > (1 + (lowest_cem >> 2)))) return false; @@ -810,7 +810,7 @@ namespace astc_helpers for (uint32_t j = 0; j < log_block.m_num_partitions; j++) { const int M = log_block.m_color_endpoint_modes[j] & 3; - + const int C = (log_block.m_color_endpoint_modes[j] >> 2) - ((encoded_cem & 3) - 1); if ((C & 1) != C) return false; @@ -851,7 +851,7 @@ namespace astc_helpers return false; total_extra_bits += 2; - + uint32_t ccs_bit_pos = 128 - (int)total_weight_bits - (int)total_extra_bits; astc_set_bits(&phys_block.m_vals[0], ccs_bit_pos, log_block.m_color_component_selector, 2); if (pStats) @@ -901,7 +901,7 @@ namespace astc_helpers // Pack endpoints forwards encode_bise(&phys_block.m_vals[0], log_block.m_endpoints, bit_pos, total_cem_vals, endpoint_ise_range); - + // Pack weights backwards uint32_t weight_data[4] = { 0 }; encode_bise(weight_data, log_block.m_weights, 0, total_grid_weights, log_block.m_weight_ise_range); @@ -1095,12 +1095,12 @@ namespace astc_helpers uint32_t u = 0; switch (ise_range) { - case 0: + case 0: { u = val ? 63 : 0; break; } - case 1: // 0-2 + case 1: // 0-2 { const uint8_t s_tab_0_2[3] = { 0, 32, 63 }; u = s_tab_0_2[val]; @@ -1141,7 +1141,7 @@ namespace astc_helpers const uint32_t num_bits = g_ise_range_table[ise_range][0]; const uint32_t num_trits = g_ise_range_table[ise_range][1]; BASISU_NOTE_UNUSED(num_trits); const uint32_t num_quints = g_ise_range_table[ise_range][2]; BASISU_NOTE_UNUSED(num_quints); - + // compute Table 103 row index const int range_index = num_bits * 2 + (num_quints ? 1 : 0); @@ -1154,11 +1154,11 @@ namespace astc_helpers // Now dequantize // See Table 103. ASTC weight unquantization parameters static const uint32_t C_table[5] = { 50, 28, 23, 13, 11 }; - + const uint32_t a = bits & 1, b = (bits >> 1) & 1, c = (bits >> 2) & 1; const uint32_t A = (a == 0) ? 0 : 0x7F; - + uint32_t B = 0; if (range_index == 4) B = ((b << 6) | (b << 2) | (b << 0)); @@ -1274,22 +1274,22 @@ namespace astc_helpers for (uint32_t i = 0; i < num_levels; i++) { uint32_t v = weight_flag ? astc_helpers::dequant_bise_weight(i, ise_range) : astc_helpers::dequant_bise_endpoint(i, ise_range); - + // Low=ISE value // High=dequantized value vals[i] = (v << 16) | i; } - + // Sorts by dequantized value std::sort(vals, vals + num_levels); - + for (uint32_t rank = 0; rank < num_levels; rank++) { uint32_t ise_val = (uint8_t)vals[rank]; if (pISE_to_rank) pISE_to_rank[ise_val] = (uint8_t)rank; - + if (pRank_to_ISE) pRank_to_ISE[rank] = (uint8_t)ise_val; } @@ -1319,13 +1319,13 @@ namespace astc_helpers } // rh-ah are half-floats - void pack_void_extent_hdr(astc_block& blk, uint16_t rh, uint16_t gh, uint16_t bh, uint16_t ah, pack_stats *pStats) + void pack_void_extent_hdr(astc_block& blk, uint16_t rh, uint16_t gh, uint16_t bh, uint16_t ah, pack_stats *pStats) { uint8_t* pDst = (uint8_t*)&blk.m_vals[0]; memset(pDst, 0xFF, 16); pDst[0] = 0b11111100; - + pDst[8] = (uint8_t)rh; pDst[9] = (uint8_t)(rh >> 8); pDst[10] = (uint8_t)gh; @@ -1338,7 +1338,7 @@ namespace astc_helpers if (pStats) pStats->m_header_bits += 128; } - + bool is_cem_ldr(uint32_t mode) { switch (mode) @@ -1357,7 +1357,7 @@ namespace astc_helpers default: break; } - + return false; } @@ -1412,7 +1412,7 @@ namespace astc_helpers return false; } - + dequant_tables g_dequant_tables; void precompute_texel_partitions_4x4(); @@ -1421,11 +1421,11 @@ namespace astc_helpers void init_tables(bool init_rank_tabs) { g_dequant_tables.init(init_rank_tabs); - + precompute_texel_partitions_4x4(); precompute_texel_partitions_6x6(); } - + void compute_upsample_weights( int block_width, int block_height, int weight_grid_width, int weight_grid_height, @@ -1585,8 +1585,8 @@ namespace astc_helpers } // 4x4, 2 and 3 subsets - static uint32_t g_texel_partitions_4x4[1024][2]; - + static uint32_t g_texel_partitions_4x4[1024][2]; + // 6x6, 2 and 3 subsets (2 subsets low 4 bits, 3 subsets high 4 bits) static uint8_t g_texel_partitions_6x6[1024][6 * 6]; @@ -1621,7 +1621,7 @@ namespace astc_helpers { const uint32_t p2 = compute_texel_partition(p, x, y, 0, 2, false); const uint32_t p3 = compute_texel_partition(p, x, y, 0, 3, false); - + assert((p2 <= 1) && (p3 <= 2)); g_texel_partitions_6x6[p][x + y * 6] = (uint8_t)((p3 << 4) | p2); } @@ -1635,7 +1635,7 @@ namespace astc_helpers assert(seed < 1024); assert((x <= 3) && (y <= 3)); assert((num_partitions >= 2) && (num_partitions <= 3)); - + const uint32_t shift = x * 2 + y * 8; return (g_texel_partitions_4x4[seed][num_partitions - 2] >> shift) & 3; } @@ -1652,7 +1652,7 @@ namespace astc_helpers } void blue_contract( - int r, int g, int b, int a, + int r, int g, int b, int a, int &dr, int &dg, int &db, int &da) { dr = (r + b) >> 1; @@ -1667,7 +1667,7 @@ namespace astc_helpers b |= (a & 0x80); a >>= 1; a &= 0x3F; - if ((a & 0x20) != 0) + if ((a & 0x20) != 0) a -= 0x40; } @@ -1901,7 +1901,7 @@ namespace astc_helpers e0_g = y0; e1_g = y1; e0_b = y0; e1_b = y1; e0_a = 0x780; e1_a = 0x780; - + break; } case CEM_HDR_LUM_SMALL_RANGE: @@ -1918,11 +1918,11 @@ namespace astc_helpers y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1); d = (v1 & 0x0F) << 1; } - + y1 = y0 + d; - if (y1 > 0xFFF) + if (y1 > 0xFFF) y1 = 0xFFF; - + e0_r = y0; e1_r = y1; e0_g = y0; e1_g = y1; e0_b = y0; e1_b = y1; @@ -1933,36 +1933,36 @@ namespace astc_helpers case CEM_HDR_RGB_BASE_SCALE: { int v2 = pE[2], v3 = pE[3]; - + int modeval = ((v0 & 0xC0) >> 6) | ((v1 & 0x80) >> 5) | ((v2 & 0x80) >> 4); - + int majcomp, mode; - if ((modeval & 0xC) != 0xC) + if ((modeval & 0xC) != 0xC) { - majcomp = modeval >> 2; + majcomp = modeval >> 2; mode = modeval & 3; } - else if (modeval != 0xF) + else if (modeval != 0xF) { - majcomp = modeval & 3; + majcomp = modeval & 3; mode = 4; } - else + else { - majcomp = 0; + majcomp = 0; mode = 5; } - int red = v0 & 0x3f; + int red = v0 & 0x3f; int green = v1 & 0x1f; - int blue = v2 & 0x1f; + int blue = v2 & 0x1f; int scale = v3 & 0x1f; - int x0 = (v1 >> 6) & 1; - int x1 = (v1 >> 5) & 1; + int x0 = (v1 >> 6) & 1; + int x1 = (v1 >> 5) & 1; int x2 = (v2 >> 6) & 1; - int x3 = (v2 >> 5) & 1; - int x4 = (v3 >> 7) & 1; + int x3 = (v2 >> 5) & 1; + int x4 = (v3 >> 7) & 1; int x5 = (v3 >> 6) & 1; int x6 = (v3 >> 5) & 1; @@ -1986,25 +1986,25 @@ namespace astc_helpers if (ohm & 0x02) red |= x5 << 10; static const int s_shamts[6] = { 1,1,2,3,4,5 }; - + const int shamt = s_shamts[mode]; - red <<= shamt; - green <<= shamt; - blue <<= shamt; + red <<= shamt; + green <<= shamt; + blue <<= shamt; scale <<= shamt; - if (mode != 5) - { - green = red - green; - blue = red - blue; + if (mode != 5) + { + green = red - green; + blue = red - blue; } - if (majcomp == 1) + if (majcomp == 1) std::swap(red, green); - if (majcomp == 2) + if (majcomp == 2) std::swap(red, blue); - + e1_r = clamp(red, 0, 0xFFF); e1_g = clamp(green, 0, 0xFFF); e1_b = clamp(blue, 0, 0xFFF); @@ -2028,7 +2028,7 @@ namespace astc_helpers e0_a = 0x780; e1_a = 0x780; - if (majcomp == 3) + if (majcomp == 3) { e0_r = v0 << 4; e0_g = v2 << 4; @@ -2129,12 +2129,12 @@ namespace astc_helpers v7 &= (0x3F >> mode); v7 ^= (0x20 >> mode); v7 -= (0x20 >> mode); - v6 <<= (4 - mode); + v6 <<= (4 - mode); v7 <<= (4 - mode); v7 += v6; v7 = clamp(v7, 0, 0xFFF); - e0_a = v6; + e0_a = v6; e1_a = v7; } } @@ -2153,7 +2153,7 @@ namespace astc_helpers } } } - + static inline bool is_half_inf_or_nan(half_float v) { return get_bits(v, 10, 14) == 31; @@ -2266,7 +2266,7 @@ namespace astc_helpers x.u = m | (e << 23) | (s << 31); return x.f; } - + // See https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt const int RGB9E5_EXPONENT_BITS = 5, RGB9E5_MANTISSA_BITS = 9, RGB9E5_EXP_BIAS = 15, RGB9E5_MAX_VALID_BIASED_EXP = 31; const int MAX_RGB9E5_EXP = (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS); @@ -2274,7 +2274,7 @@ namespace astc_helpers const int MAX_RGB9E5_MANTISSA = (RGB9E5_MANTISSA_VALUES - 1); //const int MAX_RGB9E5 = (int)(((float)MAX_RGB9E5_MANTISSA) / RGB9E5_MANTISSA_VALUES * (1 << MAX_RGB9E5_EXP)); const int EPSILON_RGB9E5 = (int)((1.0f / (float)RGB9E5_MANTISSA_VALUES) / (float)(1 << RGB9E5_EXP_BIAS)); - + void unpack_rgb9e5(uint32_t packed, float& r, float& g, float& b) { int x = packed & 511; @@ -2288,9 +2288,9 @@ namespace astc_helpers g = y * scale; b = z * scale; } - + // floor_log2 is not correct for the denorm and zero values, but we are going to do a max of this value with the minimum rgb9e5 exponent that will hide these problem cases. - static inline int floor_log2(float x) + static inline int floor_log2(float x) { union float754 { @@ -2326,7 +2326,7 @@ namespace astc_helpers exp_shared += 1; assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); } - else + else { assert(maxm <= MAX_RGB9E5_MANTISSA); } @@ -2338,7 +2338,7 @@ namespace astc_helpers assert((rm >= 0) && (rm <= MAX_RGB9E5_MANTISSA)); assert((gm >= 0) && (gm <= MAX_RGB9E5_MANTISSA)); assert((bm >= 0) && (bm <= MAX_RGB9E5_MANTISSA)); - + return rm | (gm << 9) | (bm << 18) | (exp_shared << 27); } @@ -2349,7 +2349,7 @@ namespace astc_helpers if (!x) return 17; - + uint32_t n = 0; while ((x & 0x10000) == 0) { @@ -2426,18 +2426,18 @@ namespace astc_helpers uint32_t texel = (expo << 27) | (Bm << 18) | (Gm << 9) | (Rm << 0); return texel; } - + // Important: pPixels is either 32-bit/texel or 64-bit/texel. bool decode_block(const log_astc_block& log_blk, void* pPixels, uint32_t blk_width, uint32_t blk_height, decode_mode dec_mode) { assert(is_valid_block_size(blk_width, blk_height)); - + assert(g_dequant_tables.m_endpoints[0].m_ISE_to_val.size()); if (!g_dequant_tables.m_endpoints[0].m_ISE_to_val.size()) return false; const uint32_t num_blk_pixels = blk_width * blk_height; - + // Write block error color if (dec_mode == cDecodeModeHDR16) { @@ -2511,7 +2511,7 @@ namespace astc_helpers float r = half_to_float(log_blk.m_solid_color[0]); float g = half_to_float(log_blk.m_solid_color[1]); float b = half_to_float(log_blk.m_solid_color[2]); - + const uint32_t packed = pack_rgb9e5(r, g, b); for (uint32_t i = 0; i < num_blk_pixels; i++) @@ -2524,7 +2524,7 @@ namespace astc_helpers return true; } - + // Sanity check block's config if ((log_blk.m_grid_width < 2) || (log_blk.m_grid_height < 2)) return false; @@ -2548,7 +2548,7 @@ namespace astc_helpers const uint32_t total_endpoint_levels = get_ise_levels(log_blk.m_endpoint_ise_range); const uint32_t total_weight_levels = get_ise_levels(log_blk.m_weight_ise_range); - + bool is_ldr_endpoints[MAX_PARTITIONS]; // Check CEM's @@ -2559,7 +2559,7 @@ namespace astc_helpers return false; total_cem_vals += get_num_cem_values(log_blk.m_color_endpoint_modes[i]); - + is_ldr_endpoints[i] = is_cem_ldr(log_blk.m_color_endpoint_modes[i]); } @@ -2577,13 +2577,13 @@ namespace astc_helpers return false; dequantized_endpoints[i] = pEndpoint_dequant[log_blk.m_endpoints[i]]; } - + // Dequantize weights to [0,64] uint8_t dequantized_weights[2][12 * 12]; - + const dequant_table& weight_dequant_tab = g_dequant_tables.get_weight_tab(log_blk.m_weight_ise_range); const uint8_t* pWeight_dequant = weight_dequant_tab.m_ISE_to_val.data(); - + const uint32_t total_weight_vals = (log_blk.m_dual_plane ? 2 : 1) * log_blk.m_grid_width * log_blk.m_grid_height; for (uint32_t i = 0; i < total_weight_vals; i++) { @@ -2621,7 +2621,7 @@ namespace astc_helpers const bool use_precomputed_texel_partitions_4x4 = (blk_width == 4) && (blk_height == 4) && (log_blk.m_num_partitions >= 2) && (log_blk.m_num_partitions <= 3); const bool use_precomputed_texel_partitions_6x6 = (blk_width == 6) && (blk_height == 6) && (log_blk.m_num_partitions >= 2) && (log_blk.m_num_partitions <= 3); const uint32_t ccs = log_blk.m_dual_plane ? log_blk.m_color_component_selector : UINT32_MAX; - + bool success = true; if (dec_mode == cDecodeModeRGB9E5) @@ -2632,7 +2632,7 @@ namespace astc_helpers for (uint32_t x = 0; x < blk_width; x++) { const uint32_t pixel_index = x + y * blk_width; - + uint32_t subset = 0; if (log_blk.m_num_partitions > 1) { @@ -2681,7 +2681,7 @@ namespace astc_helpers if (is_half_inf_or_nan((half_float)comp[c])) comp[c] = 0x7BFF; } - + } // c uint32_t packed; @@ -2698,14 +2698,14 @@ namespace astc_helpers else if (dec_mode == cDecodeModeHDR16) { // Note: must round towards zero when converting float to half for ASTC (18.19 Weight Application) - + // returns half floats for (uint32_t y = 0; y < blk_height; y++) { for (uint32_t x = 0; x < blk_width; x++) { const uint32_t pixel_index = x + y * blk_width; - + uint32_t subset = 0; if (log_blk.m_num_partitions > 1) { @@ -2752,13 +2752,13 @@ namespace astc_helpers int he = endpoints[subset][c][1] << 4; int qlog16 = weight_interpolate(le, he, w); - + o = qlog16_to_half(qlog16); if (is_half_inf_or_nan(o)) o = 0x7BFF; } - + ((half_float*)pPixels)[pixel_index * 4 + c] = o; } @@ -2816,7 +2816,7 @@ namespace astc_helpers uint32_t k = weight_interpolate(le, he, w); // FIXME: This is what the spec says to do in LDR mode, but this is not what ARM's decoder does - // See decompress_symbolic_block(), decode_texel() and unorm16_to_sf16. + // See decompress_symbolic_block(), decode_texel() and unorm16_to_sf16. // It seems to effectively divide by 65535.0 and convert to FP16, then back to float, mul by 255.0, add .5 and then convert to 8-bit. ((uint8_t*)pPixels)[pixel_index * 4 + c] = (uint8_t)(k >> 8); } @@ -2825,7 +2825,7 @@ namespace astc_helpers } // x } // y } - + return success; } @@ -3221,7 +3221,7 @@ namespace astc_helpers return *this; } }; - + static bool decode_void_extent(const uint128& bits, log_astc_block& log_blk) { if (bits.get_bits(10, 2) != 0b11) @@ -3233,9 +3233,9 @@ namespace astc_helpers const uint32_t min_t = bits.next_bits(bit_ofs, 13); const uint32_t max_t = bits.next_bits(bit_ofs, 13); assert(bit_ofs == 64); - + const bool all_extents_all_ones = (min_s == 0x1FFF) && (max_s == 0x1FFF) && (min_t == 0x1FFF) && (max_t == 0x1FFF); - + if (!all_extents_all_ones && ((min_s >= max_s) || (min_t >= max_t))) return false; @@ -3257,7 +3257,7 @@ namespace astc_helpers if (is_half_inf_or_nan(log_blk.m_solid_color[c])) return false; } - + return true; } @@ -3270,7 +3270,7 @@ namespace astc_helpers { // Dp_ofs, P_ofs, W_ofs, W_size, H_ofs, H_size, W_bias, H_bias, p0_ofs, p1_ofs, p2_ofs; { 10, 9, 7, 2, 5, 2, 4, 2, 4, 0, 1 }, // 4 2 - { 10, 9, 7, 2, 5, 2, 8, 2, 4, 0, 1 }, // 8 2 + { 10, 9, 7, 2, 5, 2, 8, 2, 4, 0, 1 }, // 8 2 { 10, 9, 5, 2, 7, 2, 2, 8, 4, 0, 1 }, // 2 8 { 10, 9, 5, 2, 7, 1, 2, 6, 4, 0, 1 }, // 2 6 @@ -3292,14 +3292,14 @@ namespace astc_helpers // Reserved if ((bits.get_bits(0, 2) == 0) && (bits.get_bits(6, 3) == 0b111)) { - if (bits.get_bits(2, 4) != 0b1111) + if (bits.get_bits(2, 4) != 0b1111) return false; } // Void extent if (bits.get_bits(0, 9) == 0b111111100) return decode_void_extent(bits, log_blk); - + // Check rows const uint32_t x0_2 = bits.get_bits(0, 2), x2_2 = bits.get_bits(2, 2); const uint32_t x5_4 = bits.get_bits(5, 4), x8_1 = bits.get_bits(8, 1); @@ -3345,7 +3345,7 @@ namespace astc_helpers if (r.Dp_ofs >= 0) Dp = bits.get_bits(r.Dp_ofs, 1) != 0; - + if (r.W_size) W += bits.get_bits(r.W_ofs, r.W_size); @@ -3354,7 +3354,7 @@ namespace astc_helpers assert((W >= MIN_GRID_DIM) && (W <= MAX_BLOCK_DIM)); assert((H >= MIN_GRID_DIM) && (H <= MAX_BLOCK_DIM)); - + int p0 = bits.get_bits(r.p0_ofs, 1); int p1 = bits.get_bits(r.p1_ofs, 1); int p2 = bits.get_bits(r.p2_ofs, 1); @@ -3362,10 +3362,10 @@ namespace astc_helpers uint32_t p = p0 | (p1 << 1) | (p2 << 2); if (p < 2) return false; - + log_blk.m_grid_width = (uint8_t)W; log_blk.m_grid_height = (uint8_t)H; - + log_blk.m_weight_ise_range = (uint8_t)((p - 2) + (P * BISE_10_LEVELS)); assert(log_blk.m_weight_ise_range <= LAST_VALID_WEIGHT_ISE_RANGE); @@ -3481,7 +3481,7 @@ namespace astc_helpers static void decode_bise(uint32_t ise_range, uint8_t* pVals, uint32_t num_vals, const uint128& bits, uint32_t bit_ofs) { assert(num_vals && (ise_range < TOTAL_ISE_RANGES)); - + const uint32_t bits_per_val = g_ise_range_table[ise_range][0]; if (g_ise_range_table[ise_range][1]) @@ -3522,24 +3522,24 @@ namespace astc_helpers return decode_bise(ise_range, pVals, num_vals, bits, bit_ofs); } - + // Decodes a physical ASTC block to a logical ASTC block. // blk_width/blk_height are only used to validate the weight grid's dimensions. bool unpack_block(const void* pASTC_block, log_astc_block& log_blk, uint32_t blk_width, uint32_t blk_height) { assert(is_valid_block_size(blk_width, blk_height)); - + const uint8_t* pS = (uint8_t*)pASTC_block; log_blk.clear(); log_blk.m_error_flag = true; - + const uint128 bits( (uint64_t)read_le_dword(pS) | (((uint64_t)read_le_dword(pS + sizeof(uint32_t))) << 32), (uint64_t)read_le_dword(pS + sizeof(uint32_t) * 2) | (((uint64_t)read_le_dword(pS + sizeof(uint32_t) * 3)) << 32)); - + const uint128 rev_bits(bits.get_reversed_bits()); - + if (!decode_config(bits, log_blk)) return false; @@ -3553,16 +3553,16 @@ namespace astc_helpers // Check grid dimensions if ((log_blk.m_grid_width > blk_width) || (log_blk.m_grid_height > blk_height)) return false; - + // Now we have the grid width/height, dual plane, weight ISE range - + const uint32_t total_grid_weights = (log_blk.m_dual_plane ? 2 : 1) * (log_blk.m_grid_width * log_blk.m_grid_height); const uint32_t total_weight_bits = get_ise_sequence_bits(total_grid_weights, log_blk.m_weight_ise_range); - + // 18.24 Illegal Encodings if ((!total_grid_weights) || (total_grid_weights > MAX_GRID_WEIGHTS) || (total_weight_bits < 24) || (total_weight_bits > 96)) return false; - + const uint32_t end_of_weight_bit_ofs = 128 - total_weight_bits; uint32_t total_extra_bits = 0; @@ -3599,9 +3599,9 @@ namespace astc_helpers return false; uint32_t cem_bit_pos = end_of_weight_bit_ofs - total_extra_bits; - + uint32_t c[4] = { 0 }, m[4] = { 0 }; - + cem_bits >>= 2; for (uint32_t i = 0; i < log_blk.m_num_partitions; i++, cem_bits >>= 1) c[i] = cem_bits & 1; @@ -3667,7 +3667,7 @@ namespace astc_helpers // config+num_parts+total_extra_bits (CEM extra+CCS) uint32_t total_config_bits = config_bit_pos + total_extra_bits; - + // Compute number of remaining bits in block const int num_remaining_bits = 128 - (int)total_config_bits - (int)total_weight_bits; if (num_remaining_bits < 0) @@ -3709,7 +3709,7 @@ namespace astc_helpers return true; } - + } // namespace astc_helpers #endif //BASISU_ASTC_HELPERS_IMPLEMENTATION diff --git a/transcoder/basisu_containers.h b/transcoder/basisu_containers.h index 03fae339..a7d2ae38 100644 --- a/transcoder/basisu_containers.h +++ b/transcoder/basisu_containers.h @@ -272,7 +272,7 @@ namespace basisu size_t c = a + b; return c < a; } - + // Returns false on overflow, true if OK. template inline bool can_fit_into_size_t(T val) @@ -294,7 +294,7 @@ namespace basisu template class writable_span; - + template class readable_span { @@ -304,7 +304,7 @@ namespace basisu using const_pointer = const T*; using const_reference = const T&; using const_iterator = const T*; - + inline readable_span() : m_p(nullptr), m_size(0) @@ -941,7 +941,7 @@ namespace basisu inline iterator begin() const { return m_p; } inline iterator end() const { assert(m_p || !m_size); return m_p + m_size; } - + inline const_iterator cbegin() const { return m_p; } inline const_iterator cend() const { assert(m_p || !m_size); return m_p + m_size; } @@ -1507,8 +1507,8 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif #endif if ((m_p) && (other.m_p)) { @@ -1517,7 +1517,7 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } else @@ -1652,15 +1652,15 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif #endif if ((m_p) && (other.m_p)) memcpy(m_p, other.m_p, other.m_size * sizeof(T)); -#ifndef __EMSCRIPTEN__ +#ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } else @@ -2155,7 +2155,7 @@ namespace basisu if (!try_insert(p, obj)) container_abort("vector::insert() failed!\n"); } - + // push_front() isn't going to be very fast - it's only here for usability. inline void push_front(const T& obj) { @@ -2237,7 +2237,7 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" +#pragma GCC diagnostic ignored "-Wclass-memaccess" #endif #endif @@ -2246,12 +2246,12 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } else { - // Type is not bitwise copyable or movable. + // Type is not bitwise copyable or movable. // Move them down one at a time by using the equals operator, and destroying anything that's left over at the end. T* pDst_end = pDst + num_to_move; @@ -2495,15 +2495,15 @@ namespace basisu #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif #endif memset(m_p, *reinterpret_cast(&o), m_size); -#ifndef __EMSCRIPTEN__ +#ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } else @@ -3118,7 +3118,7 @@ namespace basisu { return try_insert(result, std::move(v.first), std::move(v.second)); } - + inline const_iterator find(const Key& k) const { return const_iterator(*this, find_index(k)); @@ -3737,11 +3737,11 @@ namespace basisu va_list args; va_start(args, pFmt); -#ifdef _WIN32 +#ifdef _WIN32 vsprintf_s(buf, sizeof(buf), pFmt, args); #else vsnprintf(buf, sizeof(buf), pFmt, args); -#endif +#endif va_end(args); return std::string(buf); @@ -3909,7 +3909,7 @@ namespace basisu std::size_t copy_size = std::min(list.size(), N); std::copy_n(list.begin(), copy_size, m_data); // Copy up to min(list.size(), N) - if (list.size() < N) + if (list.size() < N) { // Initialize the rest of the array std::fill(m_data + copy_size, m_data + N, T{}); @@ -3923,7 +3923,7 @@ namespace basisu return m_data[index]; } - BASISU_FORCE_INLINE const T& operator[](std::size_t index) const + BASISU_FORCE_INLINE const T& operator[](std::size_t index) const { if (index >= N) container_abort("fixed_array: Index out of bounds."); @@ -3966,26 +3966,26 @@ namespace basisu { return writable_span(m_data, N); } - + private: BASISU_FORCE_INLINE void initialize_array() { - if constexpr (std::is_integral::value || std::is_floating_point::value) + if constexpr (std::is_integral::value || std::is_floating_point::value) memset(m_data, 0, sizeof(m_data)); - else + else std::fill(m_data, m_data + N, T{}); } BASISU_FORCE_INLINE T& access_element(std::size_t index) { - if (index >= N) + if (index >= N) container_abort("fixed_array: Index out of bounds."); return m_data[index]; } BASISU_FORCE_INLINE const T& access_element(std::size_t index) const { - if (index >= N) + if (index >= N) container_abort("fixed_array: Index out of bounds."); return m_data[index]; } @@ -4182,7 +4182,7 @@ namespace basisu return *this; } }; - + } // namespace basisu namespace std diff --git a/transcoder/basisu_containers_impl.h b/transcoder/basisu_containers_impl.h index d4d3eb23..f8ea5f85 100644 --- a/transcoder/basisu_containers_impl.h +++ b/transcoder/basisu_containers_impl.h @@ -12,7 +12,7 @@ namespace basisu #ifdef _MSC_VER __declspec(noreturn) #else - [[noreturn]] + [[noreturn]] #endif void container_abort(const char* pMsg, ...) { @@ -40,12 +40,12 @@ namespace basisu assert(m_size <= m_capacity); assert(min_new_capacity >= m_size); assert(element_size); - + // Basic sanity check min_new_capacity if (!can_fit_into_size_t((uint64_t)min_new_capacity * element_size)) { assert(0); - + if (nofail_flag) return false; @@ -98,7 +98,7 @@ namespace basisu } const size_t desired_size = static_cast(desired_size_u64); - + size_t actual_size = 0; BASISU_NOTE_UNUSED(actual_size); @@ -267,7 +267,7 @@ namespace basisu s.insert(i); k.push_back(i); } - + for (uint32_t i = 0; i < k.size(); i++) { uint32_t r = rand() ^ (rand() << 15); @@ -313,7 +313,7 @@ namespace basisu { typedef basisu::hash_map< uint32_t, basisu::vector > hm; hm q; - + basisu::vector a, b; a.push_back(1); b.push_back(2); diff --git a/transcoder/basisu_file_headers.h b/transcoder/basisu_file_headers.h index 5c160662..ddd117a0 100644 --- a/transcoder/basisu_file_headers.h +++ b/transcoder/basisu_file_headers.h @@ -21,10 +21,10 @@ namespace basist enum basis_slice_desc_flags { cSliceDescFlagsHasAlpha = 1, - + // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols) // Currently the first frame is always an I-Frame, all subsequent frames are P-Frames. This will eventually be changed to periodic I-Frames. - cSliceDescFlagsFrameIsIFrame = 2 + cSliceDescFlagsFrameIsIFrame = 2 }; #pragma pack(push) @@ -39,7 +39,7 @@ namespace basist basisu::packed_uint<2> m_orig_height; // The original image height (may not be a multiple of 4 pixels) basisu::packed_uint<2> m_num_blocks_x; // The slice's block X dimensions. Each block is 4x4 or 6x6 pixels. The slice's pixel resolution may or may not be a power of 2. - basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions. + basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions. basisu::packed_uint<4> m_file_ofs; // Offset from the start of the file to the start of the slice's data basisu::packed_uint<4> m_file_size; // The size of the compressed slice data in bytes @@ -51,24 +51,24 @@ namespace basist enum basis_header_flags { // Always set for ETC1S files. Not set for UASTC files. - cBASISHeaderFlagETC1S = 1, - + cBASISHeaderFlagETC1S = 1, + // Set if the texture had to be Y flipped before encoding. The actual interpretation of this (is Y up or down?) is up to the user. - cBASISHeaderFlagYFlipped = 2, - + cBASISHeaderFlagYFlipped = 2, + // Set if any slices contain alpha (for ETC1S, if the odd slices contain alpha data) - cBASISHeaderFlagHasAlphaSlices = 4, - - // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file. - cBASISHeaderFlagUsesGlobalCodebook = 8, - - // Set if the texture data is sRGB, otherwise it's linear. + cBASISHeaderFlagHasAlphaSlices = 4, + + // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file. + cBASISHeaderFlagUsesGlobalCodebook = 8, + + // Set if the texture data is sRGB, otherwise it's linear. // In reality, we have no idea if the texture data is actually linear or sRGB. This is the m_perceptual parameter passed to the compressor. - cBASISHeaderFlagSRGB = 16, + cBASISHeaderFlagSRGB = 16, }; // The image type field attempts to describe how to interpret the image data in a Basis file. - // The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user. + // The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user. // We do make sure the various constraints are followed (2DArray/cubemap/videoframes/volume implies that each image has the same resolution and # of mipmap levels, etc., cubemap implies that the # of image slices is a multiple of 6) enum basis_texture_type { @@ -115,7 +115,7 @@ namespace basist basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha .basis files) basisu::packed_uint<3> m_total_images; // The total # of images - + basisu::packed_uint<1> m_tex_format; // enum basis_tex_format basisu::packed_uint<2> m_flags; // enum basist::header_flags basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type @@ -125,11 +125,11 @@ namespace basist basisu::packed_uint<4> m_userdata0; // For client use basisu::packed_uint<4> m_userdata1; // For client use - basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook + basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the start of the file basisu::packed_uint<3> m_endpoint_cb_file_size; // The compressed endpoint codebook's size in bytes - basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook + basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the start of the file basisu::packed_uint<3> m_selector_cb_file_size; // The compressed selector codebook's size in bytes @@ -137,7 +137,7 @@ namespace basist basisu::packed_uint<4> m_tables_file_size; // The file size in bytes of the compressed huffman codelength tables basisu::packed_uint<4> m_slice_desc_file_ofs; // The file offset to the slice description array, usually follows the header - + basisu::packed_uint<4> m_extended_file_ofs; // The file offset of the "extended" header and compressed data, for future use basisu::packed_uint<4> m_extended_file_size; // The file size in bytes of the "extended" header and compressed data, for future use }; diff --git a/transcoder/basisu_transcoder.cpp b/transcoder/basisu_transcoder.cpp index 0f7ca156..25a3e0c6 100644 --- a/transcoder/basisu_transcoder.cpp +++ b/transcoder/basisu_transcoder.cpp @@ -188,7 +188,7 @@ namespace basisu void debug_printf(const char* pFmt, ...) { -#if BASISU_FORCE_DEVEL_MESSAGES +#if BASISU_FORCE_DEVEL_MESSAGES g_debug_printf = true; #endif if (g_debug_printf) @@ -202,7 +202,7 @@ namespace basisu void debug_puts(const char* p) { -#if BASISU_FORCE_DEVEL_MESSAGES +#if BASISU_FORCE_DEVEL_MESSAGES g_debug_printf = true; #endif if (g_debug_printf) @@ -338,7 +338,7 @@ namespace basist float operator[] (uint32_t index) const { assert(index < 4); return c[index]; } float& operator[] (uint32_t index) { assert(index < 4); return c[index]; } }; - + enum etc_constants { cETC1BytesPerBlock = 8U, @@ -411,14 +411,14 @@ namespace basist //const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 }; - + static const uint8_t g_etc_5_to_8[32] = { 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255 }; struct decoder_etc_block { // big endian uint64: // bit ofs: 56 48 40 32 24 16 8 0 - // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 + // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 union { uint64_t m_uint64; @@ -686,7 +686,7 @@ namespace basist { return (m_bytes[3] & 2) != 0; } - + inline uint32_t get_inten_table(uint32_t subblock_id) const { assert(subblock_id < 2); @@ -701,7 +701,7 @@ namespace basist const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3); return static_cast(b | (g << 3U) | (r << 6U)); } - + void get_block_colors(color32* pBlock_colors, uint32_t subblock_index) const { color32 b; @@ -819,7 +819,7 @@ namespace basist g = c.g; b = c.b; } - + static void unpack_color5(color32& result, uint16_t packed_color5, bool scaled) { result = unpack_color5(packed_color5, scaled, 255); @@ -948,7 +948,7 @@ namespace basist static void get_block_color5_r(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t &r) { assert(index < 4); - + uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2); const int* pInten_table = g_etc1_inten_tables[inten_table]; @@ -1124,7 +1124,7 @@ namespace basist { 1, 2, 2, 2 }, { 1, 2, 3, 3 }, }; - + static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; @@ -1515,9 +1515,9 @@ namespace basist return best_err; } #endif // BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES - + static -#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES +#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES const #endif etc1_g_to_eac_conversion s_etc1_g_to_etc2_a8[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] = @@ -2006,7 +2006,7 @@ namespace basist void uastc_init(); #endif -#if BASISD_SUPPORT_UASTC_HDR +#if BASISD_SUPPORT_UASTC_HDR namespace astc_6x6_hdr { static void init_quantize_tables(); @@ -2022,18 +2022,18 @@ namespace basist #endif static bool g_transcoder_initialized; - + // Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz. // If this is too slow, these computed tables can easilky be moved to be compiled in. void basisu_transcoder_init() { if (g_transcoder_initialized) { - BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n"); + BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n"); return; } - - BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n"); + + BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n"); #if BASISD_SUPPORT_UASTC uastc_init(); @@ -2049,7 +2049,7 @@ namespace basist #if BASISD_SUPPORT_ASTC transcoder_init_astc(); #endif - + #if BASISD_WRITE_NEW_ASTC_TABLES create_etc1_to_astc_conversion_table_0_47(); create_etc1_to_astc_conversion_table_0_255(); @@ -2159,11 +2159,11 @@ namespace basist astc_6x6_hdr::init_quantize_tables(); fast_encode_bc6h_init(); #endif - + #if BASISD_SUPPORT_BC7_MODE5 bc7_mode_5_encoder::encode_bc7_mode5_init(); #endif - + g_transcoder_initialized = true; } @@ -2315,7 +2315,7 @@ namespace basist std::swap(l, h); pSelectors_xlat_256 = &g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[best_mapping][0]; } - + pDst_block->set_low_color(static_cast(l)); pDst_block->set_high_color(static_cast(h)); @@ -2475,7 +2475,7 @@ namespace basist fxt1_block* pBlock = static_cast(pDst); // CC_MIXED is basically DXT1 with different encoding tricks. - // So transcode ETC1S to DXT1, then transcode that to FXT1 which is easy and nearly lossless. + // So transcode ETC1S to DXT1, then transcode that to FXT1 which is easy and nearly lossless. // (It's not completely lossless because FXT1 rounds in its color lerps while DXT1 doesn't, but it should be good enough.) dxt1_block blk; convert_etc1s_to_dxt1(&blk, pEndpoints, pSelectors, false); @@ -2488,7 +2488,7 @@ namespace basist uint32_t g0 = color0.g & 1; uint32_t g1 = color1.g & 1; - + color0.g >>= 1; color1.g >>= 1; @@ -2496,7 +2496,7 @@ namespace basist blk.m_selectors[1] = conv_dxt1_to_fxt1_sels(blk.m_selectors[1]); blk.m_selectors[2] = conv_dxt1_to_fxt1_sels(blk.m_selectors[2]); blk.m_selectors[3] = conv_dxt1_to_fxt1_sels(blk.m_selectors[3]); - + if ((blk.get_selector(0, 0) >> 1) != (g0 ^ g1)) { std::swap(color0, color1); @@ -2510,7 +2510,7 @@ namespace basist if (fxt1_subblock == 0) { - pBlock->m_hi.m_mode = 1; + pBlock->m_hi.m_mode = 1; pBlock->m_hi.m_alpha = 0; pBlock->m_hi.m_glsb = g1 | (g1 << 1); pBlock->m_hi.m_r0 = color0.r; @@ -2831,7 +2831,7 @@ namespace basist { uint32_t r; decoder_etc_block::get_block_color5_r(base_color, inten_table, low_selector, r); - + pDst_block->set_low_alpha(r); pDst_block->set_high_alpha(r); pDst_block->m_selectors[0] = 0; @@ -2914,7 +2914,7 @@ namespace basist static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 }; static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 }; static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 }; - + static const uint8_t g_pvrtc_5_floor[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,3,3,3,3,3,3,3,3, @@ -2938,7 +2938,7 @@ namespace basist 24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28, 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31 }; - + static const uint8_t g_pvrtc_4_floor[256] = { 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, @@ -2962,7 +2962,7 @@ namespace basist 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,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 }; - + static const uint8_t g_pvrtc_3_floor[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, @@ -2986,7 +2986,7 @@ namespace basist 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 }; - + static const uint8_t g_pvrtc_alpha_floor[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, @@ -3093,10 +3093,10 @@ namespace basist } assert((r < 32) && (g < 32) && (b < 32) && (a < 16)); - + return color32(r, g, b, a); } - + inline color32 get_endpoint_8888(uint32_t endpoint_index) const { assert(endpoint_index < 2); @@ -3143,7 +3143,7 @@ namespace basist a = g_pvrtc_alpha[a]; } - + return color32(r, g, b, a); } @@ -3152,7 +3152,7 @@ namespace basist color32 c(get_endpoint_8888(endpoint_index)); return c.r + c.g + c.b + c.a; } - + inline uint32_t get_opaque_endpoint_l0() const { uint32_t packed = m_endpoints & 0xFFFE; @@ -3267,7 +3267,7 @@ namespace basist else m_endpoints = (m_endpoints & 0xFFFF0000U) | packed; } - + // opaque endpoints: 554 or 555 // transparent endpoints: 3443 or 3444 inline void set_endpoint_raw(uint32_t endpoint_index, const color32& c, bool opaque_endpoint) @@ -3320,7 +3320,7 @@ namespace basist else m_endpoints = (m_endpoints & 0xFFFF0000U) | packed; } - + inline void set_endpoint_floor(uint32_t endpoint_index, const color32& c) { assert(endpoint_index < 2); @@ -3545,7 +3545,7 @@ namespace basist for (int ey = 0; ey < 3; ey++) { - int by = y + ey - 1; + int by = y + ey - 1; const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x]; @@ -3553,7 +3553,7 @@ namespace basist for (int ex = 0; ex < 3; ex++) { - int bx = 0 + ex - 1; + int bx = 0 + ex - 1; const uint32_t e = pE[bx & x_mask]; @@ -3702,8 +3702,8 @@ namespace basist } static void fixup_pvrtc1_4_modulation_rgba( - const decoder_etc_block* pETC_Blocks, - const uint32_t* pPVRTC_endpoints, + const decoder_etc_block* pETC_Blocks, + const uint32_t* pPVRTC_endpoints, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, void *pAlpha_blocks, const endpoint* pEndpoints, const selector* pSelectors) { @@ -3726,7 +3726,7 @@ namespace basist for (int ey = 0; ey < 3; ey++) { - int by = y + ey - 1; + int by = y + ey - 1; const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x]; @@ -3734,7 +3734,7 @@ namespace basist for (int ex = 0; ex < 3; ex++) { - int bx = 0 + ex - 1; + int bx = 0 + ex - 1; const uint32_t e = pE[bx & x_mask]; @@ -3748,13 +3748,13 @@ namespace basist for (int x = 0; x < static_cast(num_blocks_x); x++, block_index++) { const decoder_etc_block& src_block = pETC_Blocks[block_index]; - + const uint16_t* pSrc_alpha_block = reinterpret_cast(static_cast(pAlpha_blocks) + x + (y * num_blocks_x)); const endpoint* pAlpha_endpoints = &pEndpoints[pSrc_alpha_block[0]]; const selector* pAlpha_selectors = &pSelectors[pSrc_alpha_block[1]]; - + const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1); - + uint32_t swizzled = x_swizzle | y_swizzle; if (num_blocks_x != num_blocks_y) { @@ -3897,7 +3897,7 @@ namespace basist const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES = sizeof(g_etc1_to_bc7_m5_selector_ranges) / sizeof(g_etc1_to_bc7_m5_selector_ranges[0]); static uint32_t g_etc1_to_bc7_m5_selector_range_index[4][4]; - + const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS = 10; static const uint8_t g_etc1_to_bc7_m5_selector_mappings[NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS][4] = { @@ -3919,11 +3919,11 @@ namespace basist uint8_t m_hi; uint16_t m_err; }; - + static const etc1_to_bc7_m5_solution g_etc1_to_bc7_m5_color[32 * 8 * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS * NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES] = { #include "basisu_transcoder_tables_bc7_m5_color.inc" }; - + static dxt_selector_range g_etc1_to_bc7_m5a_selector_ranges[] = { { 0, 3 }, @@ -3948,7 +3948,7 @@ namespace basist { #include "basisu_transcoder_tables_bc7_m5_alpha.inc" }; - + static inline uint32_t set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t cur_ofs) { assert(num_bits < 32); @@ -4095,7 +4095,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1_to_bc7_m5_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -4174,7 +4174,7 @@ namespace basist int mapping_err = block_colors[s].g - colors[k]; mapping_err *= mapping_err; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) mapping_err *= 5; @@ -4185,7 +4185,7 @@ namespace basist best_k = k; } } // k - + total_err += best_mapping_err; output_selectors |= (best_k << (s * 2)); } // s @@ -4200,7 +4200,7 @@ namespace basist } // lo } // hi - + fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, best_output_selectors); n++; if ((n & 31) == 31) @@ -4239,7 +4239,7 @@ namespace basist {127,104},{126,105},{126,106},{127,106},{127,107},{126,108},{125,109},{127,109},{126,110},{126,111},{127,111},{127,112},{126,113},{126,114},{127,114},{127,115}, {126,116},{126,117},{127,117},{127,118},{126,119},{126,120},{127,120},{127,121},{126,122},{126,123},{127,123},{127,124},{126,125},{126,126},{127,126},{127,127} }; - + static void transcoder_init_bc7_mode5() { #if 0 @@ -4267,9 +4267,9 @@ namespace basist } } // hi - + } // lo - + printf("{%u,%u},", g_bc7_m5_equals_1[i].m_hi, g_bc7_m5_equals_1[i].m_lo); if ((i & 15) == 15) printf("\n"); } @@ -4293,7 +4293,7 @@ namespace basist static void convert_etc1s_to_bc7_m5_color(void* pDst, const endpoint* pEndpoints, const selector* pSelector) { bc7_mode_5* pDst_block = static_cast(pDst); - + // First ensure the block is cleared to all 0's static_cast(pDst)[0] = 0; static_cast(pDst)[1] = 0; @@ -4419,7 +4419,7 @@ namespace basist pDst_block->m_lo.m_r1 = pTable_r[best_mapping].m_lo; pDst_block->m_lo.m_g1 = pTable_g[best_mapping].m_lo; pDst_block->m_lo.m_b1 = pTable_b[best_mapping].m_lo; - + s_inv = 3; } else @@ -4440,7 +4440,7 @@ namespace basist for (uint32_t x = 0; x < 4; x++) { const uint32_t s = pSelector->get_selector(x, y); - + const uint32_t os = pSelectors_xlat[s] ^ s_inv; output_bits |= (os << output_bit_ofs); @@ -4470,7 +4470,7 @@ namespace basist pDst_block->m_lo.m_a0 = r; pDst_block->m_lo.m_a1_0 = r & 63; pDst_block->m_hi.m_a1_1 = r >> 6; - + return; } else if (pSelector->m_num_unique_selectors == 2) @@ -4520,7 +4520,7 @@ namespace basist } const uint32_t selector_range_table = g_etc1_to_bc7_m5a_selector_range_index[low_selector][high_selector]; - + const etc1_g_to_bc7_m5a_conversion* pTable = &g_etc1_g_to_bc7_m5a[inten_table * (32 * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES) + base_color_r * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES + selector_range_table]; pDst_block->m_lo.m_a0 = pTable->m_lo; @@ -4620,7 +4620,7 @@ namespace basist const bool hq_bc7_mode_5_encoder_mode = false; const int CHROMA_THRESH = 10; - + uint32_t total_filtered_blocks = 0; for (int by = 0; by < (int)num_blocks_y; by++) @@ -4628,7 +4628,7 @@ namespace basist for (int bx = 0; bx < (int)num_blocks_x; bx++) { vec2F center_cocg(color5_to_cocg(pEndpoints[decoded_endpoints(bx, by)])); - + //bool filter_flag = false; for (int dy = -1; dy <= 1; dy++) { @@ -4666,7 +4666,7 @@ namespace basist total_filtered_blocks++; bc7_mode_5* pDst_block = (bc7_mode_5*)(static_cast(pDst_blocks) + (bx + by * output_row_pitch_in_blocks_or_pixels) * sizeof(bc7_mode_5)); - + //memset(pDst_block, 0x80, 16); int lr = bc7_7_to_8(pDst_block->m_lo.m_r0); @@ -4690,7 +4690,7 @@ namespace basist float block_y_vals[16]; // [y][x] float y_sum = 0.0f, y_sum_sq = 0.0f; - + for (uint32_t i = 0; i < 16; i++) { uint32_t sel = sel_bits & (i ? 3 : 1); @@ -4699,7 +4699,7 @@ namespace basist block_y_vals[i] = y; y_sum += y; y_sum_sq += y * y; - + } // i const float S = 1.0f / 16.0f; @@ -4722,14 +4722,14 @@ namespace basist const float fy = ((float)((bpy + 2) & 3) + .5f) * (1.0f / 4.0f); const int ubx = bx + ((bpx - 2) >> 2); - + vec2F a(get_endpoint_cocg_clamped(ubx, uby, decoded_endpoints, pEndpoints)); vec2F b(get_endpoint_cocg_clamped(ubx + 1, uby, decoded_endpoints, pEndpoints)); vec2F c(get_endpoint_cocg_clamped(ubx, uby + 1, decoded_endpoints, pEndpoints)); vec2F d(get_endpoint_cocg_clamped(ubx + 1, uby + 1, decoded_endpoints, pEndpoints)); assert((fx >= 0) && (fx <= 1.0f) && (fy >= 0) && (fy <= 1.0f)); - + // TODO: Could merge this into 4 muls on each corner by weights vec2F ab = vec2F::lerp(a, b, fx); vec2F cd = vec2F::lerp(c, d, fx); @@ -4746,7 +4746,7 @@ namespace basist } // y bc7_mode_5_encoder::encode_bc7_mode_5_block(pDst_block, block_to_pack, hq_bc7_mode_5_encoder_mode); - + } // bx } // by @@ -5182,7 +5182,7 @@ namespace basist // The best selector mapping to use given a base base+inten table and used selector range for converting grayscale data. static uint8_t g_etc1_to_astc_best_grayscale_mapping[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES]; - + #if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY static const etc1_to_astc_solution g_etc1_to_astc_0_255[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] = { #include "basisu_transcoder_tables_astc_0_255.inc" @@ -5247,7 +5247,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 8; @@ -5268,7 +5268,7 @@ namespace basist mapping_best_high[m] = best_hi; mapping_best_err[m] = best_err; highest_best_err = basisu::maximum(highest_best_err, best_err); - + } // m for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++) @@ -5344,7 +5344,7 @@ namespace basist { int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]]; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. int err_scale = 1; if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) @@ -5373,9 +5373,9 @@ namespace basist uint64_t err = mapping_best_err[m]; err = basisu::minimum(err, 0xFFFF); - + fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err); - + n++; if ((n & 31) == 31) fprintf(pFile, "\n"); @@ -5458,14 +5458,14 @@ namespace basist struct astc_block_params { // 2 groups of 5, but only a max of 8 are used (RRGGBBAA00) - uint8_t m_endpoints[10]; + uint8_t m_endpoints[10]; uint8_t m_weights[32]; }; - - // Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2). + + // Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2). // We're always going to output blocks containing alpha, even if the input doesn't have alpha, for simplicity. // Each block always has 4x4 weights, uses range 13 BISE encoding on the endpoints (0-47), and each weight ranges from 0-3. This encoding should be roughly equal in quality vs. BC1 for color. - // 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47. + // 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47. // Note the input [0,47] endpoint values are not linear - they are encoded as outlined in the ASTC spec: // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-endpoint-unquantization // 32 total weights, stored as 16 CA CA, each ranging from 0-3. @@ -5487,7 +5487,7 @@ namespace basist astc_encode_trits(pOutput, pBlock->m_endpoints + 5, bit_pos, 4); // Pack 32 2-bit weights, which are stored from the top down into the block in opposite bit order. - + for (uint32_t i = 0; i < 32; i++) { static const uint8_t s_reverse_bits[4] = { 0, 2, 1, 3 }; @@ -5496,7 +5496,7 @@ namespace basist } } - // CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights + // CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights // This ASTC mode is basically block truncation coding (BTC) using 1-bit weights and 8-bit/component endpoints - very convenient. static void astc_pack_block_cem_12_weight_range0(uint32_t* pOutput, const astc_block_params* pBlock) { @@ -5534,7 +5534,7 @@ namespace basist // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode pBytes[0] = 0x42; pBytes[1] = 0x84; pBytes[2] = 0x00; pBytes[3] = 0x00; pBytes[4] = 0x00; pBytes[5] = 0x00; pBytes[6] = 0x00; pBytes[7] = 0xc0; - + pOutput[2] = 0; pOutput[3] = 0; @@ -5560,7 +5560,7 @@ namespace basist // Write constant block mode, color component selector, number of partitions, color endpoint mode // https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode pBytes[0] = 0x42; pBytes[1] = 0x00; pBytes[2] = 0x01; pBytes[3] = 0x00; - + pOutput[1] = 0; pOutput[2] = 0; pOutput[3] = 0; @@ -5588,7 +5588,7 @@ namespace basist { uint8_t m_lo, m_hi; } g_astc_single_color_encoding_1[256]; - + static void transcoder_init_astc() { for (uint32_t base_color = 0; base_color < 32; base_color++) @@ -5666,7 +5666,7 @@ namespace basist g_ise_to_unquant[bit | (trit << 4)] = unq; } } - + // Compute table used for optimal single color encoding. for (int i = 0; i < 256; i++) { @@ -5681,9 +5681,9 @@ namespace basist int l = lo_v | (lo_v << 8); int h = hi_v | (hi_v << 8); - + int v = ((l * (64 - 21) + (h * 21) + 32) / 64) >> 8; - + int e = abs(v - i); if (e < lowest_e) @@ -5705,7 +5705,7 @@ namespace basist for (int lo = 0; lo < 48; lo++) { const int lo_v = g_ise_to_unquant[lo]; - + int e = abs(lo_v - i); if (e < lowest_e) @@ -5720,7 +5720,7 @@ namespace basist // Converts opaque or color+alpha ETC1S block to ASTC 4x4. // This function tries to use the best ASTC mode given the block's actual contents. - static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector, + static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector, bool transcode_alpha, const endpoint *pEndpoint_codebook, const selector *pSelector_codebook) { astc_block_params blk; @@ -5764,7 +5764,7 @@ namespace basist // See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-void-extent-blocks uint32_t r, g, b; decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b); - + uint32_t* pOutput = static_cast(pDst_block); uint8_t* pBytes = reinterpret_cast(pDst_block); @@ -5784,7 +5784,7 @@ namespace basist } else if ((pSelector->m_num_unique_selectors <= 2) && (num_unique_alpha_selectors <= 2)) { - // Both color and alpha use <= 2 unique selectors each. + // Both color and alpha use <= 2 unique selectors each. // Use block truncation coding, which is lossless with ASTC (8-bit endpoints, 1-bit weights). color32 block_colors[4]; decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table); @@ -5831,7 +5831,7 @@ namespace basist { uint32_t s = alpha_selectors.get_selector(x, y); s = (s == alpha_high_selector) ? 1 : 0; - + blk.m_weights[(x + y * 4) * 2 + 1] = static_cast(s); } // x } // y @@ -5864,12 +5864,12 @@ namespace basist return; } - + // Either alpha and/or color use > 2 unique selectors each, so we must do something more complex. - + #if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY // The optional higher quality modes use 8-bits endpoints vs. [0,47] endpoints. - + // If the block's base color is grayscale, all pixels are grayscale, so encode the block as Luminance+Alpha. if ((base_color.r == base_color.g) && (base_color.r == base_color.b)) { @@ -5903,7 +5903,7 @@ namespace basist { // Convert ETC1S alpha const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; @@ -5911,7 +5911,7 @@ namespace basist blk.m_endpoints[2] = pTable_g[best_mapping].m_lo; blk.m_endpoints[3] = pTable_g[best_mapping].m_hi; - + const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0]; for (uint32_t y = 0; y < 4; y++) @@ -5955,10 +5955,10 @@ namespace basist { // Convert ETC1S alpha const uint32_t selector_range_table = g_etc1_to_astc_selector_range_index[low_selector][high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; - + const uint32_t best_mapping = g_etc1_to_astc_best_grayscale_mapping_0_255[base_color.g][inten_table][selector_range_table]; blk.m_endpoints[0] = pTable_g[best_mapping].m_lo; @@ -6100,7 +6100,7 @@ namespace basist { // Convert ETC1S alpha const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector]; - + //[32][8][RANGES][MAPPING] const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS]; @@ -6144,7 +6144,7 @@ namespace basist const uint32_t r = block_colors[low_selector].r; const uint32_t g = block_colors[low_selector].g; const uint32_t b = block_colors[low_selector].b; - + blk.m_endpoints[0] = g_astc_single_color_encoding_1[r].m_lo; blk.m_endpoints[1] = g_astc_single_color_encoding_1[r].m_hi; @@ -6246,7 +6246,7 @@ namespace basist blk.m_endpoints[4] = pTable_b[best_mapping].m_lo; blk.m_endpoints[5] = pTable_b[best_mapping].m_hi; - + int s0 = g_ise_to_unquant[blk.m_endpoints[0]] + g_ise_to_unquant[blk.m_endpoints[2]] + g_ise_to_unquant[blk.m_endpoints[4]]; int s1 = g_ise_to_unquant[blk.m_endpoints[1]] + g_ise_to_unquant[blk.m_endpoints[3]] + g_ise_to_unquant[blk.m_endpoints[5]]; bool invert = false; @@ -6411,8 +6411,8 @@ namespace basist static void transcoder_init_atc() { prepare_atc_single_color_table(g_pvrtc2_match45_equals_1, 16, 32, 1); - prepare_atc_single_color_table(g_atc_match55_equals_1, 32, 32, 1); - prepare_atc_single_color_table(g_atc_match56_equals_1, 32, 64, 1); + prepare_atc_single_color_table(g_atc_match55_equals_1, 32, 32, 1); + prepare_atc_single_color_table(g_atc_match56_equals_1, 32, 64, 1); prepare_atc_single_color_table(g_pvrtc2_match4, 1, 16, 3); prepare_atc_single_color_table(g_atc_match5, 1, 32, 3); @@ -6466,7 +6466,7 @@ namespace basist pBlock->set_low_color(g_atc_match55_equals_1[r].m_lo, g_atc_match56_equals_1[g].m_lo, g_atc_match55_equals_1[b].m_lo); pBlock->set_high_color(g_atc_match55_equals_1[r].m_hi, g_atc_match56_equals_1[g].m_hi, g_atc_match55_equals_1[b].m_hi); - + pBlock->m_sels[0] = 0x55; pBlock->m_sels[1] = 0x55; pBlock->m_sels[2] = 0x55; @@ -6601,7 +6601,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -6675,7 +6675,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -6705,7 +6705,7 @@ namespace basist } // inten fclose(pFile); - + // PVRTC2 45 fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_45.inc", "w"); @@ -6750,7 +6750,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -6827,7 +6827,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -6904,7 +6904,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -6981,7 +6981,7 @@ namespace basist int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]]; int err_scale = 1; - // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor + // Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor // the low/high selectors which are clamping to either 0 or 255. if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3))) err_scale = 5; @@ -7109,12 +7109,12 @@ namespace basist { uint8_t m_l, m_h; } g_pvrtc2_trans_match44[256]; - + static struct { uint8_t m_l, m_h; } g_pvrtc2_alpha_match33[256]; - + static struct { uint8_t m_l, m_h; @@ -7124,7 +7124,7 @@ namespace basist { uint8_t m_l, m_h; } g_pvrtc2_alpha_match33_3[256]; - + // PVRTC2 can be forced to look like a slightly weaker variant of ATC/BC1, so that's what we do here for simplicity. static void convert_etc1s_to_pvrtc2_rgb(void* pDst, const endpoint* pEndpoints, const selector* pSelector) { @@ -7236,7 +7236,7 @@ namespace basist pBlock->m_modulation[3] = (uint8_t)sels3; } } - + static inline vec4F* vec4F_set_scalar(vec4F* pV, float x) { pV->c[0] = x; pV->c[1] = x; pV->c[2] = x; pV->c[3] = x; return pV; } static inline vec4F* vec4F_set(vec4F* pV, float x, float y, float z, float w) { pV->c[0] = x; pV->c[1] = y; pV->c[2] = z; pV->c[3] = w; return pV; } static inline vec4F* vec4F_saturate_in_place(vec4F* pV) { pV->c[0] = saturate(pV->c[0]); pV->c[1] = saturate(pV->c[1]); pV->c[2] = saturate(pV->c[2]); pV->c[3] = saturate(pV->c[3]); return pV; } @@ -7254,9 +7254,9 @@ namespace basist } static inline int sq(int x) { return x * x; } - - // PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is expanded from 4 to 8 bits means it can never be 0. - // This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha! + + // PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is expanded from 4 to 8 bits means it can never be 0. + // This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha! // And there's nothing straightforward we can do because using the other modes is too expensive/complex. I can see why Apple didn't adopt it. static void convert_etc1s_to_pvrtc2_rgba(void* pDst, const endpoint* pEndpoints, const selector* pSelector, const endpoint* pEndpoint_codebook, const selector* pSelector_codebook) { @@ -7311,13 +7311,13 @@ namespace basist const uint32_t high_selector = pSelector->m_hi_selector; const int num_unique_color_selectors = pSelector->m_num_unique_selectors; - + // We need to reencode the block at the pixel level, unfortunately, from two ETC1S planes. // Do 4D incremental PCA, project all pixels to this hyperline, then quantize to packed endpoints and compute the modulation values. const int br = (base_color.r << 3) | (base_color.r >> 2); const int bg = (base_color.g << 3) | (base_color.g >> 2); const int bb = (base_color.b << 3) | (base_color.b >> 2); - + color32 block_cols[4]; for (uint32_t i = 0; i < 4; i++) { @@ -7346,14 +7346,14 @@ namespace basist decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b); // Mod 0 - uint32_t lr0 = (r * 15 + 128) / 255, lg0 = (g * 15 + 128) / 255, lb0 = (b * 7 + 128) / 255; + uint32_t lr0 = (r * 15 + 128) / 255, lg0 = (g * 15 + 128) / 255, lb0 = (b * 7 + 128) / 255; uint32_t la0 = g_pvrtc2_alpha_match33_0[constant_alpha_val].m_l; uint32_t cr0 = (lr0 << 1) | (lr0 >> 3); uint32_t cg0 = (lg0 << 1) | (lg0 >> 3); uint32_t cb0 = (lb0 << 2) | (lb0 >> 1); uint32_t ca0 = (la0 << 1); - + cr0 = (cr0 << 3) | (cr0 >> 2); cg0 = (cg0 << 3) | (cg0 >> 2); cb0 = (cb0 << 3) | (cb0 >> 2); @@ -7382,14 +7382,14 @@ namespace basist uint32_t cg3 = (lg3 << 1) | (lg3 >> 3); uint32_t cb3 = (lb3 << 1) | (lb3 >> 3); uint32_t ca3 = (la3 << 1) | 1; - + cr3 = (cr3 << 3) | (cr3 >> 2); cg3 = (cg3 << 3) | (cg3 >> 2); cb3 = (cb3 << 3) | (cb3 >> 2); ca3 = (ca3 << 4) | ca3; uint32_t err3 = sq(cr3 - r) + sq(cg3 - g) + sq(cb3 - b) + sq(ca3 - constant_alpha_val) * 2; - + // Mod 1 uint32_t lr1 = g_pvrtc2_trans_match44[r].m_l, lg1 = g_pvrtc2_trans_match44[g].m_l, lb1 = g_pvrtc2_trans_match34[b].m_l; uint32_t hr1 = g_pvrtc2_trans_match44[r].m_h, hg1 = g_pvrtc2_trans_match44[g].m_h, hb1 = g_pvrtc2_trans_match34[b].m_h; @@ -7464,7 +7464,7 @@ namespace basist // It's a solid color block. uint32_t low_a = block_cols[alpha_selectors.m_lo_selector].a; uint32_t high_a = block_cols[alpha_selectors.m_hi_selector].a; - + const float S = 1.0f / 255.0f; vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, low_a * S); vec4F_set(&maxColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, high_a * S); @@ -7476,7 +7476,7 @@ namespace basist vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, constant_alpha_val * S); vec4F_set(&maxColor, block_cols[high_selector].r * S, block_cols[high_selector].g * S, block_cols[high_selector].b * S, constant_alpha_val * S); } - // See if any of the block colors got clamped - if so the principle axis got distorted (it's no longer just the ETC1S luma axis). + // See if any of the block colors got clamped - if so the principle axis got distorted (it's no longer just the ETC1S luma axis). // To keep quality up we need to use full 4D PCA in this case. else if ((block_cols[low_selector].c[0] == 0) || (block_cols[high_selector].c[0] == 255) || (block_cols[low_selector].c[1] == 0) || (block_cols[high_selector].c[1] == 255) || @@ -7527,7 +7527,7 @@ namespace basist } vec4F_normalize_in_place(&axis); - + if (vec4F_dot(&axis, &axis) < .5f) vec4F_set_scalar(&axis, .5f); @@ -7627,10 +7627,10 @@ namespace basist // 4433 4443 color32 trialMinColor, trialMaxColor; - + trialMinColor.set_clamped((int)(minColor.c[0] * 15.0f + .5f), (int)(minColor.c[1] * 15.0f + .5f), (int)(minColor.c[2] * 7.0f + .5f), (int)(minColor.c[3] * 7.0f + .5f)); trialMaxColor.set_clamped((int)(maxColor.c[0] * 15.0f + .5f), (int)(maxColor.c[1] * 15.0f + .5f), (int)(maxColor.c[2] * 15.0f + .5f), (int)(maxColor.c[3] * 7.0f + .5f)); - + pBlock->set_trans_low_color(trialMinColor.r, trialMinColor.g, trialMinColor.b, trialMinColor.a); pBlock->set_trans_high_color(trialMaxColor.r, trialMaxColor.g, trialMaxColor.b, trialMaxColor.a); @@ -7703,7 +7703,7 @@ namespace basist } } } - + static void transcoder_init_pvrtc2() { for (uint32_t v = 0; v < 256; v++) @@ -7809,7 +7809,7 @@ namespace basist g_pvrtc2_trans_match34[v].m_l = (uint8_t)best_l; g_pvrtc2_trans_match34[v].m_h = (uint8_t)best_h; } - + for (uint32_t v = 0; v < 256; v++) { int best_l = 0, best_h = 0, lowest_err = INT_MAX; @@ -7843,12 +7843,12 @@ namespace basist #endif // BASISD_SUPPORT_PVRTC2 //------------------------------------------------------------------------------------------------ - + // BC7 mode 5 RGB encoder #if BASISD_SUPPORT_BC7_MODE5 namespace bc7_mode_5_encoder - { + { static float g_mode5_rgba_midpoints[128]; void encode_bc7_mode5_init() @@ -8123,10 +8123,10 @@ namespace basist } int block_max_var = basisu::maximum(icov[0], icov[3], icov[5]); // not divided by 16, i.e. scaled by 16 - + // TODO: Tune this const int32_t SIMPLE_BLOCK_THRESH = 10 * 16; - + if ((!hq_mode) && (block_max_var < SIMPLE_BLOCK_THRESH)) { const int L = 16, H = 239; @@ -8167,7 +8167,7 @@ namespace basist saxis_g = (int)(alt_xg * m); saxis_b = (int)(alt_xb * m); } - + saxis_r = (int)((uint32_t)saxis_r << 4U); saxis_g = (int)((uint32_t)saxis_g << 4U); saxis_b = (int)((uint32_t)saxis_b << 4U); @@ -8319,7 +8319,7 @@ namespace basist sym_codec.stop(); m_local_selectors.resize(num_selectors); - + if (!sym_codec.init(pSelectors_data, selectors_data_size)) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 5\n"); @@ -8344,7 +8344,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: hybrid global selector codebooks are unsupported\n"); return false; } - + const bool used_raw_encoding = (sym_codec.get_bits(1) == 1); if (used_raw_encoding) @@ -8525,7 +8525,7 @@ namespace basist if (!output_rows_in_pixels) output_rows_in_pixels = orig_height; } - + basisu::vector* pPrev_frame_indices = nullptr; if (is_video) { @@ -8553,12 +8553,12 @@ namespace basist } approx_move_to_front selector_history_buf(m_selector_history_buf_size); - + uint32_t cur_selector_rle_count = 0; decoder_etc_block block; memset(&block, 0, sizeof(block)); - + //block.set_flip_bit(true); // Setting the flip bit to false to be compatible with the Khronos KDFS. block.set_flip_bit(false); @@ -8594,7 +8594,7 @@ namespace basist if (!endpoints.size() || !selectors.size()) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: global codebooks must be unpacked first\n"); - + if (pPVRTC_work_mem) free(pPVRTC_work_mem); @@ -8605,7 +8605,7 @@ namespace basist const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = m_selector_history_buf_size + SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX; #if BASISD_SUPPORT_BC7_MODE5 - const bool bc7_chroma_filtering = ((decode_flags & cDecodeFlagsNoETC1SChromaFiltering) == 0) && + const bool bc7_chroma_filtering = ((decode_flags & cDecodeFlagsNoETC1SChromaFiltering) == 0) && ((fmt == block_format::cBC7_M5_COLOR) || (fmt == block_format::cBC7)); basisu::vector2D decoded_endpoints; @@ -8830,7 +8830,7 @@ namespace basist case block_format::cETC1: { decoder_etc_block* pDst_block = reinterpret_cast(static_cast(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes); - + block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false)); block.set_inten_table(0, pEndpoints->m_inten5); block.set_inten_table(1, pEndpoints->m_inten5); @@ -8881,7 +8881,7 @@ namespace basist const uint32_t low_selector = pSelector->m_lo_selector; const uint32_t high_selector = pSelector->m_hi_selector; - // Get block's RGB bounding box + // Get block's RGB bounding box color32 block_colors[2]; decoder_etc_block::get_block_colors5_bounds(block_colors, base_color, inten_table, low_selector, high_selector); @@ -8897,7 +8897,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -8905,7 +8905,7 @@ namespace basist { #if BASISD_SUPPORT_PVRTC1 assert(pAlpha_blocks); - + block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false)); block.set_inten_table(0, pEndpoints->m_inten5); block.set_inten_table(1, pEndpoints->m_inten5); @@ -8913,7 +8913,7 @@ namespace basist ((decoder_etc_block*)pPVRTC_work_mem)[block_x + block_y * num_blocks_x] = block; - // Get block's RGBA bounding box + // Get block's RGBA bounding box const color32& base_color = pEndpoints->m_color5; const uint32_t inten_table = pEndpoints->m_inten5; const uint32_t low_selector = pSelector->m_lo_selector; @@ -8948,7 +8948,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -9038,7 +9038,7 @@ namespace basist assert(transcode_alpha); void* pDst_block = static_cast(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes; - + convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &endpoints[0], &selectors[0]); #endif break; @@ -9054,10 +9054,10 @@ namespace basist { assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes); uint8_t* pDst_pixels = static_cast(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t); - + const uint32_t max_x = basisu::minimum(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4); const uint32_t max_y = basisu::minimum(4, (int)output_rows_in_pixels - (int)block_y * 4); - + int colors[4]; decoder_etc_block::get_block_colors5_g(colors, pEndpoints->m_color5, pEndpoints->m_inten5); @@ -9071,7 +9071,7 @@ namespace basist pDst_pixels[3+4] = static_cast(colors[(s >> 2) & 3]); pDst_pixels[3+8] = static_cast(colors[(s >> 4) & 3]); pDst_pixels[3+12] = static_cast(colors[(s >> 6) & 3]); - + pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t); } } @@ -9100,7 +9100,7 @@ namespace basist color32 colors[4]; decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5); - + for (uint32_t y = 0; y < max_y; y++) { const uint32_t s = pSelector->m_selectors[y]; @@ -9221,7 +9221,7 @@ namespace basist cur = byteswap_uint16(cur); cur = (cur & 0xF) | packed_colors[(s >> (x * 2)) & 3]; - + if (BASISD_IS_BIG_ENDIAN) cur = byteswap_uint16(cur); @@ -9321,7 +9321,7 @@ namespace basist if (endpoint_pred_repeat_count != 0) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: endpoint_pred_repeat_count != 0. The file is corrupted or this is a bug\n"); - + if (pPVRTC_work_mem) free(pPVRTC_work_mem); @@ -9367,7 +9367,7 @@ namespace basist if (!output_row_pitch_in_blocks_or_pixels) output_row_pitch_in_blocks_or_pixels = orig_width; - if (!output_rows_in_pixels) + if (!output_rows_in_pixels) output_rows_in_pixels = orig_height; // Now make sure the output buffer is large enough, or we'll overwrite memory. @@ -9401,7 +9401,7 @@ namespace basist return true; } - + uint32_t basis_compute_transcoded_image_size_in_bytes(transcoder_texture_format target_format, uint32_t orig_width, uint32_t orig_height) { assert(orig_width && orig_height); @@ -9417,7 +9417,7 @@ namespace basist const uint32_t bytes_per_slice = bytes_per_line * orig_height; return bytes_per_slice; } - + // Compressed formats are 2D arrays of blocks. const uint32_t bytes_per_block = basis_get_bytes_per_block_or_pixel(target_format); @@ -9488,11 +9488,11 @@ namespace basist // Switch to PVRTC1 RGB if the input doesn't have alpha. target_format = transcoder_texture_format::cTFPVRTC1_4_RGB; } - + const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0; const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format); const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y; - + if (!basis_validate_output_buffer_size(basis_tex_format::cETC1S, target_format, output_blocks_buf_size_in_blocks_or_pixels, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, output_rows_in_pixels)) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output buffer size too small\n"); @@ -9519,7 +9519,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels, decode_flags); - + if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC1 failed\n"); @@ -9644,7 +9644,7 @@ namespace basist if (basis_file_has_alpha_slices) { - // First decode the alpha data + // First decode the alpha data //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_A8, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels, decode_flags); } @@ -9682,8 +9682,8 @@ namespace basist return false; #else assert(bytes_per_block_or_pixel == 16); - - // First decode the alpha data + + // First decode the alpha data if (basis_file_has_alpha_slices) { //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); @@ -9812,7 +9812,7 @@ namespace basist #else assert(bytes_per_block_or_pixel == 16); - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) { //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); @@ -9872,7 +9872,7 @@ namespace basist } else { - // Now decode the color data and transcode to PVRTC2 RGBA. + // Now decode the color data and transcode to PVRTC2 RGBA. //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels, decode_flags); } @@ -9893,7 +9893,7 @@ namespace basist { // Raw 32bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory. - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cA32, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels, decode_flags); @@ -9934,7 +9934,7 @@ namespace basist { // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory. - // First decode the alpha data + // First decode the alpha data if (basis_file_has_alpha_slices) //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels, decode_flags); @@ -10038,14 +10038,14 @@ namespace basist } //------------------------------------------------------------------------------------------------ - + basisu_lowlevel_uastc_ldr_4x4_transcoder::basisu_lowlevel_uastc_ldr_4x4_transcoder() { } bool basisu_lowlevel_uastc_ldr_4x4_transcoder::transcode_slice( void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt, - uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, + uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, uint32_t output_rows_in_pixels, int channel0, int channel1, uint32_t decode_flags) { @@ -10106,7 +10106,7 @@ namespace basist for (uint32_t block_y = 0; block_y < num_blocks_y; ++block_y) { void* pDst_block = (uint8_t*)pDst_blocks + block_y * output_row_pitch_in_blocks_or_pixels * output_block_or_pixel_stride_in_bytes; - + for (uint32_t block_x = 0; block_x < num_blocks_x; ++block_x, ++pSource_block, pDst_block = (uint8_t *)pDst_block + output_block_or_pixel_stride_in_bytes) { switch (fmt) @@ -10142,7 +10142,7 @@ namespace basist } case block_format::cBC4: { - if (channel0 < 0) + if (channel0 < 0) channel0 = 0; status = transcode_uastc_to_bc4(*pSource_block, pDst_block, high_quality, channel0); break; @@ -10305,7 +10305,7 @@ namespace basist return false; #endif } - + bool basisu_lowlevel_uastc_ldr_4x4_transcoder::transcode_image( transcoder_texture_format target_format, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, @@ -10327,7 +10327,7 @@ namespace basist { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_ldr_4x4_transcoder::transcode_image: source data buffer too small\n"); return false; - } + } if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA)) { @@ -10354,7 +10354,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_ldr_4x4_transcoder::transcode_image: output buffer size too small\n"); return false; } - + bool status = false; // UASTC4x4 @@ -10365,7 +10365,7 @@ namespace basist //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC1, bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1, decode_flags); - + if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_ldr_4x4_transcoder::transcode_image: transcode_slice() to ETC1 failed\n"); @@ -10592,7 +10592,7 @@ namespace basist bool basisu_lowlevel_uastc_hdr_4x4_transcoder::transcode_slice( void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt, - uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, + uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, uint32_t output_rows_in_pixels, int channel0, int channel1, uint32_t decode_flags) { @@ -10641,7 +10641,7 @@ namespace basist bool status = false; // TODO: Optimize pure memcpy() case. - + for (uint32_t block_y = 0; block_y < num_blocks_y; ++block_y) { void* pDst_block = (uint8_t*)pDst_blocks + block_y * output_row_pitch_in_blocks_or_pixels * output_block_or_pixel_stride_in_bytes; @@ -10676,7 +10676,7 @@ namespace basist uint32_t blk_texels[4][4]; status = astc_helpers::decode_block(log_blk, blk_texels, 4, 4, astc_helpers::cDecodeModeRGB9E5); - + if (status) { const uint32_t max_x = basisu::minimum(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4); @@ -10690,7 +10690,7 @@ namespace basist } // y } } - + break; } case block_format::cRGBA_HALF: @@ -10702,7 +10702,7 @@ namespace basist half_float* pDst_pixels = reinterpret_cast( static_cast(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(half_float) * 4 ); - + half_float blk_texels[4][4][4]; status = astc_helpers::decode_block(log_blk, blk_texels, 4, 4, astc_helpers::cDecodeModeHDR16); @@ -10768,7 +10768,7 @@ namespace basist if (!status) { - BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_hdr_4x4_transcoder::transcode_slice: Transcoder failed to unpack a UASTC HDR block - this is a bug, or the data was corrupted\n"); + BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_hdr_4x4_transcoder::transcode_slice: Transcoder failed to unpack a UASTC HDR block - this is a bug, or the data was corrupted\n"); return false; } @@ -10961,7 +10961,7 @@ namespace basist assert(((orig_width + 5) / 6) == num_blocks_x); assert(((orig_height + 5) / 6) == num_blocks_y); - + if (fmt == block_format::cBC6H) { const uint32_t num_dst_blocks_x = (orig_width + 3) / 4; @@ -10986,7 +10986,7 @@ namespace basist fast_bc6h_params bc6h_enc_params; const bool hq_flag = (decode_flags & cDecodeFlagsHighQuality) != 0; bc6h_enc_params.m_max_2subset_pats_to_try = hq_flag ? 1 : 0; - + for (uint32_t src_block_y = 0; src_block_y < num_blocks_y; src_block_y += 2) { const uint32_t num_inner_blocks_y = basisu::minimum(2, num_blocks_y - src_block_y); @@ -11002,7 +11002,7 @@ namespace basist const astc_blk* pS = pSource_block + (src_block_y + iy) * num_blocks_x + (src_block_x + ix); half_float blk_texels[6][6][4]; - + astc_helpers::log_astc_block log_blk; status = astc_helpers::unpack_block(pS, log_blk, 6, 6); if (!status) @@ -11010,7 +11010,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_astc_hdr_6x6_transcoder::transcode_slice: Transcoder failed to unpack a ASTC HDR block - this is a bug, or the data was corrupted\n"); return false; } - + status = astc_helpers::decode_block(log_blk, blk_texels, 6, 6, astc_helpers::cDecodeModeHDR16); if (!status) { @@ -11025,14 +11025,14 @@ namespace basist unpacked_blocks[iy * 6 + y][ix * 6 + x][0] = blk_texels[y][x][0]; unpacked_blocks[iy * 6 + y][ix * 6 + x][1] = blk_texels[y][x][1]; unpacked_blocks[iy * 6 + y][ix * 6 + x][2] = blk_texels[y][x][2]; - + } // x } // y } // ix } // iy - + const uint32_t dst_x = src_block_x * 6; assert((dst_x & 3) == 0); const uint32_t dst_block_x = dst_x >> 2; @@ -11065,10 +11065,10 @@ namespace basist src_pixels[y][x][0] = unpacked_blocks[src_pixel_y][src_pixel_x][0]; src_pixels[y][x][1] = unpacked_blocks[src_pixel_y][src_pixel_x][1]; src_pixels[y][x][2] = unpacked_blocks[src_pixel_y][src_pixel_x][2]; - + } // x } // y - + astc_6x6_hdr::fast_encode_bc6h(&src_pixels[0][0][0], pDst_block, bc6h_enc_params); } // dx @@ -11077,7 +11077,7 @@ namespace basist } // block_x } // block_y - + status = true; } else @@ -11203,7 +11203,7 @@ namespace basist if (!status) { - BASISU_DEVEL_ERROR("basisu_lowlevel_astc_hdr_6x6_transcoder::transcode_slice: Transcoder failed to unpack a ASTC HDR block - this is a bug, or the data was corrupted\n"); + BASISU_DEVEL_ERROR("basisu_lowlevel_astc_hdr_6x6_transcoder::transcode_slice: Transcoder failed to unpack a ASTC HDR block - this is a bug, or the data was corrupted\n"); return false; } @@ -11434,7 +11434,7 @@ namespace basist fast_bc6h_params bc6h_enc_params; const bool hq_flag = (decode_flags & cDecodeFlagsHighQuality) != 0; bc6h_enc_params.m_max_2subset_pats_to_try = hq_flag ? 1 : 0; - + for (uint32_t src_block_y = 0; src_block_y < num_blocks_y; src_block_y += 2) { const uint32_t num_inner_blocks_y = basisu::minimum(2, num_blocks_y - src_block_y); @@ -11515,7 +11515,7 @@ namespace basist } // x } // y - + astc_6x6_hdr::fast_encode_bc6h(&src_pixels[0][0][0], pDst_block, bc6h_enc_params); } // dx @@ -11780,7 +11780,7 @@ namespace basist } //------------------------------------------------------------------------------------------------ - + basisu_transcoder::basisu_transcoder() : m_ready_to_transcode(false) { @@ -11808,7 +11808,7 @@ namespace basist return false; } } -#endif +#endif return true; } @@ -11895,7 +11895,7 @@ namespace basist return false; } } - + // This flag dates back to pre-Basis Universal, when .basis supported full ETC1 too. if ((pHeader->m_flags & cBASISHeaderFlagETC1S) == 0) { @@ -11911,7 +11911,7 @@ namespace basist return false; } } - + if ((pHeader->m_slice_desc_file_ofs >= data_size) || ((data_size - pHeader->m_slice_desc_file_ofs) < (sizeof(basis_slice_desc) * pHeader->m_total_slices)) ) @@ -12027,20 +12027,20 @@ namespace basist image_info.m_image_index = image_index; image_info.m_total_levels = total_levels; - + image_info.m_alpha_flag = false; // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha. if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) - image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; + image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; else image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0; image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0; - + const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format)); const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format)); - + image_info.m_width = slice_desc.m_num_blocks_x * block_width; image_info.m_height = slice_desc.m_num_blocks_y * block_height; image_info.m_orig_width = slice_desc.m_orig_width; @@ -12160,13 +12160,13 @@ namespace basist image_info.m_image_index = image_index; image_info.m_level_index = level_index; - + // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha. if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; else image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0; - + const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format)); const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format)); @@ -12229,7 +12229,7 @@ namespace basist file_info.m_tex_format = static_cast(static_cast(pHeader->m_tex_format)); file_info.m_etc1s = (pHeader->m_tex_format == (int)basis_tex_format::cETC1S); - + file_info.m_y_flipped = (pHeader->m_flags & cBASISHeaderFlagYFlipped) != 0; file_info.m_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0; @@ -12301,7 +12301,7 @@ namespace basist return true; } - + bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size) { if (!validate_header_quick(pData, data_size)) @@ -12409,7 +12409,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); } } - + m_ready_to_transcode = true; return true; @@ -12420,7 +12420,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); m_ready_to_transcode = false; - + return true; } @@ -12457,7 +12457,7 @@ namespace basist } const basis_slice_desc& slice_desc = reinterpret_cast(pDataU8 + pHeader->m_slice_desc_file_ofs)[slice_index]; - + if (basis_block_format_is_uncompressed(fmt)) { // Assume the output buffer is orig_width by orig_height @@ -12537,7 +12537,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid slice_desc.m_file_size, or passed in buffer too small\n"); return false; } - + if (pHeader->m_tex_format == (int)basis_tex_format::cASTC_HDR_6x6) { return m_lowlevel_astc_6x6_hdr_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y, @@ -12646,7 +12646,7 @@ namespace basist if (!output_row_pitch_in_blocks_or_pixels) output_row_pitch_in_blocks_or_pixels = num_blocks_x; - + if ((fmt == block_format::cETC2_EAC_A8) || (fmt == block_format::cETC2_EAC_R11)) { #if BASISD_SUPPORT_ETC2_EAC_A8 @@ -12732,7 +12732,7 @@ namespace basist if (slice_index < 0) { BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: failed finding slice index\n"); - // Unable to find the requested image/level + // Unable to find the requested image/level return false; } @@ -12741,7 +12741,7 @@ namespace basist // Switch to PVRTC1 RGB if the input doesn't have alpha. fmt = transcoder_texture_format::cTFPVRTC1_4_RGB; } - + if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) { if (pSlice_descs[slice_index].m_flags & cSliceDescFlagsHasAlpha) @@ -12778,7 +12778,7 @@ namespace basist } } } - + bool status = false; if ((pHeader->m_tex_format == (int)basis_tex_format::cETC1S) || (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)) @@ -12789,12 +12789,12 @@ namespace basist if (((fmt == transcoder_texture_format::cTFPVRTC1_4_RGB) || (fmt == transcoder_texture_format::cTFPVRTC1_4_RGBA)) && (output_blocks_buf_size_in_blocks_or_pixels > total_slice_blocks)) { // The transcoder doesn't write beyond total_slice_blocks, so we need to clear the rest ourselves. - // For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8. + // For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8. // However, for KTX and internally in Basis this formula isn't used, it's just ((width+3)/4) * ((height+3)/4) * bytes_per_block_or_pixel. This is all the transcoder actually writes to memory. memset(static_cast(pOutput_blocks) + total_slice_blocks * bytes_per_block_or_pixel, 0, (output_blocks_buf_size_in_blocks_or_pixels - total_slice_blocks) * bytes_per_block_or_pixel); } } - + if (pHeader->m_tex_format == (int)basis_tex_format::cASTC_HDR_6x6) { const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index]; @@ -12839,7 +12839,7 @@ namespace basist pSlice_desc->m_file_ofs, pSlice_desc->m_file_size, decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); } - else + else { // ETC1S const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index]; @@ -12865,14 +12865,14 @@ namespace basist decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); } // if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4) - + if (!status) { BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning false\n"); } else { - //BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n"); + //BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n"); } return status; @@ -13141,14 +13141,14 @@ namespace basist } return false; } - + uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt) { switch (fmt) { case transcoder_texture_format::cTFRGBA32: case transcoder_texture_format::cTFRGB_9E5: - return sizeof(uint32_t); + return sizeof(uint32_t); case transcoder_texture_format::cTFRGB565: case transcoder_texture_format::cTFBGR565: case transcoder_texture_format::cTFRGBA4444: @@ -13162,7 +13162,7 @@ namespace basist } return 0; } - + uint32_t basis_get_block_width(transcoder_texture_format tex_type) { switch (tex_type) @@ -13228,7 +13228,7 @@ namespace basist } return false; } - + bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt) { if ((fmt == basis_tex_format::cASTC_HDR_6x6) || (fmt == basis_tex_format::cASTC_HDR_6x6_INTERMEDIATE)) @@ -13329,7 +13329,7 @@ namespace basist case transcoder_texture_format::cTFETC2_RGBA: return true; #endif -#if BASISD_SUPPORT_ASTC +#if BASISD_SUPPORT_ASTC case transcoder_texture_format::cTFASTC_4x4_RGBA: return true; #endif @@ -13360,9 +13360,9 @@ namespace basist return false; } - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ // UASTC LDR 4x4 - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_UASTC const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2] = @@ -14087,7 +14087,7 @@ namespace basist if (group_size) { - // Range has trits or quints - pack each group of 5 or 3 values + // Range has trits or quints - pack each group of 5 or 3 values const int total_groups = (group_size == 5) ? ((num_vals + 4) / 5) : ((num_vals + 2) / 3); for (int group_index = 0; group_index < total_groups; group_index++) @@ -14379,7 +14379,7 @@ namespace basist bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool blue_contract_check, bool read_hints) { //memset(&unpacked, 0, sizeof(unpacked)); - + #if 0 uint8_t table[128]; memset(table, 0xFF, sizeof(table)); @@ -14435,7 +14435,7 @@ namespace basist return true; } - + if (read_hints) { if (g_uastc_mode_has_bc1_hint0[mode]) @@ -14468,7 +14468,7 @@ namespace basist } else bit_ofs += g_uastc_mode_total_hint_bits[mode]; - + uint32_t subsets = 1; switch (mode) { @@ -14681,7 +14681,7 @@ namespace basist { // All other modes have <= 64 weight bits. uint64_t bits; - + // Read the weight bits if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS)) bits = read_bits64(blk.m_bytes, bit_ofs, basisu::minimum(64, 128 - (int)bit_ofs)); @@ -14689,31 +14689,31 @@ namespace basist { bits = blk.m_dwords[2]; bits |= (((uint64_t)blk.m_dwords[3]) << 32U); - + if (bit_ofs >= 64U) bits >>= (bit_ofs - 64U); else { assert(bit_ofs >= 56U); - + uint32_t bits_needed = 64U - bit_ofs; bits <<= bits_needed; bits |= (blk.m_bytes[7] >> (8U - bits_needed)); } } - + bit_ofs = 0; const uint32_t mask = (1U << weight_bits) - 1U; const uint32_t anchor_mask = (1U << (weight_bits - 1U)) - 1U; - + if (total_planes == 2) { // Dual plane modes always have a single subset, and the first 2 weights are anchors. unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask); bit_ofs += (weight_bits - 1); - + unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask); bit_ofs += (weight_bits - 1); @@ -14731,7 +14731,7 @@ namespace basist if (weight_bits == 4) { assert(bit_ofs == 0); - + // Specialize the most common case: 4-bit weights. unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits) & 7); unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> 3) & 15); @@ -15277,7 +15277,7 @@ namespace basist } case 2: { - // 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE1 + // 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE1 dst_blk.m_mode = 1; dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7; @@ -16216,7 +16216,7 @@ namespace basist bool flip = pack_etc1_y_estimate_flipped(&block_y[0][0], upper_avg, lower_avg, left_avg, right_avg); // non-flipped: | | - // vs. + // vs. // flipped: -- // -- @@ -16827,7 +16827,7 @@ namespace basist static const uint8_t s_uastc2_to_bc1[4] = { 0, 2, 3, 1 }; static const uint8_t s_uastc1_to_bc1[2] = { 0, 1 }; const uint8_t* s_uastc_to_bc1_weights[6] = { nullptr, s_uastc1_to_bc1, s_uastc2_to_bc1, s_uastc3_to_bc1, s_uastc4_to_bc1, s_uastc5_to_bc1 }; - + void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride) { uint32_t min0_v, max0_v, min1_v, max1_v,min2_v, max2_v, min3_v, max3_v; @@ -16915,7 +16915,7 @@ namespace basist a2 |= (s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)] << 12U); a3 |= (s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)] << 12U); } - + { const int v0 = pPixels[8 * stride] * 14 + bias; const int v1 = pPixels[9 * stride] * 14 + bias; @@ -16939,7 +16939,7 @@ namespace basist } const uint64_t f = a0 | a1 | a2 | a3; - + pDst_bytes[2] = (uint8_t)f; pDst_bytes[3] = (uint8_t)(f >> 8U); pDst_bytes[4] = (uint8_t)(f >> 16U); @@ -16962,7 +16962,7 @@ namespace basist int dots[4]; for (uint32_t i = 0; i < 4; i++) dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab; - + int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3]; ar *= 2; ag *= 2; ab *= 2; @@ -16971,7 +16971,7 @@ namespace basist { const int d = pSrc_pixels[i].r * ar + pSrc_pixels[i].g * ag + pSrc_pixels[i].b * ab; static const uint8_t s_sels[4] = { 3, 2, 1, 0 }; - + // Rounding matters here! // d <= t0: <=, not <, to the later LS step "sees" a wider range of selectors. It matters for quality. sels[i] = s_sels[(d <= t0) + (d < t1) + (d < t2)]; @@ -17012,11 +17012,11 @@ namespace basist sels[i+3] = s_sels[(d3 <= t0) + (d3 < t1) + (d3 < t2)]; } } - + static bool compute_least_squares_endpoints_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh) { // Derived from bc7enc16's LS function. - // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf // I did this in matrix form first, expanded out all the ops, then optimized it a bit. uint32_t uq00_r = 0, uq10_r = 0, ut_r = 0, uq00_g = 0, uq10_g = 0, ut_g = 0, uq00_b = 0, uq10_b = 0, ut_b = 0; @@ -17090,7 +17090,7 @@ namespace basist return true; } - void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb) + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb) { dxt1_block* pDst_block = static_cast(pDst); @@ -17142,19 +17142,19 @@ namespace basist { const color32* pSrc_pixels = (const color32*)pPixels; dxt1_block* pDst_block = static_cast(pDst); - + int avg_r = -1, avg_g = 0, avg_b = 0; int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0; uint8_t sels[16]; - + const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0; if (use_sels) { // Caller is jamming in their own selectors for us to try. const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24); - + static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 }; - + for (uint32_t i = 0; i < 16; i++) sels[i] = s_sel_tran[(s >> (i * 2)) & 3]; } @@ -17166,13 +17166,13 @@ namespace basist for (j = 1; j < 16; j++) if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb)) break; - + if (j == 16) { encode_bc1_solid_block(pDst, fr, fg, fb); return; } - + // Select 2 colors along the principle axis. (There must be a faster/simpler way.) int total_r = fr, total_g = fg, total_b = fb; int max_r = fr, max_g = fg, max_b = fb; @@ -17206,7 +17206,7 @@ namespace basist float cov[6]; for (uint32_t i = 0; i < 6; i++) cov[i] = static_cast(icov[i])* (1.0f / 255.0f); - + #if 0 // Seems silly to use full PCA to choose 2 colors. The diff in avg. PSNR between using PCA vs. not is small (~.025 difference). // TODO: Try 2 or 3 different normalized diagonal vectors, choose the one that results in the largest dot delta @@ -17238,7 +17238,7 @@ namespace basist saxis_b = (int)(xb * m); } #endif - + int low_dot = INT_MAX, high_dot = INT_MIN, low_c = 0, high_c = 0; for (uint32_t i = 0; i < 16; i++) { @@ -17262,7 +17262,7 @@ namespace basist hr = to_5(pSrc_pixels[high_c].r); hg = to_6(pSrc_pixels[high_c].g); hb = to_5(pSrc_pixels[high_c].b); - + bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels); } // if (use_sels) @@ -17309,13 +17309,13 @@ namespace basist hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63); hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31); } - + bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels); } uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb); uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb); - + // Always forbid 3 color blocks if (lc16 == hc16) { @@ -17367,7 +17367,7 @@ namespace basist pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask; } } - + void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags) { const color32* pSrc_pixels = (const color32*)pPixels; @@ -17416,8 +17416,8 @@ namespace basist min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b); total_r += r; total_g += g; total_b += b; } - - if (grayscale_flag) + + if (grayscale_flag) { // Grayscale blocks are a common enough case to specialize. if ((max_r - min_r) < 2) @@ -17734,7 +17734,7 @@ namespace basist // Always forbid 3 color blocks uint16_t lc16 = (uint16_t)b.get_low_color(); uint16_t hc16 = (uint16_t)b.get_high_color(); - + uint8_t mask = 0; // Make l > h @@ -17964,7 +17964,7 @@ namespace basist blk.m_base = static_cast(a); blk.m_table = 13; blk.m_multiplier = 0; - + memcpy(blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4)); return; @@ -18654,7 +18654,7 @@ namespace basist if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false)) return false; - // Get block's RGB bounding box + // Get block's RGB bounding box color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0); if (from_alpha) @@ -18713,7 +18713,7 @@ namespace basist if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false)) return false; - // Get block's RGBA bounding box + // Get block's RGBA bounding box color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0); for (uint32_t i = 0; i < 16; i++) @@ -18829,9 +18829,9 @@ namespace basist #endif // #if BASISD_SUPPORT_UASTC -// ------------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------------ // KTX2 -// ------------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_KTX2 const uint8_t g_ktx2_file_identifier[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; @@ -18854,7 +18854,7 @@ namespace basist memset(&m_etc1s_header, 0, sizeof(m_etc1s_header)); m_etc1s_image_descs.clear(); m_astc_6x6_intermediate_image_descs.clear(); - + m_format = basist::basis_tex_format::cETC1S; m_dfd_color_model = 0; @@ -18866,9 +18866,9 @@ namespace basist m_dfd_chan1 = KTX2_DF_CHANNEL_UASTC_RGB; m_etc1s_transcoder.clear(); - + m_def_transcoder_state.clear(); - + m_has_alpha = false; m_is_video = false; m_ldr_hdr_upconversion_nit_multiplier = 0.0f; @@ -18903,8 +18903,8 @@ namespace basist memcpy(&m_header, pData, sizeof(m_header)); // Check for supported VK formats. We may also need to parse the DFD. - if ((m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED) && - (m_header.m_vk_format != basist::KTX2_FORMAT_ASTC_4x4_SFLOAT_BLOCK) && + if ((m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED) && + (m_header.m_vk_format != basist::KTX2_FORMAT_ASTC_4x4_SFLOAT_BLOCK) && (m_header.m_vk_format != basist::KTX2_FORMAT_ASTC_6x6_SFLOAT_BLOCK)) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file must be in ETC1S or UASTC LDR/HDR format\n"); @@ -18942,7 +18942,7 @@ namespace basist return false; } } - + // 3.7 levelCount: "levelCount=0 is allowed, except for block-compressed formats" if (m_header.m_level_count < 1) { @@ -19001,7 +19001,7 @@ namespace basist } memcpy(&m_levels[0], m_pData + sizeof(ktx2_header), level_index_size_in_bytes); - + // Sanity check the level offsets and byte sizes for (uint32_t i = 0; i < m_levels.size(); i++) { @@ -19021,9 +19021,9 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset and/or length\n"); return false; } - + const uint64_t MAX_SANE_LEVEL_UNCOMP_SIZE = 2048ULL * 1024ULL * 1024ULL; - + if (m_levels[i].m_uncompressed_byte_length >= MAX_SANE_LEVEL_UNCOMP_SIZE) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too large)\n"); @@ -19060,7 +19060,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD offset and/or length\n"); return false; } - + const uint8_t* pDFD = m_pData + m_header.m_dfd_byte_offset; if (!m_dfd.try_resize(m_header.m_dfd_byte_length)) @@ -19070,17 +19070,17 @@ namespace basist } memcpy(m_dfd.data(), pDFD, m_header.m_dfd_byte_length); - + // This is all hard coded for only ETC1S and UASTC. uint32_t dfd_total_size = basisu::read_le_dword(pDFD); - + // 3.10.3: Sanity check if (dfd_total_size != m_header.m_dfd_byte_length) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (1)\n"); return false; } - + // 3.10.3: More sanity checking if (m_header.m_kvd_byte_length) { @@ -19093,7 +19093,7 @@ namespace basist const uint32_t dfd_bits = basisu::read_le_dword(pDFD + 3 * sizeof(uint32_t)); const uint32_t sample_channel0 = basisu::read_le_dword(pDFD + 7 * sizeof(uint32_t)); - + m_dfd_color_model = dfd_bits & 255; m_dfd_color_prims = (ktx2_df_color_primaries)((dfd_bits >> 8) & 255); m_dfd_transfer_func = (dfd_bits >> 16) & 255; @@ -19115,11 +19115,11 @@ namespace basist } m_format = basist::basis_tex_format::cETC1S; - + // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD's sample count." // If m_has_alpha is true it may be 2-channel RRRG or 4-channel RGBA, but we let the caller deal with that. m_has_alpha = (m_header.m_dfd_byte_length == 60); - + m_dfd_samples = m_has_alpha ? 2 : 1; m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15); @@ -19141,7 +19141,7 @@ namespace basist m_dfd_samples = 1; m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15); - + // We're assuming "DATA" means RGBA so it has alpha. m_has_alpha = (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RGBA) || (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RRRG); } @@ -19201,7 +19201,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD color model\n"); return false; } - + if (!read_key_values()) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: read_key_values() failed\n"); @@ -19260,7 +19260,7 @@ namespace basist return nullptr; } - + bool ktx2_transcoder::start_transcoding() { if (!m_pData) @@ -19269,14 +19269,14 @@ namespace basist return false; } - if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ) + if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ) { if (m_format == basis_tex_format::cETC1S) { // Check if we've already decompressed the ETC1S global data. If so don't unpack it again. if (!m_etc1s_transcoder.get_endpoints().empty()) return true; - + if (!decompress_etc1s_global_data()) { BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: decompress_etc1s_global_data() failed\n"); @@ -19355,7 +19355,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: layer_index >= maximum(m_header.m_layer_count, 1)\n"); return false; } - + const uint32_t level_width = basisu::maximum(m_header.m_pixel_width >> level_index, 1); const uint32_t level_height = basisu::maximum(m_header.m_pixel_height >> level_index, 1); @@ -19379,7 +19379,7 @@ namespace basist level_info.m_total_blocks = num_blocks_x * num_blocks_y; level_info.m_alpha_flag = m_has_alpha; level_info.m_iframe_flag = false; - + if (m_etc1s_image_descs.size()) { const uint32_t etc1s_image_index = @@ -19392,9 +19392,9 @@ namespace basist return true; } - + bool ktx2_transcoder::transcode_image_level( - uint32_t level_index, uint32_t layer_index, uint32_t face_index, + uint32_t level_index, uint32_t layer_index, uint32_t face_index, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, basist::transcoder_texture_format fmt, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, uint32_t output_rows_in_pixels, int channel0, int channel1, @@ -19408,7 +19408,7 @@ namespace basist if (!pState) pState = &m_def_transcoder_state; - + if (level_index >= m_levels.size()) { BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: level_index >= m_levels.size()\n"); @@ -19437,7 +19437,7 @@ namespace basist const uint8_t* pComp_level_data = m_pData + m_levels[level_index].m_byte_offset; uint64_t comp_level_data_size = m_levels[level_index].m_byte_length; - + const uint8_t* pUncomp_level_data = pComp_level_data; uint64_t uncomp_level_data_size = comp_level_data_size; @@ -19446,7 +19446,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_level_data_size > UINT32_MAX\n"); return false; } - + if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD) { // Check if we've already decompressed this level's supercompressed data. @@ -19464,12 +19464,12 @@ namespace basist pUncomp_level_data = pState->m_level_uncomp_data.data(); uncomp_level_data_size = pState->m_level_uncomp_data.size(); } - + const uint32_t level_width = basisu::maximum(m_header.m_pixel_width >> level_index, 1); const uint32_t level_height = basisu::maximum(m_header.m_pixel_height >> level_index, 1); const uint32_t num_blocks4_x = (level_width + 3) >> 2; const uint32_t num_blocks4_y = (level_height + 3) >> 2; - + if (m_format == basist::basis_tex_format::cETC1S) { // Ensure start_transcoding() was called. @@ -19483,7 +19483,7 @@ namespace basist (level_index * basisu::maximum(m_header.m_layer_count, 1) * m_header.m_face_count) + layer_index * m_header.m_face_count + face_index; - + // Sanity check if (etc1s_image_index >= m_etc1s_image_descs.size()) { @@ -19532,7 +19532,7 @@ namespace basist } const ktx2_astc_hdr_6x6_intermediate_image_desc& image_desc = m_astc_6x6_intermediate_image_descs[image_index]; - + if (!m_astc_hdr_6x6_intermediate_transcoder.transcode_image(fmt, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, m_pData, m_data_size, num_blocks6_x, num_blocks6_y, level_width, level_height, level_index, @@ -19583,7 +19583,7 @@ namespace basist // Compute length and offset to uncompressed 2D UASTC texture data, given the face/layer indices. assert(uncomp_level_data_size == m_levels[level_index].m_uncompressed_byte_length); const uint32_t total_2D_image_size = num_blocks4_x * num_blocks4_y * KTX2_UASTC_BLOCK_SIZE; - + const uint32_t uncomp_ofs = (layer_index * m_header.m_face_count + face_index) * total_2D_image_size; // Sanity checks @@ -19634,12 +19634,12 @@ namespace basist return true; } - + bool ktx2_transcoder::decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data) { const uint8_t* pComp_data = m_levels[level_index].m_byte_offset + m_pData; const uint64_t comp_size = m_levels[level_index].m_byte_length; - + const uint64_t uncomp_size = m_levels[level_index].m_uncompressed_byte_length; if (((size_t)comp_size) != comp_size) @@ -19658,7 +19658,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Out of memory\n"); return false; } - + if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD) { #if BASISD_SUPPORT_KTX2_ZSTD @@ -19696,7 +19696,7 @@ namespace basist } m_astc_6x6_intermediate_image_descs.resize(image_count); - + memcpy(m_astc_6x6_intermediate_image_descs.data(), pSrc, sizeof(ktx2_astc_hdr_6x6_intermediate_image_desc) * image_count); // Sanity check the image descs @@ -19713,7 +19713,7 @@ namespace basist return true; } - + bool ktx2_transcoder::decompress_etc1s_global_data() { // Note: we don't actually support 3D textures in here yet @@ -19752,13 +19752,13 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: SGD byte length is too small, file is invalid or corrupted\n"); return false; } - + if (!m_etc1s_image_descs.try_resize(image_count)) { BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Out of memory\n"); return false; } - + memcpy(m_etc1s_image_descs.data(), pSrc, sizeof(ktx2_etc1s_image_desc) * image_count); pSrc += sizeof(ktx2_etc1s_image_desc) * image_count; @@ -19792,7 +19792,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_tables() failed, file is invalid or corrupted\n"); return false; } - + if (!m_etc1s_transcoder.decode_palettes( m_etc1s_header.m_endpoint_count, pEndpoint_data, m_etc1s_header.m_endpoints_byte_length, m_etc1s_header.m_selector_count, pSelector_data, m_etc1s_header.m_selectors_byte_length)) @@ -19800,7 +19800,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_palettes() failed, file is likely corrupted\n"); return false; } - + return true; } @@ -19841,7 +19841,7 @@ namespace basist while (src_left > sizeof(uint32_t)) { uint32_t l = basisu::read_le_dword(pSrc); - + pSrc += sizeof(uint32_t); src_left -= sizeof(uint32_t); @@ -19862,7 +19862,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n"); return false; } - + basisu::uint8_vec& key_data = m_key_values.back().m_key; basisu::uint8_vec& value_data = m_key_values.back().m_value; @@ -19891,7 +19891,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n"); return false; } - + if (!value_data.try_resize(l)) { BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n"); @@ -19927,7 +19927,7 @@ namespace basist return true; } - + #endif // BASISD_SUPPORT_KTX2 bool basisu_transcoder_supports_ktx2() @@ -19994,10 +19994,10 @@ namespace basist basist::half_float result = (basist::half_float)((s << 15) | (e << 10) | m); return result; } - + //------------------------------------------------------------------------------------------------ // HDR support - // + // // Originally from bc6h_enc.cpp // BC6H decoder fuzzed vs. DirectXTex's for unsigned/signed @@ -20026,7 +20026,7 @@ namespace basist const bc6h_bit_layout g_bc6h_bit_layouts[NUM_BC6H_MODES][MAX_BC6H_LAYOUT_INDEX] = { // comp_index, subset*2+lh_index, last_bit, first_bit - //------------------------ mode 0: 2 subsets, Weight bits: 46 bits, Endpoint bits: 75 bits (10.555, 10.555, 10.555), delta + //------------------------ mode 0: 2 subsets, Weight bits: 46 bits, Endpoint bits: 75 bits (10.555, 10.555, 10.555), delta { { 1, 2, 4, -1 }, { 2, 2, 4, -1 }, { 2, 3, 4, -1 }, { 0, 0, 9, 0 }, { 1, 0, 9, 0 }, { 2, 0, 9, 0 }, { 0, 1, 4, 0 }, { 1, 3, 4, -1 }, { 1, 2, 3, 0 }, { 1, 1, 4, 0 }, { 2, 3, 0, -1 }, { 1, 3, 3, 0 }, { 2, 1, 4, 0 }, { 2, 3, 1, -1 }, { 2, 2, 3, 0 }, { 0, 2, 4, 0 }, { 2, 3, 2, -1 }, { 0, 3, 4, 0 }, { 2, 3, 3, -1 }, { 3, -1, 4, 0 }, {-1, 0, 0, 0} }, @@ -20077,7 +20077,7 @@ namespace basist { { 0, 0, 9, 0 },{ 1, 0, 9, 0 },{ 2, 0, 9, 0 },{ 0, 1, 3, 0 },{ 0, 0, 10, 15 },{ 1, 1, 3, 0 },{ 1, 0, 10, 15 },{ 2, 1, 3, 0 },{ 2, 0, 10, 15 }, {-1, 0, 0, 0} } }; - // The same as the first 32 2-subset patterns in BC7. + // The same as the first 32 2-subset patterns in BC7. // Bit 7 is a flag indicating that the weight uses 1 less bit than usual. const uint8_t g_bc6h_2subset_patterns[TOTAL_BC6H_PARTITION_PATTERNS][4][4] = // [pat][y][x] { @@ -20101,7 +20101,7 @@ namespace basist const uint8_t g_bc6h_weight3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; const uint8_t g_bc6h_weight4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; - + static inline void write_bits(uint64_t val, uint32_t num_bits, uint32_t& bit_pos, uint64_t& l, uint64_t& h) { assert((num_bits) && (num_bits < 64) && (bit_pos < 128)); @@ -20230,12 +20230,12 @@ namespace basist return unq; } #endif - + // 6,7,8,9,10,11,12 const uint32_t BC6H_BLOG_TAB_MIN = 6; const uint32_t BC6H_BLOG_TAB_MAX = 12; //const uint32_t BC6H_BLOG_TAB_NUM = BC6H_BLOG_TAB_MAX - BC6H_BLOG_TAB_MIN + 1; - + // Handles 16, or 6-12 bits. Others assert. static inline uint32_t half_to_blog_tab(half_float h, uint32_t num_bits) { @@ -20254,7 +20254,7 @@ namespace basist else { assert((num_bits >= BC6H_BLOG_TAB_MIN) && (num_bits <= BC6H_BLOG_TAB_MAX)); - + // Note: This used to be done using a table lookup, but it required ~224KB of tables. This isn't quite as accurate, but the error is very slight (+-1 half values as ints). return bc6h_half_to_blog(h, num_bits); } @@ -20384,7 +20384,7 @@ namespace basist log_blk.m_mode = mode; pack_bc6h_block(*pPacked_block, log_blk); - + return; } @@ -20784,13 +20784,13 @@ namespace basist half_float endpoints[3][2]; endpoints[0][0] = pColor[0]; endpoints[0][1] = pColor[0]; - + endpoints[1][0] = pColor[1]; endpoints[1][1] = pColor[1]; endpoints[2][0] = pColor[2]; endpoints[2][1] = pColor[2]; - + bc6h_enc_block_1subset_4bit_weights(pPacked_block, endpoints, weights); return true; @@ -21068,7 +21068,7 @@ namespace basist if (ohm & 0x12) vb1 |= (x3 << 7); const int shamt = (mode >> 1) ^ 3; - + va = (uint32_t)va << shamt; vb0 = (uint32_t)vb0 << shamt; vb1 = (uint32_t)vb1 << shamt; @@ -21138,7 +21138,7 @@ namespace basist { assert(g_astc_hdr_core_initialized); assert((best_blk.m_weight_ise_range >= 1) && (best_blk.m_weight_ise_range <= 8)); - + if (best_blk.m_weight_ise_range == 5) { // Use 3-bit BC6H weights which are a perfect match for 3-bit ASTC weights, but encode 1-subset as 2 equal subsets @@ -21220,7 +21220,7 @@ namespace basist assert(g_astc_hdr_core_initialized); assert(best_blk.m_num_partitions == 2); assert(common_part_index < basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2); - + half_float bc6h_endpoints[2][3][2]; // [subset][comp][lh_index] // UASTC HDR checks @@ -21229,7 +21229,7 @@ namespace basist return false; if ((best_blk.m_color_endpoint_modes[0] != 7) && (best_blk.m_color_endpoint_modes[0] != 11)) return false; - + if (best_blk.m_color_endpoint_modes[0] == 7) { if (!(((best_blk.m_weight_ise_range == 1) && (best_blk.m_endpoint_ise_range == 20)) || @@ -21354,7 +21354,7 @@ namespace basist assert(0); return false; } - + if (log_blk.m_solid_color_flag_ldr) { // Don't support LDR solid colors. @@ -21370,7 +21370,7 @@ namespace basist // Only support 4x4 grid sizes if ((log_blk.m_grid_width != 4) || (log_blk.m_grid_height != 4)) return false; - + // Don't support dual plane encoding if (log_blk.m_dual_plane) return false; @@ -21378,11 +21378,11 @@ namespace basist if (log_blk.m_num_partitions == 1) { // Handle 1 partition (or subset) - + // UASTC HDR checks if ((log_blk.m_weight_ise_range < 1) || (log_blk.m_weight_ise_range > 8)) return false; - + int e[2][3]; bool success; @@ -21428,7 +21428,7 @@ namespace basist for (uint32_t i = 0; i < 2; i++) if (is_half_inf_or_nan(h_e[0][i]) || is_half_inf_or_nan(h_e[1][i]) || is_half_inf_or_nan(h_e[2][i])) return false; - + // Transcode to bc6h if (!transcode_bc6h_1subset(h_e, log_blk, dst_blk)) return false; @@ -21441,7 +21441,7 @@ namespace basist return false; assert(common_bc7_pat_index < (int)basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2); - + if (!transcode_bc6h_2subsets(common_bc7_pat_index, log_blk, dst_blk)) return false; } @@ -21453,7 +21453,7 @@ namespace basist return true; } - + // ASTC 6x6 support namespace astc_6x6_hdr { @@ -21581,7 +21581,7 @@ namespace basist // 3x3 { false, 7, 3, 3, 3, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_8_LEVELS, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_8_LEVELS, 0, 0 }, - // 6x4 + // 6x4 { false, 7, 3, 6, 4, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_2_LEVELS, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_2_LEVELS, BASIST_HDR_6X6_LEVEL2, 0 }, { false, 7, 3, 4, 6, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_2_LEVELS, astc_helpers::BISE_64_LEVELS, astc_helpers::BISE_2_LEVELS, BASIST_HDR_6X6_LEVEL2, 0 }, @@ -21609,7 +21609,7 @@ namespace basist { false, 7, 3, 5, 4, astc_helpers::BISE_40_LEVELS, astc_helpers::BISE_3_LEVELS, astc_helpers::BISE_40_LEVELS, astc_helpers::BISE_3_LEVELS, 0, 0 }, { false, 7, 3, 4, 5, astc_helpers::BISE_40_LEVELS, astc_helpers::BISE_3_LEVELS, astc_helpers::BISE_40_LEVELS, astc_helpers::BISE_3_LEVELS, 0, 0 }, }; - + const reuse_xy_delta g_reuse_xy_deltas[NUM_REUSE_XY_DELTAS] = { { -1, 0 }, { -2, 0 }, { -3, 0 }, { -4, 0 }, @@ -21662,20 +21662,20 @@ namespace basist const uint32_t g_part2_unique_index_to_seed[NUM_UNIQUE_PARTITIONS2] = { - 86, 959, 936, 476, 1007, 672, 447, 423, 488, 422, 273, 65, 267, 786, 585, 195, 108, 731, 878, 812, 264, 125, 868, 581, 258, 390, 549, 872, 661, 352, 645, 543, 988, - 906, 903, 616, 482, 529, 3, 286, 272, 303, 151, 504, 498, 260, 79, 66, 608, 769, 305, 610, 1014, 967, 835, 789, 7, 951, 691, 15, 763, 976, 438, 314, 601, 673, 177, - 252, 615, 436, 220, 899, 623, 433, 674, 278, 797, 107, 847, 114, 470, 760, 821, 490, 329, 945, 387, 471, 225, 172, 83, 418, 966, 439, 316, 247, 43, 343, 625, 798, - 1, 61, 73, 307, 136, 474, 42, 664, 1013, 249, 389, 227, 374, 121, 48, 538, 226, 309, 554, 802, 834, 335, 495, 10, 955, 461, 293, 508, 153, 101, 63, 139, 31, 687, - 132, 174, 324, 545, 289, 39, 178, 594, 963, 854, 222, 323, 998, 964, 598, 475, 720, 1019, 983, 91, 703, 614, 394, 612, 281, 207, 930, 758, 586, 128, 517, 426, 306, - 168, 713, 36, 458, 876, 368, 780, 5, 9, 214, 109, 553, 726, 175, 103, 753, 684, 44, 665, 53, 500, 367, 611, 119, 732, 639, 326, 203, 156, 686, 910, 255, 62, 392, 591, - 112, 88, 213, 19, 1022, 478, 90, 486, 799, 702, 730, 414, 99, 1008, 142, 886, 373, 216, 69, 393, 299, 648, 415, 822, 912, 110, 567, 550, 693, 2, 138, 59, 271, 562, 295, - 714, 719, 199, 893, 831, 1006, 662, 235, 262, 78, 51, 902, 298, 190, 169, 583, 347, 890, 958, 909, 49, 987, 696, 633, 480, 50, 764, 826, 1023, 1016, 437, 891, 774, 257, - 724, 791, 526, 593, 690, 638, 858, 895, 794, 995, 130, 87, 877, 819, 318, 649, 376, 211, 284, 937, 370, 688, 229, 994, 115, 842, 60, 521, 95, 694, 804, 146, 754, 487, 55, - 17, 770, 450, 223, 4, 137, 911, 236, 683, 523, 47, 181, 24, 270, 602, 736, 11, 355, 148, 351, 762, 1009, 16, 210, 619, 805, 874, 807, 887, 403, 999, 810, 27, 402, 551, 135, - 778, 33, 409, 993, 71, 363, 159, 183, 77, 596, 670, 380, 968, 811, 404, 348, 539, 158, 578, 196, 621, 68, 530, 193, 100, 167, 919, 353, 366, 327, 643, 948, 518, 756, 801, 558, - 28, 705, 116, 94, 898, 453, 622, 647, 231, 445, 652, 230, 191, 277, 292, 254, 198, 766, 386, 232, 29, 70, 942, 740, 291, 607, 411, 496, 839, 8, 675, 319, 742, 21, 547, 627, 716, - 663, 23, 914, 631, 595, 499, 685, 950, 510, 54, 587, 432, 45, 646, 25, 122, 947, 171, 862, 441, 808, 722, 14, 74, 658, 129, 266, 1001, 534, 395, 527, 250, 206, 237, 67, 897, 634, - 572, 569, 533, 37, 341, 89, 463, 419, 75, 134, 283, 943, 519, 362, 144, 681, 407, 954, 131, 455, 934, 46, 513, 339, 194, 361, 606, 852, 546, 655, 1015, 147, 506, 240, 56, 836, 76, + 86, 959, 936, 476, 1007, 672, 447, 423, 488, 422, 273, 65, 267, 786, 585, 195, 108, 731, 878, 812, 264, 125, 868, 581, 258, 390, 549, 872, 661, 352, 645, 543, 988, + 906, 903, 616, 482, 529, 3, 286, 272, 303, 151, 504, 498, 260, 79, 66, 608, 769, 305, 610, 1014, 967, 835, 789, 7, 951, 691, 15, 763, 976, 438, 314, 601, 673, 177, + 252, 615, 436, 220, 899, 623, 433, 674, 278, 797, 107, 847, 114, 470, 760, 821, 490, 329, 945, 387, 471, 225, 172, 83, 418, 966, 439, 316, 247, 43, 343, 625, 798, + 1, 61, 73, 307, 136, 474, 42, 664, 1013, 249, 389, 227, 374, 121, 48, 538, 226, 309, 554, 802, 834, 335, 495, 10, 955, 461, 293, 508, 153, 101, 63, 139, 31, 687, + 132, 174, 324, 545, 289, 39, 178, 594, 963, 854, 222, 323, 998, 964, 598, 475, 720, 1019, 983, 91, 703, 614, 394, 612, 281, 207, 930, 758, 586, 128, 517, 426, 306, + 168, 713, 36, 458, 876, 368, 780, 5, 9, 214, 109, 553, 726, 175, 103, 753, 684, 44, 665, 53, 500, 367, 611, 119, 732, 639, 326, 203, 156, 686, 910, 255, 62, 392, 591, + 112, 88, 213, 19, 1022, 478, 90, 486, 799, 702, 730, 414, 99, 1008, 142, 886, 373, 216, 69, 393, 299, 648, 415, 822, 912, 110, 567, 550, 693, 2, 138, 59, 271, 562, 295, + 714, 719, 199, 893, 831, 1006, 662, 235, 262, 78, 51, 902, 298, 190, 169, 583, 347, 890, 958, 909, 49, 987, 696, 633, 480, 50, 764, 826, 1023, 1016, 437, 891, 774, 257, + 724, 791, 526, 593, 690, 638, 858, 895, 794, 995, 130, 87, 877, 819, 318, 649, 376, 211, 284, 937, 370, 688, 229, 994, 115, 842, 60, 521, 95, 694, 804, 146, 754, 487, 55, + 17, 770, 450, 223, 4, 137, 911, 236, 683, 523, 47, 181, 24, 270, 602, 736, 11, 355, 148, 351, 762, 1009, 16, 210, 619, 805, 874, 807, 887, 403, 999, 810, 27, 402, 551, 135, + 778, 33, 409, 993, 71, 363, 159, 183, 77, 596, 670, 380, 968, 811, 404, 348, 539, 158, 578, 196, 621, 68, 530, 193, 100, 167, 919, 353, 366, 327, 643, 948, 518, 756, 801, 558, + 28, 705, 116, 94, 898, 453, 622, 647, 231, 445, 652, 230, 191, 277, 292, 254, 198, 766, 386, 232, 29, 70, 942, 740, 291, 607, 411, 496, 839, 8, 675, 319, 742, 21, 547, 627, 716, + 663, 23, 914, 631, 595, 499, 685, 950, 510, 54, 587, 432, 45, 646, 25, 122, 947, 171, 862, 441, 808, 722, 14, 74, 658, 129, 266, 1001, 534, 395, 527, 250, 206, 237, 67, 897, 634, + 572, 569, 533, 37, 341, 89, 463, 419, 75, 134, 283, 943, 519, 362, 144, 681, 407, 954, 131, 455, 934, 46, 513, 339, 194, 361, 606, 852, 546, 655, 1015, 147, 506, 240, 56, 836, 76, 98, 600, 430, 388, 980, 695, 817, 279, 58, 215, 149, 170, 531, 870, 18, 727, 154, 26, 938, 929, 302, 697, 452, 218, 700, 524, 828, 751, 869, 217, 440, 354 }; @@ -22062,7 +22062,7 @@ namespace basist assert((cem == 7) || (cem == 11)); return (cem == 11) ? basist::NUM_MODE11_ENDPOINTS : basist::NUM_MODE7_ENDPOINTS; } - + const uint32_t g_bc6h_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; #if 0 @@ -22146,7 +22146,7 @@ namespace basist float res = (float)fast_float_to_half_no_clamp_neg_nan_or_inf(fabsf(f)) * ((f < 0.0f) ? -1.0f : 1.0f); return res; } - + // Supports positive and denormals only. No NaN or Inf. static BASISU_FORCE_INLINE float fast_half_to_float_pos_not_inf_or_nan(basist::half_float h) { @@ -22187,7 +22187,7 @@ namespace basist int max_r, int max_g, int max_b, int64_t block_max_var) { BASISU_NOTE_UNUSED(block_max_var); - + float fmin_r = fast_half_to_float_pos_not_inf_or_nan((basist::half_float)min_r); float fmin_g = fast_half_to_float_pos_not_inf_or_nan((basist::half_float)min_g); float fmin_b = fast_half_to_float_pos_not_inf_or_nan((basist::half_float)min_b); @@ -22224,12 +22224,12 @@ namespace basist pWeights[i] = (uint8_t)basisu::clamp((int)(w * frr + lr), 0, 15); } } - + static double assign_weights_4( const vec3F* pFloat_pixels, const float* pPixel_scales, uint8_t* pWeights, int min_r, int min_g, int min_b, - int max_r, int max_g, int max_b, int64_t block_max_var, bool try_2subsets_flag, + int max_r, int max_g, int max_b, int64_t block_max_var, bool try_2subsets_flag, const fast_bc6h_params& params) { float cr[16], cg[16], cb[16]; @@ -22347,7 +22347,7 @@ namespace basist pWeights[i] = (uint8_t)best_idx; - // Giesen's MRSSE (Mean Relative Sum of Squared Errors). + // Giesen's MRSSE (Mean Relative Sum of Squared Errors). // Our ASTC HDR encoder uses slightly slower approx. MSLE, and it's too late/risky to eval the difference vs. MRSSE on the larger ASTC HDR blocks. float err = basisu::squaref(qr - cr[best_idx]) + basisu::squaref(qg - cg[best_idx]) + basisu::squaref(qb - cb[best_idx]); total_err += err * pPixel_scales[i]; @@ -22447,7 +22447,7 @@ namespace basist float best_error = basisu::squaref(subset_cr[subset][0] - qr) + basisu::squaref(subset_cg[subset][0] - qg) + basisu::squaref(subset_cb[subset][0] - qb); uint32_t best_idx = 0; - + for (uint32_t j = 1; j < 8; j++) { float e = basisu::squaref(subset_cr[subset][j] - qr) + basisu::squaref(subset_cg[subset][j] - qg) + basisu::squaref(subset_cb[subset][j] - qb); @@ -22520,7 +22520,7 @@ namespace basist static basist::vec4F g_bc6h_ls_weights_3[8]; static basist::vec4F g_bc6h_ls_weights_4[16]; - + const uint32_t BC6H_NUM_PATS = 32; static uint32_t g_bc6h_pats2[BC6H_NUM_PATS]; @@ -22586,7 +22586,7 @@ namespace basist static void bc6h_quant_endpoints( uint32_t min_hr, uint32_t min_hg, uint32_t min_hb, uint32_t max_hr, uint32_t max_hg, uint32_t max_hb, - uint32_t& min_r, uint32_t& min_g, uint32_t& min_b, uint32_t& max_r, uint32_t& max_g, uint32_t& max_b, + uint32_t& min_r, uint32_t& min_g, uint32_t& min_b, uint32_t& max_r, uint32_t& max_g, uint32_t& max_b, int bits) { min_r = basist::bc6h_half_to_blog((basist::half_float)min_hr, bits); @@ -22612,7 +22612,7 @@ namespace basist max_hb = bc6h_convert_to_half(bc6h_dequantize(max_bb, bits)); } - static BASISU_FORCE_INLINE int popcount32(uint32_t x) + static BASISU_FORCE_INLINE int popcount32(uint32_t x) { #if defined(__EMSCRIPTEN__) || defined(__clang__) || defined(__GNUC__) return __builtin_popcount(x); @@ -22620,7 +22620,7 @@ namespace basist return __popcnt(x); #else int count = 0; - while (x) + while (x) { x &= (x - 1); ++count; @@ -22633,23 +22633,23 @@ namespace basist { return (x >= 0.0f) ? (int)(x + 0.5f) : (int)(x - 0.5f); } - + static void fast_encode_bc6h_2subsets_pattern( uint32_t best_pat_index, uint32_t best_pat_bits, const basist::half_float* pPixels, const vec3F* pFloat_pixels, const float* pPixel_scales, double& cur_error, basist::bc6h_logical_block& log_blk, int64_t block_max_var, - int mean_r, int mean_g, int mean_b, + int mean_r, int mean_g, int mean_b, const fast_bc6h_params& params) { BASISU_NOTE_UNUSED(block_max_var); - + uint32_t subset_means[2][3] = { { 0 } }; for (uint32_t i = 0; i < 16; i++) { const uint32_t subset_index = (best_pat_bits >> i) & 1; const uint32_t r = pPixels[i * 3 + 0], g = pPixels[i * 3 + 1], b = pPixels[i * 3 + 2]; - + subset_means[subset_index][0] += r; subset_means[subset_index][1] += g; subset_means[subset_index][2] += b; @@ -22702,7 +22702,7 @@ namespace basist subset_axis[subset_index].set(axis_r, axis_g, axis_b); } // s - + float subset_min_dot[2] = { basisu::BIG_FLOAT_VAL, basisu::BIG_FLOAT_VAL }; float subset_max_dot[2] = { -basisu::BIG_FLOAT_VAL, -basisu::BIG_FLOAT_VAL }; int subset_min_idx[2] = { 0 }, subset_max_idx[2] = { 0 }; @@ -22819,7 +22819,7 @@ namespace basist if (params.m_num_diff_endpoint_modes_to_try) { // ordered from largest base bits to least - static const int s_bc6h_mode_order2[2] = { 5, 1 }; + static const int s_bc6h_mode_order2[2] = { 5, 1 }; static const int s_bc6h_mode_order4[4] = { 0, 5, 7, 1 }; static const int s_bc6h_mode_order9[9] = { 2, 3, 4, 0, 5, 6, 7, 8, 1 }; @@ -22927,10 +22927,10 @@ namespace basist trial_log_blk.m_mode = bc6h_mode_index; trial_log_blk.m_partition_pattern = best_pat_index; - + memcpy(trial_log_blk.m_endpoints, abs_blog_endpoints, sizeof(trial_log_blk.m_endpoints)); memcpy(trial_log_blk.m_weights, trial_weights, 16); - + if (trial_log_blk.m_weights[0] & 4) { for (uint32_t c = 0; c < 3; c++) @@ -22957,7 +22957,7 @@ namespace basist trial_log_blk.m_weights[i] = 7 - trial_log_blk.m_weights[i]; } } - + if (bc6h_mode_index != BC6H_2SUBSET_ABS_ENDPOINT_MODE) { const uint32_t num_delta_bits[3] = { g_bc6h_mode_sig_bits[bc6h_mode_index][1], g_bc6h_mode_sig_bits[bc6h_mode_index][2], g_bc6h_mode_sig_bits[bc6h_mode_index][3] }; @@ -22998,7 +22998,7 @@ namespace basist const basist::half_float* pPixels, const vec3F* pFloat_pixels, const float* pPixel_scales, double& cur_error, basist::bc6h_logical_block& log_blk, int64_t block_max_var, - int mean_r, int mean_g, int mean_b, float block_axis_r, float block_axis_g, float block_axis_b, + int mean_r, int mean_g, int mean_b, float block_axis_r, float block_axis_g, float block_axis_b, const fast_bc6h_params& params) { assert((params.m_max_2subset_pats_to_try > 0) && (params.m_max_2subset_pats_to_try <= BC6H_NUM_PATS)); @@ -23019,7 +23019,7 @@ namespace basist } return; } - + uint32_t desired_pat_bits = 0; for (uint32_t i = 0; i < 16; i++) { @@ -23097,13 +23097,13 @@ namespace basist uint32_t omin_r = UINT32_MAX, omin_g = UINT32_MAX, omin_b = UINT32_MAX; uint32_t omax_r = 0, omax_g = 0, omax_b = 0; uint32_t total_r = 0, total_g = 0, total_b = 0; - + for (uint32_t i = 0; i < 16; i++) { uint32_t r = pPixels[i * 3 + 0]; uint32_t g = pPixels[i * 3 + 1]; uint32_t b = pPixels[i * 3 + 2]; - + total_r += r; total_g += g; total_b += b; @@ -23128,13 +23128,13 @@ namespace basist log_blk.m_endpoints[2][0] = basist::bc6h_half_to_blog16((basist::half_float)omin_b); log_blk.m_endpoints[2][1] = 0; - + log_blk.m_mode = 13; pack_bc6h_block(*pBlock, log_blk); return; } - + uint32_t min_r, min_g, min_b, max_r, max_g, max_b; int mean_r = (total_r + 8) / 16; @@ -23156,9 +23156,9 @@ namespace basist icov[4] += g * b; icov[5] += b * b; } - + int64_t block_max_var = basisu::maximum(icov[0], icov[3], icov[5]); // not divided by 16, i.e. scaled by 16 - + if (block_max_var < (FAST_BC6H_STD_DEV_THRESH * FAST_BC6H_STD_DEV_THRESH * 16)) { // Simple block @@ -23253,7 +23253,7 @@ namespace basist uint32_t min_idx = 0, max_idx = 0; float min_dot = basisu::BIG_FLOAT_VAL, max_dot = -basisu::BIG_FLOAT_VAL; - + for (uint32_t i = 0; i < 16; i++) { float r = (float)pPixels[i * 3 + 0]; @@ -23294,7 +23294,7 @@ namespace basist bc6h_quant_dequant_endpoints(min_r, min_g, min_b, max_r, max_g, max_b, 10); cur_err = assign_weights_4(float_pixels, pixel_scales, log_blk.m_weights, min_r, min_g, min_b, max_r, max_g, max_b, block_max_var, try_2subsets, params); - + const uint32_t MAX_LS_PASSES = params.m_hq_ls ? 2 : 1; for (uint32_t pass = 0; pass < MAX_LS_PASSES; pass++) { @@ -23370,7 +23370,7 @@ namespace basist min_b = trial_min_b; max_b = trial_max_b; - + memcpy(log_blk.m_weights, trial_weights, 16); } else @@ -23412,7 +23412,7 @@ namespace basist std::swap(log_blk.m_endpoints[c][0], log_blk.m_endpoints[c][1]); } } - + if ((params.m_max_2subset_pats_to_try > 0) && ((try_2subsets) && (block_max_var > (FAST_BC6H_COMPLEX_STD_DEV_THRESH * FAST_BC6H_COMPLEX_STD_DEV_THRESH * 16)))) { fast_encode_bc6h_2subsets(pPixels, float_pixels, pixel_scales, cur_err, log_blk, block_max_var, mean_r, mean_g, mean_b, axis_r, axis_g, axis_b, params); diff --git a/transcoder/basisu_transcoder.h b/transcoder/basisu_transcoder.h index 4667943e..3f076f6e 100644 --- a/transcoder/basisu_transcoder.h +++ b/transcoder/basisu_transcoder.h @@ -22,7 +22,7 @@ #define BASISD_SUPPORT_KTX2 1 #endif -// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support +// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support #ifndef BASISD_SUPPORT_KTX2_ZSTD #define BASISD_SUPPORT_KTX2_ZSTD 1 #endif @@ -42,7 +42,7 @@ namespace basist // High-level composite texture formats supported by the transcoder. // Each of these texture formats directly correspond to OpenGL/D3D/Vulkan etc. texture formats. // Notes: - // - If you specify a texture format that supports alpha, but the .basis file doesn't have alpha, the transcoder will automatically output a + // - If you specify a texture format that supports alpha, but the .basis file doesn't have alpha, the transcoder will automatically output a // fully opaque (255) alpha channel. // - The PVRTC1 texture formats only support power of 2 dimension .basis files, but this may be relaxed in a future version. // - The PVRTC1 transcoders are real-time encoders, so don't expect the highest quality. We may add a slower encoder with improved quality. @@ -67,12 +67,12 @@ namespace basist cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format. // ASTC (mobile, Intel devices, hopefully all desktop GPU's one day) - cTFASTC_4x4_RGBA = 10, // LDR. Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. + cTFASTC_4x4_RGBA = 10, // LDR. Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. // LDR: Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions. // ATC (mobile, Adreno devices, this is a niche format) cTFATC_RGB = 11, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD) - cTFATC_RGBA = 12, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD) + cTFATC_RGBA = 12, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD) // FXT1 (desktop, Intel devices, this is a super obscure format) cTFFXT1_RGB = 17, // Opaque only, uses exclusively CC_MIXED blocks. Notable for having a 8x4 block size. GL_3DFX_texture_compression_FXT1 is supported on Intel integrated GPU's (such as HD 630). @@ -94,7 +94,7 @@ namespace basist cTFRGB565 = 14, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11 cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0 cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0 - + // Note these uncompressed formats (HALF and 9E5) can only be transcoded to from HDR input files (UASTC HDR 4x4 or ASTC HDR 6x6). cTFRGB_HALF = 24, // 48bpp RGB half (16-bits/component, 3 components) cTFRGBA_HALF = 25, // 64bpp RGBA half (16-bits/component, 4 components) (A will always currently 1.0, UASTC_HDR doesn't support alpha) @@ -167,10 +167,10 @@ namespace basist // Returns the block width/height for the specified basis texture file format. uint32_t basis_tex_format_get_block_width(basis_tex_format fmt); uint32_t basis_tex_format_get_block_height(basis_tex_format fmt); - + bool basis_tex_format_is_hdr(basis_tex_format fmt); inline bool basis_tex_format_is_ldr(basis_tex_format fmt) { return !basis_tex_format_is_hdr(fmt); } - + // Validates that the output buffer is large enough to hold the entire transcoded texture. // For uncompressed texture formats, most input parameters are in pixels, not blocks. Blocks are 4x4 pixels. bool basis_validate_output_buffer_size(transcoder_texture_format target_format, @@ -199,7 +199,7 @@ namespace basist basisu::vector m_block_endpoint_preds[2]; enum { cMaxPrevFrameLevels = 16 }; - basisu::vector m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index] + basisu::vector m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index] void clear() { @@ -214,7 +214,7 @@ namespace basist }; // Low-level helper classes that do the actual transcoding. - + // ETC1S class basisu_lowlevel_etc1s_transcoder { @@ -279,13 +279,13 @@ namespace basist typedef basisu::vector selector_vec; const selector_vec& get_selectors() const { return m_local_selectors; } - + private: const basisu_lowlevel_etc1s_transcoder* m_pGlobal_codebook; endpoint_vec m_local_endpoints; selector_vec m_local_selectors; - + huffman_decoding_table m_endpoint_pred_model, m_delta_endpoint_model, m_selector_model, m_selector_history_buf_rle_model; uint32_t m_selector_history_buf_size; @@ -306,7 +306,7 @@ namespace basist // This flag is used internally when decoding to BC3. cDecodeFlagsBC1ForbidThreeColorBlocks = 8, - // The output buffer contains alpha endpoint/selector indices. + // The output buffer contains alpha endpoint/selector indices. // Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format. cDecodeFlagsOutputHasAlphaIndices = 16, @@ -499,7 +499,7 @@ namespace basist uint32_t m_orig_width; uint32_t m_orig_height; - + uint32_t m_width; uint32_t m_height; @@ -639,11 +639,11 @@ namespace basist // transcode_image_level() decodes a single mipmap level from the .basis file to any of the supported output texture formats. // It'll first find the slice(s) to transcode, then call transcode_slice() one or two times to decode both the color and alpha texture data (or RG texture data from two slices for BC5). // If the .basis file doesn't have alpha slices, the output alpha blocks will be set to fully opaque (all 255's). - // Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements. + // Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements. // output_blocks_buf_size_in_blocks_or_pixels should be at least the image level's total_blocks (num_blocks_x * num_blocks_y), or the total number of output pixels if fmt==cTFRGBA32 etc. // output_row_pitch_in_blocks_or_pixels: Number of blocks or pixels per row. If 0, the transcoder uses the slice's num_blocks_x or orig_width (NOT num_blocks_x * 4). Ignored for PVRTC1 (due to texture swizzling). // output_rows_in_pixels: Ignored unless fmt is uncompressed (cRGBA32, etc.). The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4). - // Notes: + // Notes: // - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function. // - This method assumes the output texture buffer is readable. In some cases to handle alpha, the transcoder will write temporary data to the output texture in // a first pass, which will be read in a second pass. @@ -701,7 +701,7 @@ namespace basist // basisu_transcoder_init() MUST be called before a .basis file can be transcoded. void basisu_transcoder_init(); - + enum debug_flags_t { cDebugFlagVisCRs = 1, @@ -711,10 +711,10 @@ namespace basist uint32_t get_debug_flags(); void set_debug_flags(uint32_t f); - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ // Optional .KTX2 file format support // KTX2 reading optionally requires miniz or Zstd decompressors for supercompressed UASTC files. - // ------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------ #if BASISD_SUPPORT_KTX2 #pragma pack(push) #pragma pack(1) @@ -779,7 +779,7 @@ namespace basist #pragma pack(pop) const uint32_t KTX2_VK_FORMAT_UNDEFINED = 0; - + // These are standard Vulkan texture VkFormat ID's, see https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkFormat.html const uint32_t KTX2_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000; const uint32_t KTX2_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001; @@ -794,7 +794,7 @@ namespace basist const uint32_t KTX2_KDF_DF_MODEL_UASTC_LDR_4X4 = 166; // 0xA6 const uint32_t KTX2_KDF_DF_MODEL_UASTC_HDR_4X4 = 167; // 0xA7 const uint32_t KTX2_KDF_DF_MODEL_ASTC_HDR_6X6_INTERMEDIATE = 168; // 0xA8, TODO - coordinate with Khronos on this - + const uint32_t KTX2_IMAGE_IS_P_FRAME = 2; const uint32_t KTX2_UASTC_BLOCK_SIZE = 16; // also the block size for UASTC_HDR const uint32_t KTX2_MAX_SUPPORTED_LEVEL_COUNT = 16; // this is an implementation specific constraint and can be increased @@ -878,12 +878,12 @@ namespace basist { case KTX2_DF_PRIMARIES_UNSPECIFIED: return "UNSPECIFIED"; case KTX2_DF_PRIMARIES_BT709: return "BT709"; - case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU"; + case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU"; case KTX2_DF_PRIMARIES_BT601_SMPTE: return "SMPTE"; case KTX2_DF_PRIMARIES_BT2020: return "BT2020"; case KTX2_DF_PRIMARIES_CIEXYZ: return "CIEXYZ"; case KTX2_DF_PRIMARIES_ACES: return "ACES"; - case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC"; + case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC"; case KTX2_DF_PRIMARIES_NTSC1953: return "NTSC1953"; case KTX2_DF_PRIMARIES_PAL525: return "PAL525"; case KTX2_DF_PRIMARIES_DISPLAYP3: return "DISPLAYP3"; @@ -891,7 +891,7 @@ namespace basist default: break; } return "?"; - } + } // Information about a single 2D texture "image" in a KTX2 file. struct ktx2_image_level_info @@ -908,7 +908,7 @@ namespace basist // The image's physical width/height, which will always be divisible by 4 pixels. uint32_t m_width; uint32_t m_height; - + // The texture's dimensions in 4x4 or 6x6 texel blocks. uint32_t m_num_blocks_x; uint32_t m_num_blocks_y; @@ -926,7 +926,7 @@ namespace basist // true if the image is an I-Frame. Currently, for ETC1S textures, the first frame will always be an I-Frame, and subsequent frames will always be P-Frames. bool m_iframe_flag; }; - + // Thread-specific ETC1S/supercompressed UASTC transcoder state. (If you're not doing multithreading transcoding you can ignore this.) struct ktx2_transcoder_state { @@ -944,9 +944,9 @@ namespace basist // This class is quite similar to basisu_transcoder. It treats KTX2 files as a simple container for ETC1S/UASTC texture data. // It does not support 1D or 3D textures. - // It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files. + // It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files. // It only supports raw non-supercompressed UASTC, ETC1S, UASTC+Zstd, or UASTC+zlib compressed files. - // DFD (Data Format Descriptor) parsing is purposely as simple as possible. + // DFD (Data Format Descriptor) parsing is purposely as simple as possible. // If you need to know how to interpret the texture channels you'll need to parse the DFD yourself after calling get_dfd(). class ktx2_transcoder { @@ -1032,7 +1032,7 @@ namespace basist // Returns the DFD color primary. // We do not validate the color primaries, so the returned value may not be in the ktx2_df_color_primaries enum. ktx2_df_color_primaries get_dfd_color_primaries() const { return m_dfd_color_prims; } - + // Returns KTX2_KHR_DF_TRANSFER_LINEAR or KTX2_KHR_DF_TRANSFER_SRGB. uint32_t get_dfd_transfer_func() const { return m_dfd_transfer_func; } @@ -1040,9 +1040,9 @@ namespace basist // Returns 1 (ETC1S/UASTC) or 2 (ETC1S with an internal alpha channel). uint32_t get_dfd_total_samples() const { return m_dfd_samples; } - - // Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two. - // Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that. + + // Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two. + // Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that. // It's up to the caller to decide what to do if the value isn't in the enum. ktx2_df_channel_id get_dfd_channel_id0() const { return m_dfd_chan0; } ktx2_df_channel_id get_dfd_channel_id1() const { return m_dfd_chan1; } @@ -1050,11 +1050,11 @@ namespace basist // Key value field data. struct key_value { - // The key field is UTF8 and always zero terminated. + // The key field is UTF8 and always zero terminated. // In memory we always append a zero terminator to the key. basisu::uint8_vec m_key; - // The value may be empty. In the KTX2 file it consists of raw bytes which may or may not be zero terminated. + // The value may be empty. In the KTX2 file it consists of raw bytes which may or may not be zero terminated. // In memory we always append a zero terminator to the value. basisu::uint8_vec m_value; @@ -1084,21 +1084,21 @@ namespace basist // is_video() is only valid after start_transcoding() is called. // For ETC1S data, if this returns true you must currently transcode the file from first to last frame, in order, without skipping any frames. bool is_video() const { return m_is_video; } - + // Defaults to 0, only non-zero if the key existed in the source KTX2 file. float get_ldr_hdr_upconversion_nit_multiplier() const { return m_ldr_hdr_upconversion_nit_multiplier; } - + // start_transcoding() MUST be called before calling transcode_image(). // This method decompresses the ETC1S global endpoint/selector codebooks, which is not free, so try to avoid calling it excessively. bool start_transcoding(); - + // get_image_level_info() be called after init(), but the m_iframe_flag's won't be valid until start_transcoding() is called. // You can call this method before calling transcode_image_level() to retrieve basic information about the mipmap level's dimensions, etc. bool get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const; // transcode_image_level() transcodes a single 2D texture or cubemap face from the KTX2 file. // Internally it uses the same low-level transcode API's as basisu_transcoder::transcode_image_level(). - // If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is + // If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is // completely transcoded before switching to another level. Every time the mipmap level is changed all supercompressed level data must be decompressed using Zstandard as a single unit. // Currently ETC1S videos must always be transcoded from first to last frame (or KTX2 "layer"), in order, with no skipping of frames. // By default this method is not thread safe unless you specify a pointer to a user allocated thread-specific transcoder_state struct. @@ -1108,7 +1108,7 @@ namespace basist basist::transcoder_texture_format fmt, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, ktx2_transcoder_state *pState = nullptr); - + private: const uint8_t* m_pData; uint32_t m_data_size; @@ -1117,26 +1117,26 @@ namespace basist basisu::vector m_levels; basisu::uint8_vec m_dfd; key_value_vec m_key_values; - + ktx2_etc1s_global_data_header m_etc1s_header; basisu::vector m_etc1s_image_descs; basisu::vector m_astc_6x6_intermediate_image_descs; basist::basis_tex_format m_format; - + uint32_t m_dfd_color_model; ktx2_df_color_primaries m_dfd_color_prims; uint32_t m_dfd_transfer_func; uint32_t m_dfd_flags; uint32_t m_dfd_samples; ktx2_df_channel_id m_dfd_chan0, m_dfd_chan1; - + basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder; basist::basisu_lowlevel_uastc_ldr_4x4_transcoder m_uastc_transcoder; basist::basisu_lowlevel_uastc_hdr_4x4_transcoder m_uastc_hdr_transcoder; basist::basisu_lowlevel_astc_hdr_6x6_transcoder m_astc_hdr_6x6_transcoder; basist::basisu_lowlevel_astc_hdr_6x6_intermediate_transcoder m_astc_hdr_6x6_intermediate_transcoder; - + ktx2_transcoder_state m_def_transcoder_state; bool m_has_alpha; @@ -1165,7 +1165,7 @@ namespace basist break; } } - + if (!p) p = key_values.enlarge(1); @@ -1189,4 +1189,3 @@ namespace basist bool basisu_transcoder_supports_ktx2_zstd(); } // namespace basisu - diff --git a/transcoder/basisu_transcoder_internal.h b/transcoder/basisu_transcoder_internal.h index 8bf4abad..5480ba32 100644 --- a/transcoder/basisu_transcoder_internal.h +++ b/transcoder/basisu_transcoder_internal.h @@ -46,9 +46,9 @@ namespace basist // You probably don't care about these enum's unless you are going pretty low-level and calling the transcoder to decode individual slices. enum class block_format { - cETC1, // ETC1S RGB + cETC1, // ETC1S RGB cETC2_RGBA, // full ETC2 EAC RGBA8 block - cBC1, // DXT1 RGB + cBC1, // DXT1 RGB cBC3, // BC4 block followed by a four color BC1 block cBC4, // DXT5A (alpha block only) cBC5, // two BC4 blocks @@ -58,9 +58,9 @@ namespace basist cBC7_M5_COLOR, // RGB BC7 mode 5 color (writes an opaque mode 5 block) cBC7_M5_ALPHA, // alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.) cETC2_EAC_A8, // alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format) - cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC + cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC // data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking. - + cATC_RGB, cATC_RGBA_INTERPOLATED_ALPHA, cFXT1_RGB, // Opaque-only, has oddball 8x4 pixel block size @@ -70,16 +70,16 @@ namespace basist cETC2_EAC_R11, cETC2_EAC_RG11, - + cIndices, // Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits) cRGB32, // Writes RGB components to 32bpp output pixels cRGBA32, // Writes RGB255 components to 32bpp output pixels cA32, // Writes alpha component to 32bpp output pixels - + cRGB565, cBGR565, - + cRGBA4444_COLOR, cRGBA4444_ALPHA, cRGBA4444_COLOR_OPAQUE, @@ -93,7 +93,7 @@ namespace basist cBC6H, cASTC_HDR_4x4, cASTC_HDR_6x6, - + cTotalBlockFormats }; @@ -140,9 +140,9 @@ namespace basist const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_THRESH = 3; const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_BITS = 6; const uint32_t SELECTOR_HISTORY_BUF_RLE_COUNT_TOTAL = (1 << SELECTOR_HISTORY_BUF_RLE_COUNT_BITS); - + uint16_t crc16(const void *r, size_t size, uint16_t crc); - + class huffman_decoding_table { friend class bitwise_decoder; @@ -260,7 +260,7 @@ namespace basist return false; else if (idx >= (int)m_tree.size()) m_tree.resize(idx + 1); - + if (!m_tree[idx]) { m_tree[idx] = (int16_t)tree_next; @@ -429,14 +429,14 @@ namespace basist for (;;) { uint32_t k = peek_bits(16); - + uint32_t l = 0; while (k & 1) { l++; k >>= 1; } - + q += l; remove_bits(l); @@ -454,7 +454,7 @@ namespace basist const uint32_t chunk_size = 1 << chunk_bits; const uint32_t chunk_mask = chunk_size - 1; - + uint32_t v = 0; uint32_t ofs = 0; @@ -466,7 +466,7 @@ namespace basist if ((s & chunk_size) == 0) break; - + if (ofs >= 32) { assert(0); @@ -482,7 +482,7 @@ namespace basist assert(ct.m_code_sizes.size()); const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits; - + while (m_bit_buf_size < 16) { uint32_t c = 0; @@ -493,7 +493,7 @@ namespace basist m_bit_buf_size += 8; assert(m_bit_buf_size <= 32); } - + int code_len; int sym; @@ -684,7 +684,7 @@ namespace basist }; struct decoder_etc_block; - + inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); @@ -708,7 +708,7 @@ namespace basist }; uint8_t c[4]; - + uint32_t m; }; @@ -989,7 +989,7 @@ namespace basist extern const uint8_t g_bc6h_weight4[16]; extern const int8_t g_bc6h_mode_lookup[32]; - + // Converts b16 to half float inline half_float bc6h_blog16_to_half(uint32_t comp) { @@ -1003,7 +1003,7 @@ namespace basist const uint32_t MAX_BC6H_HALF_FLOAT_AS_UINT = 0x7BFF; // Inverts bc6h_blog16_to_half(). - // Returns the nearest blog16 given a half value. + // Returns the nearest blog16 given a half value. inline uint32_t bc6h_half_to_blog16(half_float h) { assert(h <= MAX_BC6H_HALF_FLOAT_AS_UINT); @@ -1044,13 +1044,10 @@ namespace basist }; void pack_bc6h_block(bc6h_block& dst_blk, bc6h_logical_block& log_blk); - + namespace bc7_mode_5_encoder { void encode_bc7_mode_5_block(void* pDst_block, color32* pPixels, bool hq_mode); } - -} // namespace basist - - +} // namespace basist diff --git a/transcoder/basisu_transcoder_uastc.h b/transcoder/basisu_transcoder_uastc.h index 457bd51e..c1d01864 100644 --- a/transcoder/basisu_transcoder_uastc.h +++ b/transcoder/basisu_transcoder_uastc.h @@ -5,8 +5,8 @@ namespace basist { struct color_quad_u8 - { - uint8_t m_c[4]; + { + uint8_t m_c[4]; }; const uint32_t TOTAL_UASTC_MODES = 19; @@ -102,9 +102,9 @@ namespace basist int m_ccs; // color component selector (dual plane only) bool m_dual_plane; // true if dual plane - // Weight and endpoint BISE values. + // Weight and endpoint BISE values. // Note these values are NOT linear, they must be BISE encoded. See Table 97 and Table 107. - uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order + uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order uint8_t m_weights[64]; // weight index values, raster order, in P0 P1, P0 P1, etc. or P0, P0, P0, P0, etc. order }; @@ -199,7 +199,7 @@ namespace basist #ifdef _DEBUG int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block); #endif - + struct uastc_block { union @@ -235,10 +235,10 @@ namespace basist }; color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock); - + struct decoder_etc_block; struct eac_block; - + bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb); bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb); @@ -260,7 +260,7 @@ namespace basist // Packs 16 scalar values to BC4. Same PSNR as stb_dxt's BC4 encoder, around 13% faster. void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride); - + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb); enum @@ -270,7 +270,7 @@ namespace basist cEncodeBC1UseSelectors = 4, }; void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags); - + // Alternate PCA-free encoder, around 15% faster, same (or slightly higher) avg. PSNR void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags); @@ -287,7 +287,7 @@ namespace basist bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha); bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality); - + // uastc_init() MUST be called before using this module. void uastc_init(); diff --git a/webgl/README.md b/webgl/README.md index 66f8795c..2d655eb9 100644 --- a/webgl/README.md +++ b/webgl/README.md @@ -45,7 +45,7 @@ extension that is [currently in development](https://github.com/KhronosGroup/glT Live demo: [`ktx2_encode_test/index.html'](https://subquantumtech.com/uastchdr2/ktx2_encode_test/) -This demo shows how to use the compressor from JavaScript. To use it, select a .PNG file then hit the "Encode!" button. The compressor will dynamically generate a .ktx2 file in memory which will then be immediately transcoded and displayed. Hit the "Download!" button to locally download the generated .ktx2 file. +This demo shows how to use the compressor from JavaScript. To use it, select a .PNG file then hit the "Encode!" button. The compressor will dynamically generate a .ktx2 file in memory which will then be immediately transcoded and displayed. Hit the "Download!" button to locally download the generated .ktx2 file. To view the compressor's textual debug output, open your browser's developer debug console (under Developer Tools in Chrome) and enable the Debug checkbox before hitting the "Encode!" button. Multithreading is not currently supported when the compressor is compiled to WebAssembly, so compression will be slower than using the stand-alone command line tool. @@ -59,4 +59,4 @@ You can locally host the files under the "webgl" folder. One way is to use [Pyth cd webgl python3 -m http.server 8000 ``` -Note: For WASM multithreading to be available and enabled, the server must be properly configured. +Note: For WASM multithreading to be available and enabled, the server must be properly configured. diff --git a/webgl/encoder/CMakeLists.txt b/webgl/encoder/CMakeLists.txt index 3b16c5b8..2b6cd759 100644 --- a/webgl/encoder/CMakeLists.txt +++ b/webgl/encoder/CMakeLists.txt @@ -10,27 +10,27 @@ message("KTX2_ZSTANDARD=${KTX2_ZSTANDARD}") if (EMSCRIPTEN) set(CMAKE_CXX_STANDARD 17) - + set(SRC_LIST ../transcoder/basis_wrappers.cpp ../../transcoder/basisu_transcoder.cpp - ../../encoder/basisu_backend.cpp - ../../encoder/basisu_basis_file.cpp - ../../encoder/basisu_comp.cpp - ../../encoder/basisu_enc.cpp - ../../encoder/basisu_etc.cpp - ../../encoder/basisu_frontend.cpp - ../../encoder/basisu_gpu_texture.cpp - ../../encoder/basisu_pvrtc1_4.cpp - ../../encoder/basisu_resampler.cpp - ../../encoder/basisu_resample_filters.cpp - ../../encoder/basisu_ssim.cpp - ../../encoder/basisu_uastc_enc.cpp + ../../encoder/basisu_backend.cpp + ../../encoder/basisu_basis_file.cpp + ../../encoder/basisu_comp.cpp + ../../encoder/basisu_enc.cpp + ../../encoder/basisu_etc.cpp + ../../encoder/basisu_frontend.cpp + ../../encoder/basisu_gpu_texture.cpp + ../../encoder/basisu_pvrtc1_4.cpp + ../../encoder/basisu_resampler.cpp + ../../encoder/basisu_resample_filters.cpp + ../../encoder/basisu_ssim.cpp + ../../encoder/basisu_uastc_enc.cpp ../../encoder/basisu_bc7enc.cpp ../../encoder/basisu_kernels_sse.cpp ../../encoder/basisu_opencl.cpp ../../encoder/pvpngreader.cpp - ../../encoder/jpgd.cpp + ../../encoder/jpgd.cpp ../../encoder/3rdparty/android_astc_decomp.cpp ../../encoder/basisu_uastc_hdr_4x4_enc.cpp ../../encoder/basisu_astc_hdr_6x6_enc.cpp @@ -46,30 +46,30 @@ if (EMSCRIPTEN) else() set(ZSTD_DEFINITION BASISD_SUPPORT_KTX2_ZSTD=0) endif() - + # No threading version add_executable(basis_encoder.js ${SRC_LIST}) #target_compile_definitions(basis_encoder.js PRIVATE NDEBUG BASISD_SUPPORT_UASTC=1 BASISD_SUPPORT_BC7=1 BASISD_SUPPORT_ATC=0 BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY=0 BASISD_SUPPORT_PVRTC2=0 BASISD_SUPPORT_FXT1=0 BASISD_SUPPORT_ETC2_EAC_RG11=0 BASISU_SUPPORT_ENCODING=1 BASISU_SUPPORT_SSE=0 ${ZSTD_DEFINITION} ) #target_compile_options(basis_encoder.js PRIVATE -fno-strict-aliasing -O3) - + #target_compile_definitions(basis_encoder.js PRIVATE DEBUG BASISD_SUPPORT_UASTC=1 BASISD_SUPPORT_BC7=1 BASISD_SUPPORT_ATC=0 BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY=0 BASISD_SUPPORT_PVRTC2=0 BASISD_SUPPORT_FXT1=0 BASISD_SUPPORT_ETC2_EAC_RG11=0 BASISU_SUPPORT_ENCODING=1 BASISU_SUPPORT_SSE=0 ${ZSTD_DEFINITION} ) #target_compile_options(basis_encoder.js PRIVATE -fno-strict-aliasing -g -O1 -fsanitize=undefined -fsanitize=address) - - # debug options + + # debug options #target_compile_definitions(basis_encoder.js PRIVATE DEBUG BASISD_SUPPORT_UASTC=1 BASISD_SUPPORT_BC7=1 BASISD_SUPPORT_ATC=0 BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY=0 BASISD_SUPPORT_PVRTC2=0 BASISD_SUPPORT_FXT1=0 BASISD_SUPPORT_ETC2_EAC_RG11=0 BASISU_SUPPORT_ENCODING=1 BASISU_SUPPORT_SSE=0 ${ZSTD_DEFINITION} ) #target_compile_options(basis_encoder.js PRIVATE -fno-strict-aliasing -g -O0) - + # release options target_compile_definitions(basis_encoder.js PRIVATE NDEBUG BASISD_SUPPORT_UASTC=1 BASISD_SUPPORT_BC7=1 BASISD_SUPPORT_ATC=0 BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY=0 BASISD_SUPPORT_PVRTC2=0 BASISD_SUPPORT_FXT1=0 BASISD_SUPPORT_ETC2_EAC_RG11=0 BASISU_SUPPORT_ENCODING=1 BASISU_SUPPORT_SSE=0 ${ZSTD_DEFINITION} ) target_compile_options(basis_encoder.js PRIVATE -fno-strict-aliasing -O3) - + target_include_directories(basis_encoder.js PRIVATE ../../transcoder) set_target_properties(basis_encoder.js PROPERTIES OUTPUT_NAME "basis_encoder" SUFFIX ".js" - + #LINK_FLAGS "--bind -s INITIAL_MEMORY=536870912 -s ALLOW_MEMORY_GROWTH=1 -s STACK_SIZE=262144 -s MODULARIZE=1 -s EXPORT_NAME=BASIS") #LINK_FLAGS "--bind -s INITIAL_MEMORY=536870912 -g -s STACK_SIZE=262144 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=BASIS -fsanitize=undefined -fsanitize=address") #LINK_FLAGS "--bind -s INITIAL_MEMORY=536870912 -g -s STACK_SIZE=262144 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=BASIS -s ASSERTIONS=2") @@ -77,12 +77,12 @@ if (EMSCRIPTEN) add_executable(basis_encoder_threads.js ${SRC_LIST}) - # Threaded version + # Threaded version target_compile_definitions(basis_encoder_threads.js PRIVATE NDEBUG BASISD_SUPPORT_UASTC=1 BASISD_SUPPORT_BC7=1 BASISD_SUPPORT_ATC=0 BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY=0 BASISD_SUPPORT_PVRTC2=0 BASISD_SUPPORT_FXT1=0 BASISD_SUPPORT_ETC2_EAC_RG11=0 BASISU_SUPPORT_ENCODING=1 BASISU_SUPPORT_SSE=0 ${ZSTD_DEFINITION} WASM_THREADS_ENABLED=1 ) - target_include_directories(basis_encoder_threads.js PRIVATE ../../transcoder) - - target_compile_options(basis_encoder_threads.js PRIVATE -fno-strict-aliasing -O3 -matomics -mbulk-memory) - + target_include_directories(basis_encoder_threads.js PRIVATE ../../transcoder) + + target_compile_options(basis_encoder_threads.js PRIVATE -fno-strict-aliasing -O3 -matomics -mbulk-memory) + set_target_properties(basis_encoder_threads.js PROPERTIES OUTPUT_NAME "basis_encoder_threads" SUFFIX ".js" diff --git a/webgl/encoder/build/basis_encoder.js b/webgl/encoder/build/basis_encoder.js index 3fb6e1ae..89d91ce5 100644 --- a/webgl/encoder/build/basis_encoder.js +++ b/webgl/encoder/build/basis_encoder.js @@ -227,7 +227,7 @@ if (Module['quit']) quit_ = Module['quit']; // An online HTML version (which may be of a different version of Emscripten) // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html -var wasmBinary; +var wasmBinary; if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; // Wasm globals @@ -318,7 +318,7 @@ function preRun() { function initRuntime() { runtimeInitialized = true; - + if (!Module['noFSInit'] && !FS.init.initialized) FS.init(); FS.ignorePermissions = false; @@ -562,14 +562,14 @@ function createWasm() { function receiveInstance(instance, module) { wasmExports = instance.exports; - + wasmMemory = wasmExports['memory']; - + updateMemoryViews(); wasmTable = wasmExports['__indirect_function_table']; - + addOnInit(wasmExports['__wasm_call_ctors']); @@ -635,7 +635,7 @@ var tempI64; } }; - + /** * @param {number} ptr * @param {string} type @@ -657,7 +657,7 @@ var tempI64; var noExitRuntime = Module['noExitRuntime'] || true; - + /** * @param {number} ptr * @param {number} value @@ -688,56 +688,56 @@ var tempI64; this.excPtr = excPtr; this.ptr = excPtr - 24; } - + set_type(type) { HEAPU32[(((this.ptr)+(4))>>2)] = type; } - + get_type() { return HEAPU32[(((this.ptr)+(4))>>2)]; } - + set_destructor(destructor) { HEAPU32[(((this.ptr)+(8))>>2)] = destructor; } - + get_destructor() { return HEAPU32[(((this.ptr)+(8))>>2)]; } - + set_caught(caught) { caught = caught ? 1 : 0; HEAP8[(this.ptr)+(12)] = caught; } - + get_caught() { return HEAP8[(this.ptr)+(12)] != 0; } - + set_rethrown(rethrown) { rethrown = rethrown ? 1 : 0; HEAP8[(this.ptr)+(13)] = rethrown; } - + get_rethrown() { return HEAP8[(this.ptr)+(13)] != 0; } - + // Initialize native structure fields. Should be called once after allocated. init(type, destructor) { this.set_adjusted_ptr(0); this.set_type(type); this.set_destructor(destructor); } - + set_adjusted_ptr(adjustedPtr) { HEAPU32[(((this.ptr)+(16))>>2)] = adjustedPtr; } - + get_adjusted_ptr() { return HEAPU32[(((this.ptr)+(16))>>2)]; } - + // Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted // when the pointer is casted to some of the exception object base classes (e.g. when virtual // inheritance is used). When a pointer is thrown this method should return the thrown pointer @@ -754,9 +754,9 @@ var tempI64; return this.excPtr; } } - + var exceptionLast = 0; - + var uncaughtExceptionCount = 0; var ___cxa_throw = (ptr, type, destructor) => { var info = new ExceptionInfo(ptr); @@ -775,8 +775,8 @@ var tempI64; return ret; } var syscallGetVarargP = syscallGetVarargI; - - + + var PATH = { isAbs:(path) => path.charAt(0) === '/', splitPath:(filename) => { @@ -845,7 +845,7 @@ var tempI64; join:(...paths) => PATH.normalize(paths.join('/')), join2:(l, r) => PATH.normalize(l + '/' + r), }; - + var initRandomFill = () => { if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') { // for modern web browsers @@ -878,9 +878,9 @@ var tempI64; // Lazily init on the first invocation. return (randomFill = initRandomFill())(view); }; - - - + + + var PATH_FS = { resolve:(...args) => { var resolvedPath = '', @@ -934,10 +934,10 @@ var tempI64; return outputParts.join('/'); }, }; - - + + var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined; - + /** * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given * array that contains uint8 values, returns a copy of that string as a @@ -956,7 +956,7 @@ var tempI64; // (As a tiny code save trick, compare endPtr against endIdx using a negation, // so that undefined means Infinity) while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; - + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); } @@ -978,7 +978,7 @@ var tempI64; } else { u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); } - + if (u0 < 0x10000) { str += String.fromCharCode(u0); } else { @@ -988,9 +988,9 @@ var tempI64; } return str; }; - + var FS_stdin_getChar_buffer = []; - + var lengthBytesUTF8 = (str) => { var len = 0; for (var i = 0; i < str.length; ++i) { @@ -1011,13 +1011,13 @@ var tempI64; } return len; }; - + var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { // Parameter maxBytesToWrite is not optional. Negative values, 0, null, // undefined and false each don't write out any bytes. if (!(maxBytesToWrite > 0)) return 0; - + var startIdx = outIdx; var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. for (var i = 0; i < str.length; ++i) { @@ -1073,7 +1073,7 @@ var tempI64; var BUFSIZE = 256; var buf = Buffer.alloc(BUFSIZE); var bytesRead = 0; - + // For some reason we must suppress a closure warning here, even though // fd definitely exists on process.stdin, and is even the proper way to // get the fd of stdin, @@ -1082,7 +1082,7 @@ var tempI64; // so it is related to the surrounding code in some unclear manner. /** @suppress {missingProperties} */ var fd = process.stdin.fd; - + try { bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); } catch(e) { @@ -1092,7 +1092,7 @@ var tempI64; if (e.toString().includes('EOF')) bytesRead = 0; else throw e; } - + if (bytesRead > 0) { result = buf.slice(0, bytesRead).toString('utf-8'); } @@ -1254,13 +1254,13 @@ var tempI64; }, }, }; - - + + var zeroMemory = (address, size) => { HEAPU8.fill(0, address, address + size); return address; }; - + var alignMemory = (size, alignment) => { return Math.ceil(size / alignment) * alignment; }; @@ -1339,7 +1339,7 @@ var tempI64; // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. - node.contents = null; + node.contents = null; } else if (FS.isLink(node.mode)) { node.node_ops = MEMFS.ops_table.link.node; node.stream_ops = MEMFS.ops_table.link.stream; @@ -1505,11 +1505,11 @@ var tempI64; if (buffer.buffer === HEAP8.buffer) { canOwn = false; } - + if (!length) return 0; var node = stream.node; node.timestamp = Date.now(); - + if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? if (canOwn) { node.contents = buffer.subarray(offset, offset + length); @@ -1524,7 +1524,7 @@ var tempI64; return length; } } - + // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. MEMFS.expandFileStorage(node, position+length); if (node.contents.subarray && buffer.subarray) { @@ -1594,7 +1594,7 @@ var tempI64; }, }, }; - + /** @param {boolean=} noRunDep */ var asyncLoad = (url, onload, onerror, noRunDep) => { var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : ''; @@ -1613,17 +1613,17 @@ var tempI64; ); if (dep) addRunDependency(dep); }; - - + + var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => { FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn); }; - + var preloadPlugins = Module['preloadPlugins'] || []; var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => { // Ensure plugins are ready. if (typeof Browser != 'undefined') Browser.init(); - + var handled = false; preloadPlugins.forEach((plugin) => { if (handled) return; @@ -1663,7 +1663,7 @@ var tempI64; processData(url); } }; - + var FS_modeStringToFlags = (str) => { var flagModes = { 'r': 0, @@ -1679,16 +1679,16 @@ var tempI64; } return flags; }; - + var FS_getMode = (canRead, canWrite) => { var mode = 0; if (canRead) mode |= 292 | 73; if (canWrite) mode |= 146; return mode; }; - - - + + + var FS = { root:null, mounts:[], @@ -1790,43 +1790,43 @@ var tempI64; }, lookupPath(path, opts = {}) { path = PATH_FS.resolve(path); - + if (!path) return { path: '', node: null }; - + var defaults = { follow_mount: true, recurse_count: 0 }; opts = Object.assign(defaults, opts) - + if (opts.recurse_count > 8) { // max recursive lookup of 8 throw new FS.ErrnoError(32); } - + // split the absolute path var parts = path.split('/').filter((p) => !!p); - + // start at the root var current = FS.root; var current_path = '/'; - + for (var i = 0; i < parts.length; i++) { var islast = (i === parts.length-1); if (islast && opts.parent) { // stop resolving break; } - + current = FS.lookupNode(current, parts[i]); current_path = PATH.join2(current_path, parts[i]); - + // jump to the mount's root node if this is a mountpoint if (FS.isMountpoint(current)) { if (!islast || (islast && opts.follow_mount)) { current = current.mounted.root; } } - + // by default, lookupPath will not follow a symlink if it is the final path component. // setting opts.follow = true will override this behavior. if (!islast || opts.follow) { @@ -1834,17 +1834,17 @@ var tempI64; while (FS.isLink(current.mode)) { var link = FS.readlink(current_path); current_path = PATH_FS.resolve(PATH.dirname(current_path), link); - + var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count + 1 }); current = lookup.node; - + if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). throw new FS.ErrnoError(32); } } } } - + return { path: current_path, node: current }; }, getPath(node) { @@ -1861,7 +1861,7 @@ var tempI64; }, hashName(parentid, name) { var hash = 0; - + for (var i = 0; i < name.length; i++) { hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; } @@ -1904,9 +1904,9 @@ var tempI64; }, createNode(parent, name, mode, rdev) { var node = new FS.FSNode(parent, name, mode, rdev); - + FS.hashAddNode(node); - + return node; }, destroyNode(node) { @@ -2032,7 +2032,7 @@ var tempI64; }, getStream:(fd) => FS.streams[fd], createStream(stream, fd = -1) { - + // clone it, so we can return an instance of FSStream stream = Object.assign(new FS.FSStream(), stream); if (fd == -1) { @@ -2072,15 +2072,15 @@ var tempI64; getMounts(mount) { var mounts = []; var check = [mount]; - + while (check.length) { var m = check.pop(); - + mounts.push(m); - + check.push(...m.mounts); } - + return mounts; }, syncfs(populate, callback) { @@ -2088,21 +2088,21 @@ var tempI64; callback = populate; populate = false; } - + FS.syncFSRequests++; - + if (FS.syncFSRequests > 1) { err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); } - + var mounts = FS.getMounts(FS.root.mount); var completed = 0; - + function doCallback(errCode) { FS.syncFSRequests--; return callback(errCode); } - + function done(errCode) { if (errCode) { if (!done.errored) { @@ -2115,7 +2115,7 @@ var tempI64; doCallback(null); } }; - + // sync all mounts mounts.forEach((mount) => { if (!mount.type.syncfs) { @@ -2128,79 +2128,79 @@ var tempI64; var root = mountpoint === '/'; var pseudo = !mountpoint; var node; - + if (root && FS.root) { throw new FS.ErrnoError(10); } else if (!root && !pseudo) { var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - + mountpoint = lookup.path; // use the absolute path node = lookup.node; - + if (FS.isMountpoint(node)) { throw new FS.ErrnoError(10); } - + if (!FS.isDir(node.mode)) { throw new FS.ErrnoError(54); } } - + var mount = { type, opts, mountpoint, mounts: [] }; - + // create a root node for the fs var mountRoot = type.mount(mount); mountRoot.mount = mount; mount.root = mountRoot; - + if (root) { FS.root = mountRoot; } else if (node) { // set as a mountpoint node.mounted = mount; - + // add the new mount to the current mount's children if (node.mount) { node.mount.mounts.push(mount); } } - + return mountRoot; }, unmount(mountpoint) { var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - + if (!FS.isMountpoint(lookup.node)) { throw new FS.ErrnoError(28); } - + // destroy the nodes for this mount, and all its child mounts var node = lookup.node; var mount = node.mounted; var mounts = FS.getMounts(mount); - + Object.keys(FS.nameTable).forEach((hash) => { var current = FS.nameTable[hash]; - + while (current) { var next = current.name_next; - + if (mounts.includes(current.mount)) { FS.destroyNode(current); } - + current = next; } }); - + // no longer a mountpoint node.mounted = null; - + // remove this mount from the child mounts var idx = node.mount.mounts.indexOf(mount); node.mount.mounts.splice(idx, 1); @@ -2283,13 +2283,13 @@ var tempI64; var new_name = PATH.basename(new_path); // parents must exist var lookup, old_dir, new_dir; - + // let the errors from non existent directories percolate up lookup = FS.lookupPath(old_path, { parent: true }); old_dir = lookup.node; lookup = FS.lookupPath(new_path, { parent: true }); new_dir = lookup.node; - + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); // need to be part of the same mount if (old_dir.mount !== new_dir.mount) { @@ -2350,7 +2350,7 @@ var tempI64; // do the underlying fs rename try { old_dir.node_ops.rename(old_node, new_dir, new_name); - // update old node (we do this here to avoid each backend + // update old node (we do this here to avoid each backend // needing to) old_node.parent = new_dir; } catch (e) { @@ -2590,7 +2590,7 @@ var tempI64; } // we've already handled these, don't pass down to the underlying vfs flags &= ~(128 | 512 | 131072); - + // register the stream with the filesystem var stream = FS.createStream({ node, @@ -2870,7 +2870,7 @@ var tempI64; // TODO deprecate the old functionality of a single // input / output callback and that utilizes FS.createDevice // and instead require a unique set of stream ops - + // by default, we symlink the standard streams to the // default tty devices. however, if the standard streams // have been overwritten we create a unique device for @@ -2890,7 +2890,7 @@ var tempI64; } else { FS.symlink('/dev/tty1', '/dev/stderr'); } - + // open default streams for the stdin, stdout and stderr devices var stdin = FS.open('/dev/stdin', 0); var stdout = FS.open('/dev/stdout', 1); @@ -2902,27 +2902,27 @@ var tempI64; FS.genericErrors[code] = new FS.ErrnoError(code); FS.genericErrors[code].stack = ''; }); - + FS.nameTable = new Array(4096); - + FS.mount(MEMFS, {}, '/'); - + FS.createDefaultDirectories(); FS.createDefaultDevices(); FS.createSpecialDirectories(); - + FS.filesystems = { 'MEMFS': MEMFS, }; }, init(input, output, error) { FS.init.initialized = true; - + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here Module['stdin'] = input || Module['stdin']; Module['stdout'] = output || Module['stdout']; Module['stderr'] = error || Module['stderr']; - + FS.createStandardStreams(); }, quit() { @@ -3111,27 +3111,27 @@ var tempI64; var header; var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; - + var chunkSize = 1024*1024; // Chunk size in bytes - + if (!hasByteServing) chunkSize = datalength; - + // Function to get a range from the remote URL. var doXHR = (from, to) => { if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); - + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); - + // Some hints to the browser that we want binary data. xhr.responseType = 'arraybuffer'; if (xhr.overrideMimeType) { xhr.overrideMimeType('text/plain; charset=x-user-defined'); } - + xhr.send(null); if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); if (xhr.response !== undefined) { @@ -3150,7 +3150,7 @@ var tempI64; if (typeof lazyArray.chunks[chunkNum] == 'undefined') throw new Error('doXHR failed!'); return lazyArray.chunks[chunkNum]; }); - + if (usesGzip || !datalength) { // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file @@ -3158,7 +3158,7 @@ var tempI64; chunkSize = datalength; out("LazyFiles on gzip forces download of the whole file when length is accessed"); } - + this._length = datalength; this._chunkSize = chunkSize; this.lengthKnown = true; @@ -3176,7 +3176,7 @@ var tempI64; return this._chunkSize; } } - + if (typeof XMLHttpRequest != 'undefined') { if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; var lazyArray = new LazyUint8Array(); @@ -3184,7 +3184,7 @@ var tempI64; } else { var properties = { isDevice: false, url: url }; } - + var node = FS.createFile(parent, name, properties, canRead, canWrite); // This is a total hack, but I want to get this lazy file code out of the // core of MEMFS. If we want to keep this lazy file concept I feel it should @@ -3246,8 +3246,8 @@ var tempI64; return node; }, }; - - + + /** * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the * emscripten HEAP, returns a copy of that string as a Javascript String object. @@ -3335,7 +3335,7 @@ var tempI64; function ___syscall_fcntl64(fd, cmd, varargs) { SYSCALLS.varargs = varargs; try { - + var stream = SYSCALLS.getStreamFromFD(fd); switch (cmd) { case 0: { @@ -3380,7 +3380,7 @@ var tempI64; function ___syscall_fstat64(fd, buf) { try { - + var stream = SYSCALLS.getStreamFromFD(fd); return SYSCALLS.doStat(FS.stat, stream.path, buf); } catch (e) { @@ -3389,11 +3389,11 @@ var tempI64; } } - + function ___syscall_ioctl(fd, op, varargs) { SYSCALLS.varargs = varargs; try { - + var stream = SYSCALLS.getStreamFromFD(fd); switch (op) { case 21509: { @@ -3487,7 +3487,7 @@ var tempI64; function ___syscall_lstat64(path, buf) { try { - + path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.lstat, path, buf); } catch (e) { @@ -3498,7 +3498,7 @@ var tempI64; function ___syscall_newfstatat(dirfd, path, buf, flags) { try { - + path = SYSCALLS.getStr(path); var nofollow = flags & 256; var allowEmpty = flags & 4096; @@ -3511,11 +3511,11 @@ var tempI64; } } - + function ___syscall_openat(dirfd, path, flags, varargs) { SYSCALLS.varargs = varargs; try { - + path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); var mode = varargs ? syscallGetVarargI() : 0; @@ -3528,7 +3528,7 @@ var tempI64; function ___syscall_stat64(path, buf) { try { - + path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.stat, path, buf); } catch (e) { @@ -3543,7 +3543,7 @@ var tempI64; var structRegistrations = { }; - + var runDestructors = (destructors) => { while (destructors.length) { var ptr = destructors.pop(); @@ -3551,28 +3551,28 @@ var tempI64; del(ptr); } }; - + /** @suppress {globalThis} */ function readPointer(pointer) { return this['fromWireType'](HEAPU32[((pointer)>>2)]); } - + var awaitingDependencies = { }; - + var registeredTypes = { }; - + var typeDependencies = { }; - + var InternalError; var throwInternalError = (message) => { throw new InternalError(message); }; var whenDependentTypesAreResolved = (myTypes, dependentTypes, getTypeConverters) => { myTypes.forEach(function(type) { typeDependencies[type] = dependentTypes; }); - + function onComplete(typeConverters) { var myTypeConverters = getTypeConverters(typeConverters); if (myTypeConverters.length !== myTypes.length) { @@ -3582,7 +3582,7 @@ var tempI64; registerType(myTypes[i], myTypeConverters[i]); } } - + var typeConverters = new Array(dependentTypes.length); var unregisteredTypes = []; var registered = 0; @@ -3610,7 +3610,7 @@ var tempI64; var __embind_finalize_value_object = (structType) => { var reg = structRegistrations[structType]; delete structRegistrations[structType]; - + var rawConstructor = reg.rawConstructor; var rawDestructor = reg.rawDestructor; var fieldRecords = reg.fields; @@ -3635,7 +3635,7 @@ var tempI64; } }; }); - + return [{ name: reg.name, 'fromWireType': (ptr) => { @@ -3688,13 +3688,13 @@ var tempI64; } return ret; }; - - - - + + + + var BindingError; var throwBindingError = (message) => { throw new BindingError(message); }; - + /** @param {Object=} options */ function sharedRegisterType(rawType, registeredInstance, options = {}) { var name = registeredInstance.name; @@ -3708,10 +3708,10 @@ var tempI64; throwBindingError(`Cannot register type '${name}' twice`); } } - + registeredTypes[rawType] = registeredInstance; delete typeDependencies[rawType]; - + if (awaitingDependencies.hasOwnProperty(rawType)) { var callbacks = awaitingDependencies[rawType]; delete awaitingDependencies[rawType]; @@ -3725,7 +3725,7 @@ var tempI64; } return sharedRegisterType(rawType, registeredInstance, options); } - + var GenericWireTypeSize = 8; /** @suppress {globalThis} */ var __embind_register_bool = (rawType, name, trueValue, falseValue) => { @@ -3748,8 +3748,8 @@ var tempI64; }); }; - - + + var shallowCopyInternalPointer = (o) => { return { count: o.count, @@ -3761,18 +3761,18 @@ var tempI64; smartPtrType: o.smartPtrType, }; }; - + var throwInstanceAlreadyDeleted = (obj) => { function getInstanceTypeName(handle) { return handle.$$.ptrType.registeredClass.name; } throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); }; - + var finalizationRegistry = false; - + var detachFinalizer = (handle) => {}; - + var runDestructor = ($$) => { if ($$.smartPtr) { $$.smartPtrType.rawDestructor($$.smartPtr); @@ -3787,7 +3787,7 @@ var tempI64; runDestructor($$); } }; - + var downcastPointer = (ptr, ptrClass, desiredClass) => { if (ptrClass === desiredClass) { return ptr; @@ -3795,19 +3795,19 @@ var tempI64; if (undefined === desiredClass.baseClass) { return null; // no conversion } - + var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); if (rv === null) { return null; } return desiredClass.downcast(rv); }; - + var registeredPointers = { }; - + var getInheritedInstanceCount = () => Object.keys(registeredInstances).length; - + var getLiveInheritedInstances = () => { var rv = []; for (var k in registeredInstances) { @@ -3817,7 +3817,7 @@ var tempI64; } return rv; }; - + var deletionQueue = []; var flushPendingDeletes = () => { while (deletionQueue.length) { @@ -3826,10 +3826,10 @@ var tempI64; obj['delete'](); } }; - + var delayFunction; - - + + var setDelayFunction = (fn) => { delayFunction = fn; if (deletionQueue.length && delayFunction) { @@ -3844,7 +3844,7 @@ var tempI64; }; var registeredInstances = { }; - + var getBasestPointer = (class_, ptr) => { if (ptr === undefined) { throwBindingError('ptr should not be undefined'); @@ -3859,8 +3859,8 @@ var tempI64; ptr = getBasestPointer(class_, ptr); return registeredInstances[ptr]; }; - - + + var makeClassHandle = (prototype, record) => { if (!record.ptrType || !record.ptr) { throwInternalError('makeClassHandle requires ptr and ptrType'); @@ -3881,14 +3881,14 @@ var tempI64; /** @suppress {globalThis} */ function RegisteredPointer_fromWireType(ptr) { // ptr is a raw pointer (or a raw smartpointer) - + // rawPointer is a maybe-null raw pointer var rawPointer = this.getPointee(ptr); if (!rawPointer) { this.destructor(ptr); return null; } - + var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); if (undefined !== registeredInstance) { // JS object has been neutered, time to repopulate it @@ -3904,7 +3904,7 @@ var tempI64; return rv; } } - + function makeDefaultHandle() { if (this.isSmartPointer) { return makeClassHandle(this.registeredClass.instancePrototype, { @@ -3920,13 +3920,13 @@ var tempI64; }); } } - + var actualType = this.registeredClass.getActualType(rawPointer); var registeredPointerRecord = registeredPointers[actualType]; if (!registeredPointerRecord) { return makeDefaultHandle.call(this); } - + var toType; if (this.isConst) { toType = registeredPointerRecord.constPointerType; @@ -3979,9 +3979,9 @@ var tempI64; detachFinalizer = (handle) => finalizationRegistry.unregister(handle); return attachFinalizer(handle); }; - - - + + + var init_ClassHandle = () => { Object.assign(ClassHandle.prototype, { "isAliasOf"(other) { @@ -3991,31 +3991,31 @@ var tempI64; if (!(other instanceof ClassHandle)) { return false; } - + var leftClass = this.$$.ptrType.registeredClass; var left = this.$$.ptr; other.$$ = /** @type {Object} */ (other.$$); var rightClass = other.$$.ptrType.registeredClass; var right = other.$$.ptr; - + while (leftClass.baseClass) { left = leftClass.upcast(left); leftClass = leftClass.baseClass; } - + while (rightClass.baseClass) { right = rightClass.upcast(right); rightClass = rightClass.baseClass; } - + return leftClass === rightClass && left === right; }, - + "clone"() { if (!this.$$.ptr) { throwInstanceAlreadyDeleted(this); } - + if (this.$$.preservePointerOnDelete) { this.$$.count.value += 1; return this; @@ -4025,35 +4025,35 @@ var tempI64; value: shallowCopyInternalPointer(this.$$), } })); - + clone.$$.count.value += 1; clone.$$.deleteScheduled = false; return clone; } }, - + "delete"() { if (!this.$$.ptr) { throwInstanceAlreadyDeleted(this); } - + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { throwBindingError('Object already scheduled for deletion'); } - + detachFinalizer(this); releaseClassHandle(this.$$); - + if (!this.$$.preservePointerOnDelete) { this.$$.smartPtr = undefined; this.$$.ptr = undefined; } }, - + "isDeleted"() { return !this.$$.ptr; }, - + "deleteLater"() { if (!this.$$.ptr) { throwInstanceAlreadyDeleted(this); @@ -4073,12 +4073,12 @@ var tempI64; /** @constructor */ function ClassHandle() { } - + var createNamedFunction = (name, body) => Object.defineProperty(body, 'name', { value: name }); - - + + var ensureOverloadTable = (proto, methodName, humanName) => { if (undefined === proto[methodName].overloadTable) { var prevFunc = proto[methodName]; @@ -4095,14 +4095,14 @@ var tempI64; proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; } }; - + /** @param {number=} numArguments */ var exposePublicSymbol = (name, value, numArguments) => { if (Module.hasOwnProperty(name)) { if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { throwBindingError(`Cannot register public name '${name}' twice`); } - + // We are exposing a function with the same name as an existing function. Create an overload table and a function selector // that routes between the two. ensureOverloadTable(Module, name, name); @@ -4119,9 +4119,9 @@ var tempI64; } } }; - + var char_0 = 48; - + var char_9 = 57; var makeLegalFunctionName = (name) => { if (undefined === name) { @@ -4134,8 +4134,8 @@ var tempI64; } return name; }; - - + + /** @constructor */ function RegisteredClass(name, constructor, @@ -4155,8 +4155,8 @@ var tempI64; this.downcast = downcast; this.pureVirtualFunctions = []; } - - + + var upcastPointer = (ptr, ptrClass, desiredClass) => { while (ptrClass !== desiredClass) { if (!ptrClass.upcast) { @@ -4175,7 +4175,7 @@ var tempI64; } return 0; } - + if (!handle.$$) { throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } @@ -4186,8 +4186,8 @@ var tempI64; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; } - - + + /** @suppress {globalThis} */ function genericPointerToWireType(destructors, handle) { var ptr; @@ -4195,7 +4195,7 @@ var tempI64; if (this.isReference) { throwBindingError(`null is not a valid ${this.name}`); } - + if (this.isSmartPointer) { ptr = this.rawConstructor(); if (destructors !== null) { @@ -4206,7 +4206,7 @@ var tempI64; return 0; } } - + if (!handle || !handle.$$) { throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } @@ -4218,7 +4218,7 @@ var tempI64; } var handleClass = handle.$$.ptrType.registeredClass; ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - + if (this.isSmartPointer) { // TODO: this is not strictly true // We could support BY_EMVAL conversions from raw pointers to smart pointers @@ -4226,7 +4226,7 @@ var tempI64; if (undefined === handle.$$.smartPtr) { throwBindingError('Passing raw pointer to smart pointer is illegal'); } - + switch (this.sharingPolicy) { case 0: // NONE // no upcasting @@ -4236,11 +4236,11 @@ var tempI64; throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); } break; - + case 1: // INTRUSIVE ptr = handle.$$.smartPtr; break; - + case 2: // BY_EMVAL if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; @@ -4255,15 +4255,15 @@ var tempI64; } } break; - + default: throwBindingError('Unsupporting sharing policy'); } } return ptr; } - - + + /** @suppress {globalThis} */ function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { if (handle === null) { @@ -4272,7 +4272,7 @@ var tempI64; } return 0; } - + if (!handle.$$) { throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } @@ -4286,10 +4286,10 @@ var tempI64; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); return ptr; } - - - - + + + + var init_RegisteredPointer = () => { Object.assign(RegisteredPointer.prototype, { getPointee(ptr) { @@ -4319,7 +4319,7 @@ var tempI64; registeredClass, isReference, isConst, - + // smart pointer properties isSmartPointer, pointeeType, @@ -4333,7 +4333,7 @@ var tempI64; this.registeredClass = registeredClass; this.isReference = isReference; this.isConst = isConst; - + // smart pointer properties this.isSmartPointer = isSmartPointer; this.pointeeType = pointeeType; @@ -4342,7 +4342,7 @@ var tempI64; this.rawConstructor = rawConstructor; this.rawShare = rawShare; this.rawDestructor = rawDestructor; - + if (!isSmartPointer && registeredClass.baseClass === undefined) { if (isConst) { this['toWireType'] = constNoSmartPtrRawPointerToWireType; @@ -4359,7 +4359,7 @@ var tempI64; // craftInvokerFunction altogether. } } - + /** @param {number=} numArguments */ var replacePublicSymbol = (name, value, numArguments) => { if (!Module.hasOwnProperty(name)) { @@ -4374,17 +4374,17 @@ var tempI64; Module[name].argCount = numArguments; } }; - - - + + + var dynCallLegacy = (sig, ptr, args) => { sig = sig.replace(/p/g, 'i') var f = Module['dynCall_' + sig]; return f(ptr, ...args); }; - + var wasmTableMirror = []; - + /** @type {WebAssembly.Table} */ var wasmTable; var getWasmTableEntry = (funcPtr) => { @@ -4395,7 +4395,7 @@ var tempI64; } return func; }; - + var dynCall = (sig, ptr, args = []) => { // Without WASM_BIGINT support we cannot directly call function with i64 as // part of their signature, so we rely on the dynCall functions generated by @@ -4409,32 +4409,32 @@ var tempI64; var getDynCaller = (sig, ptr) => { return (...args) => dynCall(sig, ptr, args); }; - - + + var embind__requireFunction = (signature, rawFunction) => { signature = readLatin1String(signature); - + function makeDynCaller() { if (signature.includes('j')) { return getDynCaller(signature, rawFunction); } return getWasmTableEntry(rawFunction); } - + var fp = makeDynCaller(); if (typeof fp != "function") { throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); } return fp; }; - - - + + + var extendError = (baseErrorType, errorName) => { var errorClass = createNamedFunction(errorName, function(message) { this.name = errorName; this.message = message; - + var stack = (new Error(message)).stack; if (stack !== undefined) { this.stack = this.toString() + '\n' + @@ -4450,13 +4450,13 @@ var tempI64; return `${this.name}: ${this.message}`; } }; - + return errorClass; }; var UnboundTypeError; - - - + + + var getTypeName = (type) => { var ptr = ___getTypeName(type); var rv = readLatin1String(ptr); @@ -4481,10 +4481,10 @@ var tempI64; seen[type] = true; } types.forEach(visit); - + throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([', '])); }; - + var __embind_register_class = (rawType, rawPointerType, rawConstPointerType, @@ -4504,18 +4504,18 @@ var tempI64; downcast &&= embind__requireFunction(downcastSignature, downcast); rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); var legalFunctionName = makeLegalFunctionName(name); - + exposePublicSymbol(legalFunctionName, function() { // this code cannot run if baseClassRawType is zero throwUnboundTypeError(`Cannot construct ${name} due to unbound types`, [baseClassRawType]); }); - + whenDependentTypesAreResolved( [rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], (base) => { base = base[0]; - + var baseClass; var basePrototype; if (baseClassRawType) { @@ -4524,7 +4524,7 @@ var tempI64; } else { basePrototype = ClassHandle.prototype; } - + var constructor = createNamedFunction(name, function(...args) { if (Object.getPrototypeOf(this) !== instancePrototype) { throw new BindingError("Use 'new' to construct " + name); @@ -4538,13 +4538,13 @@ var tempI64; } return body.apply(this, args); }); - + var instancePrototype = Object.create(basePrototype, { constructor: { value: constructor }, }); - + constructor.prototype = instancePrototype; - + var registeredClass = new RegisteredClass(name, constructor, instancePrototype, @@ -4553,39 +4553,39 @@ var tempI64; getActualType, upcast, downcast); - + if (registeredClass.baseClass) { // Keep track of class hierarchy. Used to allow sub-classes to inherit class functions. registeredClass.baseClass.__derivedClasses ??= []; - + registeredClass.baseClass.__derivedClasses.push(registeredClass); } - + var referenceConverter = new RegisteredPointer(name, registeredClass, true, false, false); - + var pointerConverter = new RegisteredPointer(name + '*', registeredClass, false, false, false); - + var constPointerConverter = new RegisteredPointer(name + ' const*', registeredClass, false, true, false); - + registeredPointers[rawType] = { pointerType: pointerConverter, constPointerType: constPointerConverter }; - + replacePublicSymbol(legalFunctionName, constructor); - + return [referenceConverter, pointerConverter, constPointerConverter]; } ); @@ -4600,15 +4600,15 @@ var tempI64; } return array; }; - - - - - - - - - + + + + + + + + + function usesDestructorStack(argTypes) { // Skip return value at index 0 - it's not deleted here. for (var i = 1; i < argTypes.length; ++i) { @@ -4619,7 +4619,7 @@ var tempI64; } return false; } - + function newFunc(constructor, argumentList) { if (!(constructor instanceof Function)) { throw new TypeError(`new_ called with constructor type ${typeof(constructor)} which is not a function`); @@ -4637,11 +4637,11 @@ var tempI64; var dummy = createNamedFunction(constructor.name || 'unknownFunctionName', function(){}); dummy.prototype = constructor.prototype; var obj = new dummy; - + var r = constructor.apply(obj, argumentList); return (r instanceof Object) ? r : obj; } - + function createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync) { var needsDestructorStack = usesDestructorStack(argTypes); var argCount = argTypes.length; @@ -4651,38 +4651,38 @@ var tempI64; argsList += (i!==0?", ":"")+"arg"+i; argsListWired += (i!==0?", ":"")+"arg"+i+"Wired"; } - + var invokerFnBody = ` return function (${argsList}) { if (arguments.length !== ${argCount - 2}) { throwBindingError('function ' + humanName + ' called with ' + arguments.length + ' arguments, expected ${argCount - 2}'); }`; - + if (needsDestructorStack) { invokerFnBody += "var destructors = [];\n"; } - + var dtorStack = needsDestructorStack ? "destructors" : "null"; var args1 = ["humanName", "throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; - + if (isClassMethodFunc) { invokerFnBody += "var thisWired = classParam['toWireType']("+dtorStack+", this);\n"; } - + for (var i = 0; i < argCount - 2; ++i) { invokerFnBody += "var arg"+i+"Wired = argType"+i+"['toWireType']("+dtorStack+", arg"+i+");\n"; args1.push("argType"+i); } - + if (isClassMethodFunc) { argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; } - + invokerFnBody += (returns || isAsync ? "var rv = ":"") + "invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n"; - + var returnVal = returns ? "rv" : ""; - + if (needsDestructorStack) { invokerFnBody += "runDestructors(destructors);\n"; } else { @@ -4694,15 +4694,15 @@ var tempI64; } } } - + if (returns) { invokerFnBody += "var ret = retType['fromWireType'](rv);\n" + "return ret;\n"; } else { } - + invokerFnBody += "}\n"; - + return [args1, invokerFnBody]; } function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { @@ -4716,25 +4716,25 @@ var tempI64; // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. var argCount = argTypes.length; - + if (argCount < 2) { throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); } - + var isClassMethodFunc = (argTypes[1] !== null && classType !== null); - + // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. // TODO: This omits argument count check - enable only at -O3 or similar. // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { // return FUNCTION_TABLE[fn]; // } - + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. // TODO: Remove this completely once all function invokers are being dynamically generated. var needsDestructorStack = usesDestructorStack(argTypes); - + var returns = (argTypes[0].name !== "void"); - + // Builld the arguments that will be passed into the closure around the invoker // function. var closureArgs = [humanName, throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; @@ -4748,7 +4748,7 @@ var tempI64; } } } - + let [args, invokerFnBody] = createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync); args.push(invokerFnBody); var invokerFn = newFunc(Function, args)(...closureArgs); @@ -4766,11 +4766,11 @@ var tempI64; invoker = embind__requireFunction(invokerSignature, invoker); var args = [rawConstructor]; var destructors = []; - + whenDependentTypesAreResolved([], [rawClassType], (classType) => { classType = classType[0]; var humanName = `constructor ${classType.name}`; - + if (undefined === classType.registeredClass.constructor_body) { classType.registeredClass.constructor_body = []; } @@ -4780,7 +4780,7 @@ var tempI64; classType.registeredClass.constructor_body[argCount - 1] = () => { throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`, rawArgTypes); }; - + whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { // Insert empty slot for context type (argTypes[1]). argTypes.splice(1, 0, null); @@ -4791,12 +4791,12 @@ var tempI64; }); }; - - - - - - + + + + + + var getFunctionName = (signature) => { signature = signature.trim(); const argsIndex = signature.indexOf("("); @@ -4819,23 +4819,23 @@ var tempI64; methodName = readLatin1String(methodName); methodName = getFunctionName(methodName); rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); - + whenDependentTypesAreResolved([], [rawClassType], (classType) => { classType = classType[0]; var humanName = `${classType.name}.${methodName}`; - + if (methodName.startsWith("@@")) { methodName = Symbol[methodName.substring(2)]; } - + if (isPureVirtual) { classType.registeredClass.pureVirtualFunctions.push(methodName); } - + function unboundTypesHandler() { throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); } - + var proto = classType.registeredClass.instancePrototype; var method = proto[methodName]; if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2)) { @@ -4850,10 +4850,10 @@ var tempI64; ensureOverloadTable(proto, methodName, humanName); proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; } - + whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context, isAsync); - + // Replace the initial unbound-handler-stub function with the // appropriate member function, now that all types are resolved. If // multiple overloads are registered for this function, the function @@ -4865,14 +4865,14 @@ var tempI64; } else { proto[methodName].overloadTable[argCount - 2] = memberFunction; } - + return []; }); return []; }); }; - + var __embind_register_constant = (name, type, value) => { name = readLatin1String(name); whenDependentTypesAreResolved([], [type], (type) => { @@ -4882,9 +4882,9 @@ var tempI64; }); }; - + var emval_freelist = []; - + var emval_handles = []; var __emval_decref = (handle) => { if (handle > 9 && 0 === --emval_handles[handle + 1]) { @@ -4892,15 +4892,15 @@ var tempI64; emval_freelist.push(handle); } }; - - - - - + + + + + var count_emval_handles = () => { return emval_handles.length / 2 - 5 - emval_freelist.length; }; - + var init_emval = () => { // reserve 0 and some special values. These never get de-allocated. emval_handles.push( @@ -4934,8 +4934,8 @@ var tempI64; } }, }; - - + + var EmValType = { name: 'emscripten::val', 'fromWireType': (handle) => { @@ -4947,13 +4947,13 @@ var tempI64; 'argPackAdvance': GenericWireTypeSize, 'readValueFromPointer': readPointer, destructorFunction: null, // This type does not need a destructor - + // TODO: do we need a deleteObject here? write a test where // emval is passed into JS via an interface }; var __embind_register_emval = (rawType) => registerType(rawType, EmValType); - + var enumReadValueFromPointer = (name, width, signed) => { switch (width) { case 1: return signed ? @@ -4969,15 +4969,15 @@ var tempI64; throw new TypeError(`invalid integer width (${width}): ${name}`); } }; - - + + /** @suppress {globalThis} */ var __embind_register_enum = (rawType, name, size, isSigned) => { name = readLatin1String(name); - + function ctor() {} ctor.values = {}; - + registerType(rawType, { name, constructor: ctor, @@ -4992,10 +4992,10 @@ var tempI64; exposePublicSymbol(name, ctor); }; - - - - + + + + var requireRegisteredType = (rawType, humanName) => { var impl = registeredTypes[rawType]; if (undefined === impl) { @@ -5006,9 +5006,9 @@ var tempI64; var __embind_register_enum_value = (rawEnumType, name, enumValue) => { var enumType = requireRegisteredType(rawEnumType, 'enum'); name = readLatin1String(name); - + var Enum = enumType.constructor; - + var Value = Object.create(enumType.constructor.prototype, { value: {value: enumValue}, constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})}, @@ -5028,7 +5028,7 @@ var tempI64; return '' + v; } }; - + var floatReadValueFromPointer = (name, width) => { switch (width) { case 4: return function(pointer) { @@ -5041,8 +5041,8 @@ var tempI64; throw new TypeError(`invalid float width (${width}): ${name}`); } }; - - + + var __embind_register_float = (rawType, name, size) => { name = readLatin1String(name); registerType(rawType, { @@ -5059,25 +5059,25 @@ var tempI64; }); }; - - - - - - - - + + + + + + + + var __embind_register_function = (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync) => { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); name = getFunctionName(name); - + rawInvoker = embind__requireFunction(signature, rawInvoker); - + exposePublicSymbol(name, function() { throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); }, argCount - 1); - + whenDependentTypesAreResolved([], argTypes, (argTypes) => { var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync), argCount - 1); @@ -5085,7 +5085,7 @@ var tempI64; }); }; - + var integerReadValueFromPointer = (name, width, signed) => { // integers are quite common, so generate very specialized functions switch (width) { @@ -5102,8 +5102,8 @@ var tempI64; throw new TypeError(`invalid integer width (${width}): ${name}`); } }; - - + + /** @suppress {globalThis} */ var __embind_register_integer = (primitiveType, name, size, minRange, maxRange) => { name = readLatin1String(name); @@ -5112,14 +5112,14 @@ var tempI64; if (maxRange === -1) { maxRange = 4294967295; } - + var fromWireType = (value) => value; - + if (minRange === 0) { var bitshift = 32 - 8*size; fromWireType = (value) => (value << bitshift) >>> bitshift; } - + var isUnsignedType = (name.includes('unsigned')); var checkAssertions = (value, toTypeName) => { } @@ -5147,7 +5147,7 @@ var tempI64; }); }; - + var __embind_register_memory_view = (rawType, dataTypeIndex, name) => { var typeMapping = [ Int8Array, @@ -5159,15 +5159,15 @@ var tempI64; Float32Array, Float64Array, ]; - + var TA = typeMapping[dataTypeIndex]; - + function decodeMemoryView(handle) { var size = HEAPU32[((handle)>>2)]; var data = HEAPU32[(((handle)+(4))>>2)]; return new TA(HEAP8.buffer, data, size); } - + name = readLatin1String(name); registerType(rawType, { name, @@ -5179,23 +5179,23 @@ var tempI64; }); }; - - - - + + + + var stringToUTF8 = (str, outPtr, maxBytesToWrite) => { return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); }; - - - - + + + + var __embind_register_std_string = (rawType, name) => { name = readLatin1String(name); var stdStringIsUTF8 //process only std::string bindings with UTF8 support, in contrast to e.g. std::basic_string = (name === "std::string"); - + registerType(rawType, { name, // For some method names we use string keys here since they are part of @@ -5203,7 +5203,7 @@ var tempI64; 'fromWireType'(value) { var length = HEAPU32[((value)>>2)]; var payload = value + 4; - + var str; if (stdStringIsUTF8) { var decodeStartPtr = payload; @@ -5229,19 +5229,19 @@ var tempI64; } str = a.join(''); } - + _free(value); - + return str; }, 'toWireType'(destructors, value) { if (value instanceof ArrayBuffer) { value = new Uint8Array(value); } - + var length; var valueIsOfTypeString = (typeof value == 'string'); - + if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { throwBindingError('Cannot pass non-string to std::string'); } @@ -5250,7 +5250,7 @@ var tempI64; } else { length = value.length; } - + // assumes POINTER_SIZE alignment var base = _malloc(4 + length + 1); var ptr = base + 4; @@ -5273,7 +5273,7 @@ var tempI64; } } } - + if (destructors !== null) { destructors.push(_free, base); } @@ -5287,9 +5287,9 @@ var tempI64; }); }; - - - + + + var UTF16Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf-16le') : undefined;; var UTF16ToString = (ptr, maxBytesToRead) => { var endPtr = ptr; @@ -5303,13 +5303,13 @@ var tempI64; // will always evaluate to true. This saves on code size. while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; endPtr = idx << 1; - + if (endPtr - ptr > 32 && UTF16Decoder) return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); - + // Fallback: decode without UTF16Decoder var str = ''; - + // If maxBytesToRead is not passed explicitly, it will be undefined, and the // for-loop's condition will always evaluate to true. The loop is then // terminated on the first null char. @@ -5320,10 +5320,10 @@ var tempI64; // pass the UTF16 string right through. str += String.fromCharCode(codeUnit); } - + return str; }; - + var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. maxBytesToWrite ??= 0x7FFFFFFF; @@ -5341,14 +5341,14 @@ var tempI64; HEAP16[((outPtr)>>1)] = 0; return outPtr - startPtr; }; - + var lengthBytesUTF16 = (str) => { return str.length*2; }; - + var UTF32ToString = (ptr, maxBytesToRead) => { var i = 0; - + var str = ''; // If maxBytesToRead is not passed explicitly, it will be undefined, and this // will always evaluate to true. This saves on code size. @@ -5367,7 +5367,7 @@ var tempI64; } return str; }; - + var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. maxBytesToWrite ??= 0x7FFFFFFF; @@ -5390,7 +5390,7 @@ var tempI64; HEAP32[((outPtr)>>2)] = 0; return outPtr - startPtr; }; - + var lengthBytesUTF32 = (str) => { var len = 0; for (var i = 0; i < str.length; ++i) { @@ -5400,7 +5400,7 @@ var tempI64; if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. len += 4; } - + return len; }; var __embind_register_std_wstring = (rawType, charSize, name) => { @@ -5423,7 +5423,7 @@ var tempI64; // Code mostly taken from _embind_register_std_string fromWireType var length = HEAPU32[((value)>>2)]; var str; - + var decodeStartPtr = value + 4; // Looping here to support possible embedded '0' bytes for (var i = 0; i <= length; ++i) { @@ -5440,23 +5440,23 @@ var tempI64; decodeStartPtr = currentBytePtr + charSize; } } - + _free(value); - + return str; }, 'toWireType': (destructors, value) => { if (!(typeof value == 'string')) { throwBindingError(`Cannot pass non-string to C++ string type ${name}`); } - + // assumes POINTER_SIZE alignment var length = lengthBytesUTF(value); var ptr = _malloc(4 + length + charSize); HEAPU32[((ptr)>>2)] = length / charSize; - + encodeString(value, ptr + 4, length + charSize); - + if (destructors !== null) { destructors.push(_free, ptr); } @@ -5470,8 +5470,8 @@ var tempI64; }); }; - - + + var __embind_register_value_object = ( rawType, name, @@ -5488,8 +5488,8 @@ var tempI64; }; }; - - + + var __embind_register_value_object_field = ( structType, fieldName, @@ -5513,7 +5513,7 @@ var tempI64; }); }; - + var __embind_register_void = (rawType, name) => { name = readLatin1String(name); registerType(rawType, { @@ -5535,8 +5535,8 @@ var tempI64; throw Infinity; }; - - + + var emval_returnValue = (returnType, destructorsRef, handle) => { var destructors = []; var result = returnType['toWireType'](destructors, handle); @@ -5553,7 +5553,7 @@ var tempI64; }; var emval_methodCallers = []; - + var __emval_call = (caller, handle, destructorsRef, args) => { caller = emval_methodCallers[caller]; handle = Emval.toValue(handle); @@ -5562,7 +5562,7 @@ var tempI64; var emval_symbols = { }; - + var getStringOrSymbol = (address) => { var symbol = emval_symbols[address]; if (symbol === undefined) { @@ -5570,8 +5570,8 @@ var tempI64; } return symbol; }; - - + + var __emval_call_method = (caller, objHandle, methodName, destructorsRef, args) => { caller = emval_methodCallers[caller]; objHandle = Emval.toValue(objHandle); @@ -5580,8 +5580,8 @@ var tempI64; }; - - + + var emval_get_global = () => { if (typeof globalThis == 'object') { return globalThis; @@ -5604,7 +5604,7 @@ var tempI64; emval_methodCallers.push(caller); return id; }; - + var emval_lookupTypes = (argCount, argTypes) => { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { @@ -5613,19 +5613,19 @@ var tempI64; } return a; }; - - + + var reflectConstruct = Reflect.construct; - - + + var __emval_get_method_caller = (argCount, argTypes, kind) => { var types = emval_lookupTypes(argCount, argTypes); var retType = types.shift(); argCount--; // remove the shifted off return type - + var functionBody = `return function (obj, func, destructorsRef, args) {\n`; - + var offset = 0; var argsList = []; // 'obj?, arg0, arg1, arg2, ... , argN' if (kind === /* FUNCTION */ 0) { @@ -5652,14 +5652,14 @@ var tempI64; } functionBody += "};\n"; - + params.push(functionBody); var invokerFunction = newFunc(Function, params)(...args); var functionName = `methodCaller<(${types.map(t => t.name).join(', ')}) => ${retType.name}>`; return emval_addMethodCaller(createNamedFunction(functionName, invokerFunction)); }; - + var __emval_get_module_property = (name) => { name = getStringOrSymbol(name); return Emval.toHandle(Module[name]); @@ -5677,31 +5677,31 @@ var tempI64; } }; - + var __emval_new_cstring = (v) => Emval.toHandle(getStringOrSymbol(v)); - - + + var __emval_run_destructors = (handle) => { var destructors = Emval.toValue(handle); runDestructors(destructors); __emval_decref(handle); }; - - - - - + + + + + var convertI32PairToI53Checked = (lo, hi) => { return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; }; function __mmap_js(len,prot,flags,fd,offset_low, offset_high,allocated,addr) { var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + + try { - + if (isNaN(offset)) return 61; var stream = SYSCALLS.getStreamFromFD(fd); var res = FS.mmap(stream, len, offset, prot, flags); @@ -5716,13 +5716,13 @@ var tempI64; ; } - + function __munmap_js(addr,len,prot,flags,fd,offset_low, offset_high) { var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + + try { - + var stream = SYSCALLS.getStreamFromFD(fd); if (prot & 2) { SYSCALLS.doMsync(addr, stream, len, flags, offset); @@ -5741,7 +5741,7 @@ var tempI64; var summer = new Date(currentYear, 6, 1); var winterOffset = winter.getTimezoneOffset(); var summerOffset = summer.getTimezoneOffset(); - + // Local standard timezone offset. Local standard time is not adjusted for // daylight savings. This code uses the fact that getTimezoneOffset returns // a greater value during Standard Time versus Daylight Saving Time (DST). @@ -5749,28 +5749,28 @@ var tempI64; // compares whether the output of the given date the same (Standard) or less // (DST). var stdTimezoneOffset = Math.max(winterOffset, summerOffset); - + // timezone is specified as seconds west of UTC ("The external variable // `timezone` shall be set to the difference, in seconds, between // Coordinated Universal Time (UTC) and local standard time."), the same // as returned by stdTimezoneOffset. // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html HEAPU32[((timezone)>>2)] = stdTimezoneOffset * 60; - + HEAP32[((daylight)>>2)] = Number(winterOffset != summerOffset); - + var extractZone = (timezoneOffset) => { // Why inverse sign? // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset var sign = timezoneOffset >= 0 ? "-" : "+"; - + var absOffset = Math.abs(timezoneOffset) var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); var minutes = String(absOffset % 60).padStart(2, "0"); - + return `UTC${sign}${hours}${minutes}`; } - + var winterName = extractZone(winterOffset); var summerName = extractZone(summerOffset); if (summerOffset < winterOffset) { @@ -5800,7 +5800,7 @@ var tempI64; _emscripten_get_now = () => performance.now(); ; - + var growMemory = (size) => { var b = wasmMemory.buffer; var pages = (size - b.byteLength + 65535) / 65536; @@ -5820,7 +5820,7 @@ var tempI64; requestedSize >>>= 0; // With multithreaded builds, races can happen (another thread might increase the size // in between), so return a failure, and let the caller retry. - + // Memory resize rules: // 1. Always increase heap size to at least the requested size, rounded up // to next page multiple. @@ -5837,16 +5837,16 @@ var tempI64; // over-eager decision to excessively reserve due to (3) above. // Hence if an allocation fails, cut down on the amount of excess // growth, in an attempt to succeed to perform a smaller allocation. - + // A limit is set for how much we can grow. We should not exceed that // (the wasm binary specifies it, so if we tried, we'd fail anyhow). var maxHeapSize = getHeapMax(); if (requestedSize > maxHeapSize) { return false; } - + var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; - + // Loop through potential heap size increases. If we attempt a too eager // reservation that fails, cut down on the attempted size and reserve a // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) @@ -5854,12 +5854,12 @@ var tempI64; var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth // but limit overreserving (default to capping at +96MB overgrowth at most) overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); - + var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); - + var replacement = growMemory(newSize); if (replacement) { - + return true; } } @@ -5868,7 +5868,7 @@ var tempI64; var ENV = { }; - + var getExecutableName = () => { return thisProgram || './this.program'; }; @@ -5902,7 +5902,7 @@ var tempI64; } return getEnvStrings.strings; }; - + var stringToAscii = (str, buffer) => { for (var i = 0; i < str.length; ++i) { HEAP8[buffer++] = str.charCodeAt(i); @@ -5932,7 +5932,7 @@ var tempI64; function _fd_close(fd) { try { - + var stream = SYSCALLS.getStreamFromFD(fd); FS.close(stream); return 0; @@ -5959,10 +5959,10 @@ var tempI64; } return ret; }; - + function _fd_read(fd, iov, iovcnt, pnum) { try { - + var stream = SYSCALLS.getStreamFromFD(fd); var num = doReadv(stream, iov, iovcnt); HEAPU32[((pnum)>>2)] = num; @@ -5973,13 +5973,13 @@ var tempI64; } } - + function _fd_seek(fd,offset_low, offset_high,whence,newOffset) { var offset = convertI32PairToI53Checked(offset_low, offset_high); - - + + try { - + if (isNaN(offset)) return 61; var stream = SYSCALLS.getStreamFromFD(fd); FS.llseek(stream, offset, whence); @@ -6009,10 +6009,10 @@ var tempI64; } return ret; }; - + function _fd_write(fd, iov, iovcnt, pnum) { try { - + var stream = SYSCALLS.getStreamFromFD(fd); var num = doWritev(stream, iov, iovcnt); HEAPU32[((pnum)>>2)] = num; diff --git a/webgl/gltf/BasisTextureLoader.js b/webgl/gltf/BasisTextureLoader.js index 627bdf30..1c492604 100644 --- a/webgl/gltf/BasisTextureLoader.js +++ b/webgl/gltf/BasisTextureLoader.js @@ -75,7 +75,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader. } else if ( config.bc7Supported ) { - config.format = THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC7_M6_OPAQUE_ONLY; + config.format = THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC7_M6_OPAQUE_ONLY; } else if ( config.dxtSupported ) { @@ -88,7 +88,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader. } else if ( config.pvrtcSupported ) { config.format = this.useAlpha ? THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGBA : THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGB; - + } else { throw new Error( 'THREE.BasisTextureLoader: No suitable compressed texture format found.' ); diff --git a/webgl/gltf/GLTFLoader.js b/webgl/gltf/GLTFLoader.js index 78c0687c..79a70d74 100644 --- a/webgl/gltf/GLTFLoader.js +++ b/webgl/gltf/GLTFLoader.js @@ -183,7 +183,7 @@ THREE.GLTFLoader = ( function () { case EXTENSIONS.MSFT_TEXTURE_DDS: extensions[ extensionName ] = new GLTFTextureDDSExtension( this.ddsLoader ); break; - + case EXTENSIONS.GOOGLE_TEXTURE_BASIS: extensions[ EXTENSIONS.GOOGLE_TEXTURE_BASIS ] = new GLTFTextureBasisExtension(); break; diff --git a/webgl/gltf/index.html b/webgl/gltf/index.html index 4525c211..de131340 100644 --- a/webgl/gltf/index.html +++ b/webgl/gltf/index.html @@ -17,7 +17,7 @@
Basis Texture Transcoder glTF Demo
- +
- + diff --git a/webgl/gltf/three.min.js b/webgl/gltf/three.min.js index 3e56587d..be949ad3 100644 --- a/webgl/gltf/three.min.js +++ b/webgl/gltf/three.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).THREE={})}(this,function(e){"use strict";void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52)),void 0===Number.isInteger&&(Number.isInteger=function(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}),void 0===Math.sign&&(Math.sign=function(e){return e<0?-1:e>0?1:+e}),"name"in Function.prototype==!1&&Object.defineProperty(Function.prototype,"name",{get:function(){return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]}}),void 0===Object.assign&&(Object.assign=function(e){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1;n>8&255]+Vt[e>>16&255]+Vt[e>>24&255]+"-"+Vt[255&t]+Vt[t>>8&255]+"-"+Vt[t>>16&15|64]+Vt[t>>24&255]+"-"+Vt[63&n|128]+Vt[n>>8&255]+"-"+Vt[n>>16&255]+Vt[n>>24&255]+Vt[255&i]+Vt[i>>8&255]+Vt[i>>16&255]+Vt[i>>24&255]).toUpperCase()},clamp:function(e,t,n){return Math.max(t,Math.min(n,e))},euclideanModulo:function(e,t){return(e%t+t)%t},mapLinear:function(e,t,n,i,r){return i+(e-t)*(r-i)/(n-t)},lerp:function(e,t,n){return(1-n)*e+n*t},smoothstep:function(e,t,n){return e<=t?0:e>=n?1:(e=(e-t)/(n-t))*e*(3-2*e)},smootherstep:function(e,t,n){return e<=t?0:e>=n?1:(e=(e-t)/(n-t))*e*e*(e*(6*e-15)+10)},randInt:function(e,t){return e+Math.floor(Math.random()*(t-e+1))},randFloat:function(e,t){return e+Math.random()*(t-e)},randFloatSpread:function(e){return e*(.5-Math.random())},degToRad:function(e){return e*Wt.DEG2RAD},radToDeg:function(e){return e*Wt.RAD2DEG},isPowerOfTwo:function(e){return 0==(e&e-1)&&0!==e},ceilPowerOfTwo:function(e){return Math.pow(2,Math.ceil(Math.log(e)/Math.LN2))},floorPowerOfTwo:function(e){return Math.pow(2,Math.floor(Math.log(e)/Math.LN2))},setQuaternionFromProperEuler:function(e,t,n,i,r){var a=Math.cos,o=Math.sin,s=a(n/2),c=o(n/2),l=a((t+i)/2),h=o((t+i)/2),u=a((t-i)/2),p=o((t-i)/2),d=a((i-t)/2),f=o((i-t)/2);"XYX"===r?e.set(s*h,c*u,c*p,s*l):"YZY"===r?e.set(c*p,s*h,c*u,s*l):"ZXZ"===r?e.set(c*u,c*p,s*h,s*l):"XZX"===r?e.set(s*h,c*f,c*d,s*l):"YXY"===r?e.set(c*d,s*h,c*f,s*l):"ZYZ"===r?e.set(c*f,c*d,s*h,s*l):console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order.")}};function qt(e,t){this.x=e||0,this.y=t||0}function Xt(){this.elements=[1,0,0,0,1,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}Object.defineProperties(qt.prototype,{width:{get:function(){return this.x},set:function(e){this.x=e}},height:{get:function(){return this.y},set:function(e){this.y=e}}}),Object.assign(qt.prototype,{isVector2:!0,set:function(e,t){return this.x=e,this.y=t,this},setScalar:function(e){return this.x=e,this.y=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(e){return this.x=e.x,this.y=e.y,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this)},addScalar:function(e){return this.x+=e,this.y+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this)},subScalar:function(e){return this.x-=e,this.y-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this},multiply:function(e){return this.x*=e.x,this.y*=e.y,this},multiplyScalar:function(e){return this.x*=e,this.y*=e,this},divide:function(e){return this.x/=e.x,this.y/=e.y,this},divideScalar:function(e){return this.multiplyScalar(1/e)},applyMatrix3:function(e){var t=this.x,n=this.y,i=e.elements;return this.x=i[0]*t+i[3]*n+i[6],this.y=i[1]*t+i[4]*n+i[7],this},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this},negate:function(){return this.x=-this.x,this.y=-this.y,this},dot:function(e){return this.x*e.x+this.y*e.y},cross:function(e){return this.x*e.y-this.y*e.x},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){return Math.atan2(-this.y,-this.x)+Math.PI},distanceTo:function(e){return Math.sqrt(this.distanceToSquared(e))},distanceToSquared:function(e){var t=this.x-e.x,n=this.y-e.y;return t*t+n*n},manhattanDistanceTo:function(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},equals:function(e){return e.x===this.x&&e.y===this.y},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this},rotateAround:function(e,t){var n=Math.cos(t),i=Math.sin(t),r=this.x-e.x,a=this.y-e.y;return this.x=r*n-a*i+e.x,this.y=r*i+a*n+e.y,this}}),Object.assign(Xt.prototype,{isMatrix3:!0,set:function(e,t,n,i,r,a,o,s,c){var l=this.elements;return l[0]=e,l[1]=i,l[2]=o,l[3]=t,l[4]=r,l[5]=s,l[6]=n,l[7]=a,l[8]=c,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(e){var t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this},extractBasis:function(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this},setFromMatrix4:function(e){var t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this},multiply:function(e){return this.multiplyMatrices(this,e)},premultiply:function(e){return this.multiplyMatrices(e,this)},multiplyMatrices:function(e,t){var n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[3],s=n[6],c=n[1],l=n[4],h=n[7],u=n[2],p=n[5],d=n[8],f=i[0],m=i[3],g=i[6],v=i[1],y=i[4],x=i[7],b=i[2],_=i[5],w=i[8];return r[0]=a*f+o*v+s*b,r[3]=a*m+o*y+s*_,r[6]=a*g+o*x+s*w,r[1]=c*f+l*v+h*b,r[4]=c*m+l*y+h*_,r[7]=c*g+l*x+h*w,r[2]=u*f+p*v+d*b,r[5]=u*m+p*y+d*_,r[8]=u*g+p*x+d*w,this},multiplyScalar:function(e){var t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this},determinant:function(){var e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],a=e[4],o=e[5],s=e[6],c=e[7],l=e[8];return t*a*l-t*o*c-n*r*l+n*o*s+i*r*c-i*a*s},getInverse:function(e,t){e&&e.isMatrix4&&console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");var n=e.elements,i=this.elements,r=n[0],a=n[1],o=n[2],s=n[3],c=n[4],l=n[5],h=n[6],u=n[7],p=n[8],d=p*c-l*u,f=l*h-p*s,m=u*s-c*h,g=r*d+a*f+o*m;if(0===g){var v="THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";if(!0===t)throw new Error(v);return console.warn(v),this.identity()}var y=1/g;return i[0]=d*y,i[1]=(o*u-p*a)*y,i[2]=(l*a-o*c)*y,i[3]=f*y,i[4]=(p*r-o*h)*y,i[5]=(o*s-l*r)*y,i[6]=m*y,i[7]=(a*h-u*r)*y,i[8]=(c*r-a*s)*y,this},transpose:function(){var e,t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this},getNormalMatrix:function(e){return this.setFromMatrix4(e).getInverse(this).transpose()},transposeIntoArray:function(e){var t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this},setUvTransform:function(e,t,n,i,r,a,o){var s=Math.cos(r),c=Math.sin(r);this.set(n*s,n*c,-n*(s*a+c*o)+a+e,-i*c,i*s,-i*(-c*a+s*o)+o+t,0,0,1)},scale:function(e,t){var n=this.elements;return n[0]*=e,n[3]*=e,n[6]*=e,n[1]*=t,n[4]*=t,n[7]*=t,this},rotate:function(e){var t=Math.cos(e),n=Math.sin(e),i=this.elements,r=i[0],a=i[3],o=i[6],s=i[1],c=i[4],l=i[7];return i[0]=t*r+n*s,i[3]=t*a+n*c,i[6]=t*o+n*l,i[1]=-n*r+t*s,i[4]=-n*a+t*c,i[7]=-n*o+t*l,this},translate:function(e,t){var n=this.elements;return n[0]+=e*n[2],n[3]+=e*n[5],n[6]+=e*n[8],n[1]+=t*n[2],n[4]+=t*n[5],n[7]+=t*n[8],this},equals:function(e){for(var t=this.elements,n=e.elements,i=0;i<9;i++)if(t[i]!==n[i])return!1;return!0},fromArray:function(e,t){void 0===t&&(t=0);for(var n=0;n<9;n++)this.elements[n]=e[n+t];return this},toArray:function(e,t){void 0===e&&(e=[]),void 0===t&&(t=0);var n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}});var Yt={getDataURL:function(e){var t;if("undefined"==typeof HTMLCanvasElement)return e.src;if(e instanceof HTMLCanvasElement)t=e;else{void 0===jt&&(jt=document.createElementNS("http://www.w3.org/1999/xhtml","canvas")),jt.width=e.width,jt.height=e.height;var n=jt.getContext("2d");e instanceof ImageData?n.putImageData(e,0,0):n.drawImage(e,0,0,e.width,e.height),t=jt}return t.width>2048||t.height>2048?t.toDataURL("image/jpeg",.6):t.toDataURL("image/png")}},Zt=0;function Jt(e,t,n,i,r,a,o,s,c,l){Object.defineProperty(this,"id",{value:Zt++}),this.uuid=Wt.generateUUID(),this.name="",this.image=void 0!==e?e:Jt.DEFAULT_IMAGE,this.mipmaps=[],this.mapping=void 0!==t?t:Jt.DEFAULT_MAPPING,this.wrapS=void 0!==n?n:ie,this.wrapT=void 0!==i?i:ie,this.magFilter=void 0!==r?r:ce,this.minFilter=void 0!==a?a:he,this.anisotropy=void 0!==c?c:1,this.format=void 0!==o?o:Te,this.internalFormat=null,this.type=void 0!==s?s:ue,this.offset=new qt(0,0),this.repeat=new qt(1,1),this.center=new qt(0,0),this.rotation=0,this.matrixAutoUpdate=!0,this.matrix=new Xt,this.generateMipmaps=!0,this.premultiplyAlpha=!1,this.flipY=!0,this.unpackAlignment=4,this.encoding=void 0!==l?l:Tt,this.version=0,this.onUpdate=null}function Qt(e,t,n,i){this.x=e||0,this.y=t||0,this.z=n||0,this.w=void 0!==i?i:1}function Kt(e,t,n){this.width=e,this.height=t,this.scissor=new Qt(0,0,e,t),this.scissorTest=!1,this.viewport=new Qt(0,0,e,t),n=n||{},this.texture=new Jt(void 0,n.mapping,n.wrapS,n.wrapT,n.magFilter,n.minFilter,n.format,n.type,n.anisotropy,n.encoding),this.texture.image={},this.texture.image.width=e,this.texture.image.height=t,this.texture.generateMipmaps=void 0!==n.generateMipmaps&&n.generateMipmaps,this.texture.minFilter=void 0!==n.minFilter?n.minFilter:ce,this.depthBuffer=void 0===n.depthBuffer||n.depthBuffer,this.stencilBuffer=void 0===n.stencilBuffer||n.stencilBuffer,this.depthTexture=void 0!==n.depthTexture?n.depthTexture:null}function $t(e,t,n){Kt.call(this,e,t,n),this.samples=4}function en(e,t,n,i){this._x=e||0,this._y=t||0,this._z=n||0,this._w=void 0!==i?i:1}Jt.DEFAULT_IMAGE=void 0,Jt.DEFAULT_MAPPING=300,Jt.prototype=Object.assign(Object.create(Ht.prototype),{constructor:Jt,isTexture:!0,updateMatrix:function(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.name=e.name,this.image=e.image,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.encoding=e.encoding,this},toJSON:function(e){var t=void 0===e||"string"==typeof e;if(!t&&void 0!==e.textures[this.uuid])return e.textures[this.uuid];var n={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,type:this.type,encoding:this.encoding,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};if(void 0!==this.image){var i=this.image;if(void 0===i.uuid&&(i.uuid=Wt.generateUUID()),!t&&void 0===e.images[i.uuid]){var r;if(Array.isArray(i)){r=[];for(var a=0,o=i.length;a1)switch(this.wrapS){case ne:e.x=e.x-Math.floor(e.x);break;case ie:e.x=e.x<0?0:1;break;case re:1===Math.abs(Math.floor(e.x)%2)?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x)}if(e.y<0||e.y>1)switch(this.wrapT){case ne:e.y=e.y-Math.floor(e.y);break;case ie:e.y=e.y<0?0:1;break;case re:1===Math.abs(Math.floor(e.y)%2)?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y)}return this.flipY&&(e.y=1-e.y),e}}),Object.defineProperty(Jt.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.defineProperties(Qt.prototype,{width:{get:function(){return this.z},set:function(e){this.z=e}},height:{get:function(){return this.w},set:function(e){this.w=e}}}),Object.assign(Qt.prototype,{isVector4:!0,set:function(e,t,n,i){return this.x=e,this.y=t,this.z=n,this.w=i,this},setScalar:function(e){return this.x=e,this.y=e,this.z=e,this.w=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setZ:function(e){return this.z=e,this},setW:function(e){return this.w=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=void 0!==e.w?e.w:1,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this)},addScalar:function(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this)},subScalar:function(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this},multiplyScalar:function(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this},applyMatrix4:function(e){var t=this.x,n=this.y,i=this.z,r=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*i+a[12]*r,this.y=a[1]*t+a[5]*n+a[9]*i+a[13]*r,this.z=a[2]*t+a[6]*n+a[10]*i+a[14]*r,this.w=a[3]*t+a[7]*n+a[11]*i+a[15]*r,this},divideScalar:function(e){return this.multiplyScalar(1/e)},setAxisAngleFromQuaternion:function(e){this.w=2*Math.acos(e.w);var t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this},setAxisAngleFromRotationMatrix:function(e){var t,n,i,r,a=e.elements,o=a[0],s=a[4],c=a[8],l=a[1],h=a[5],u=a[9],p=a[2],d=a[6],f=a[10];if(Math.abs(s-l)<.01&&Math.abs(c-p)<.01&&Math.abs(u-d)<.01){if(Math.abs(s+l)<.1&&Math.abs(c+p)<.1&&Math.abs(u+d)<.1&&Math.abs(o+h+f-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;var m=(o+1)/2,g=(h+1)/2,v=(f+1)/2,y=(s+l)/4,x=(c+p)/4,b=(u+d)/4;return m>g&&m>v?m<.01?(n=0,i=.707106781,r=.707106781):(i=y/(n=Math.sqrt(m)),r=x/n):g>v?g<.01?(n=.707106781,i=0,r=.707106781):(n=y/(i=Math.sqrt(g)),r=b/i):v<.01?(n=.707106781,i=.707106781,r=0):(n=x/(r=Math.sqrt(v)),i=b/r),this.set(n,i,r,t),this}var _=Math.sqrt((d-u)*(d-u)+(c-p)*(c-p)+(l-s)*(l-s));return Math.abs(_)<.001&&(_=1),this.x=(d-u)/_,this.y=(c-p)/_,this.z=(l-s)/_,this.w=Math.acos((o+h+f-1)/2),this},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this.w=Math.max(e.w,Math.min(t.w,this.w)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this.w=Math.max(e,Math.min(t,this.w)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this.w=this.w<0?Math.ceil(this.w):Math.floor(this.w),this},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this},dot:function(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},equals:function(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}}),Kt.prototype=Object.assign(Object.create(Ht.prototype),{constructor:Kt,isWebGLRenderTarget:!0,setSize:function(e,t){this.width===e&&this.height===t||(this.width=e,this.height=t,this.texture.image.width=e,this.texture.image.height=t,this.dispose()),this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.width=e.width,this.height=e.height,this.viewport.copy(e.viewport),this.texture=e.texture.clone(),this.depthBuffer=e.depthBuffer,this.stencilBuffer=e.stencilBuffer,this.depthTexture=e.depthTexture,this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),$t.prototype=Object.assign(Object.create(Kt.prototype),{constructor:$t,isWebGLMultisampleRenderTarget:!0,copy:function(e){return Kt.prototype.copy.call(this,e),this.samples=e.samples,this}}),Object.assign(en,{slerp:function(e,t,n,i){return n.copy(e).slerp(t,i)},slerpFlat:function(e,t,n,i,r,a,o){var s=n[i+0],c=n[i+1],l=n[i+2],h=n[i+3],u=r[a+0],p=r[a+1],d=r[a+2],f=r[a+3];if(h!==f||s!==u||c!==p||l!==d){var m=1-o,g=s*u+c*p+l*d+h*f,v=g>=0?1:-1,y=1-g*g;if(y>Number.EPSILON){var x=Math.sqrt(y),b=Math.atan2(x,g*v);m=Math.sin(m*b)/x,o=Math.sin(o*b)/x}var _=o*v;if(s=s*m+u*_,c=c*m+p*_,l=l*m+d*_,h=h*m+f*_,m===1-o){var w=1/Math.sqrt(s*s+c*c+l*l+h*h);s*=w,c*=w,l*=w,h*=w}}e[t]=s,e[t+1]=c,e[t+2]=l,e[t+3]=h}}),Object.defineProperties(en.prototype,{x:{get:function(){return this._x},set:function(e){this._x=e,this._onChangeCallback()}},y:{get:function(){return this._y},set:function(e){this._y=e,this._onChangeCallback()}},z:{get:function(){return this._z},set:function(e){this._z=e,this._onChangeCallback()}},w:{get:function(){return this._w},set:function(e){this._w=e,this._onChangeCallback()}}}),Object.assign(en.prototype,{isQuaternion:!0,set:function(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._w=i,this._onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this},setFromEuler:function(e,t){if(!e||!e.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var n=e._x,i=e._y,r=e._z,a=e.order,o=Math.cos,s=Math.sin,c=o(n/2),l=o(i/2),h=o(r/2),u=s(n/2),p=s(i/2),d=s(r/2);return"XYZ"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h-u*p*d):"YXZ"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h+u*p*d):"ZXY"===a?(this._x=u*l*h-c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h-u*p*d):"ZYX"===a?(this._x=u*l*h-c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h+u*p*d):"YZX"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h-u*p*d):"XZY"===a&&(this._x=u*l*h-c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h+u*p*d),!1!==t&&this._onChangeCallback(),this},setFromAxisAngle:function(e,t){var n=t/2,i=Math.sin(n);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(n),this._onChangeCallback(),this},setFromRotationMatrix:function(e){var t,n=e.elements,i=n[0],r=n[4],a=n[8],o=n[1],s=n[5],c=n[9],l=n[2],h=n[6],u=n[10],p=i+s+u;return p>0?(t=.5/Math.sqrt(p+1),this._w=.25/t,this._x=(h-c)*t,this._y=(a-l)*t,this._z=(o-r)*t):i>s&&i>u?(t=2*Math.sqrt(1+i-s-u),this._w=(h-c)/t,this._x=.25*t,this._y=(r+o)/t,this._z=(a+l)/t):s>u?(t=2*Math.sqrt(1+s-i-u),this._w=(a-l)/t,this._x=(r+o)/t,this._y=.25*t,this._z=(c+h)/t):(t=2*Math.sqrt(1+u-i-s),this._w=(o-r)/t,this._x=(a+l)/t,this._y=(c+h)/t,this._z=.25*t),this._onChangeCallback(),this},setFromUnitVectors:function(e,t){var n=e.dot(t)+1;return n<1e-6?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()},angleTo:function(e){return 2*Math.acos(Math.abs(Wt.clamp(this.dot(e),-1,1)))},rotateTowards:function(e,t){var n=this.angleTo(e);if(0===n)return this;var i=Math.min(1,t/n);return this.slerp(e,i),this},inverse:function(){return this.conjugate()},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this},dot:function(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var e=this.length();return 0===e?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(e,t)):this.multiplyQuaternions(this,e)},premultiply:function(e){return this.multiplyQuaternions(e,this)},multiplyQuaternions:function(e,t){var n=e._x,i=e._y,r=e._z,a=e._w,o=t._x,s=t._y,c=t._z,l=t._w;return this._x=n*l+a*o+i*c-r*s,this._y=i*l+a*s+r*o-n*c,this._z=r*l+a*c+n*s-i*o,this._w=a*l-n*o-i*s-r*c,this._onChangeCallback(),this},slerp:function(e,t){if(0===t)return this;if(1===t)return this.copy(e);var n=this._x,i=this._y,r=this._z,a=this._w,o=a*e._w+n*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=i,this._z=r,this;var s=1-o*o;if(s<=Number.EPSILON){var c=1-t;return this._w=c*a+t*this._w,this._x=c*n+t*this._x,this._y=c*i+t*this._y,this._z=c*r+t*this._z,this.normalize(),this._onChangeCallback(),this}var l=Math.sqrt(s),h=Math.atan2(l,o),u=Math.sin((1-t)*h)/l,p=Math.sin(t*h)/l;return this._w=a*u+this._w*p,this._x=n*u+this._x*p,this._y=i*u+this._y*p,this._z=r*u+this._z*p,this._onChangeCallback(),this},equals:function(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w},fromArray:function(e,t){return void 0===t&&(t=0),this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e},_onChange:function(e){return this._onChangeCallback=e,this},_onChangeCallback:function(){}});var tn=new rn,nn=new en;function rn(e,t,n){this.x=e||0,this.y=t||0,this.z=n||0}Object.assign(rn.prototype,{isVector3:!0,set:function(e,t,n){return this.x=e,this.y=t,this.z=n,this},setScalar:function(e){return this.x=e,this.y=e,this.z=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setZ:function(e){return this.z=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this.z+=e.z,this)},addScalar:function(e){return this.x+=e,this.y+=e,this.z+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this.z-=e.z,this)},subScalar:function(e){return this.x-=e,this.y-=e,this.z-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(e,t)):(this.x*=e.x,this.y*=e.y,this.z*=e.z,this)},multiplyScalar:function(e){return this.x*=e,this.y*=e,this.z*=e,this},multiplyVectors:function(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this},applyEuler:function(e){return e&&e.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(nn.setFromEuler(e))},applyAxisAngle:function(e,t){return this.applyQuaternion(nn.setFromAxisAngle(e,t))},applyMatrix3:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*i,this.y=r[1]*t+r[4]*n+r[7]*i,this.z=r[2]*t+r[5]*n+r[8]*i,this},applyNormalMatrix:function(e){return this.applyMatrix3(e).normalize()},applyMatrix4:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements,a=1/(r[3]*t+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*i+r[12])*a,this.y=(r[1]*t+r[5]*n+r[9]*i+r[13])*a,this.z=(r[2]*t+r[6]*n+r[10]*i+r[14])*a,this},applyQuaternion:function(e){var t=this.x,n=this.y,i=this.z,r=e.x,a=e.y,o=e.z,s=e.w,c=s*t+a*i-o*n,l=s*n+o*t-r*i,h=s*i+r*n-a*t,u=-r*t-a*n-o*i;return this.x=c*s+u*-r+l*-o-h*-a,this.y=l*s+u*-a+h*-r-c*-o,this.z=h*s+u*-o+c*-a-l*-r,this},project:function(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)},unproject:function(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)},transformDirection:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*i,this.y=r[1]*t+r[5]*n+r[9]*i,this.z=r[2]*t+r[6]*n+r[10]*i,this.normalize()},divide:function(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this},divideScalar:function(e){return this.multiplyScalar(1/e)},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this},dot:function(e){return this.x*e.x+this.y*e.y+this.z*e.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},cross:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(e,t)):this.crossVectors(this,e)},crossVectors:function(e,t){var n=e.x,i=e.y,r=e.z,a=t.x,o=t.y,s=t.z;return this.x=i*s-r*o,this.y=r*a-n*s,this.z=n*o-i*a,this},projectOnVector:function(e){var t=e.lengthSq();if(0===t)return this.set(0,0,0);var n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)},projectOnPlane:function(e){return tn.copy(this).projectOnVector(e),this.sub(tn)},reflect:function(e){return this.sub(tn.copy(e).multiplyScalar(2*this.dot(e)))},angleTo:function(e){var t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;var n=this.dot(e)/t;return Math.acos(Wt.clamp(n,-1,1))},distanceTo:function(e){return Math.sqrt(this.distanceToSquared(e))},distanceToSquared:function(e){var t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i},manhattanDistanceTo:function(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)},setFromSpherical:function(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)},setFromSphericalCoords:function(e,t,n){var i=Math.sin(t)*e;return this.x=i*Math.sin(n),this.y=Math.cos(t)*e,this.z=i*Math.cos(n),this},setFromCylindrical:function(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)},setFromCylindricalCoords:function(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this},setFromMatrixPosition:function(e){var t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this},setFromMatrixScale:function(e){var t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=i,this},setFromMatrixColumn:function(e,t){return this.fromArray(e.elements,4*t)},setFromMatrix3Column:function(e,t){return this.fromArray(e.elements,3*t)},equals:function(e){return e.x===this.x&&e.y===this.y&&e.z===this.z},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this.z=e[t+2],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}});var an=new rn,on=new pn,sn=new rn(0,0,0),cn=new rn(1,1,1),ln=new rn,hn=new rn,un=new rn;function pn(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}Object.assign(pn.prototype,{isMatrix4:!0,set:function(e,t,n,i,r,a,o,s,c,l,h,u,p,d,f,m){var g=this.elements;return g[0]=e,g[4]=t,g[8]=n,g[12]=i,g[1]=r,g[5]=a,g[9]=o,g[13]=s,g[2]=c,g[6]=l,g[10]=h,g[14]=u,g[3]=p,g[7]=d,g[11]=f,g[15]=m,this},identity:function(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this},clone:function(){return(new pn).fromArray(this.elements)},copy:function(e){var t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this},copyPosition:function(e){var t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this},extractBasis:function(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this},makeBasis:function(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this},extractRotation:function(e){var t=this.elements,n=e.elements,i=1/an.setFromMatrixColumn(e,0).length(),r=1/an.setFromMatrixColumn(e,1).length(),a=1/an.setFromMatrixColumn(e,2).length();return t[0]=n[0]*i,t[1]=n[1]*i,t[2]=n[2]*i,t[3]=0,t[4]=n[4]*r,t[5]=n[5]*r,t[6]=n[6]*r,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this},makeRotationFromEuler:function(e){e&&e.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var t=this.elements,n=e.x,i=e.y,r=e.z,a=Math.cos(n),o=Math.sin(n),s=Math.cos(i),c=Math.sin(i),l=Math.cos(r),h=Math.sin(r);if("XYZ"===e.order){var u=a*l,p=a*h,d=o*l,f=o*h;t[0]=s*l,t[4]=-s*h,t[8]=c,t[1]=p+d*c,t[5]=u-f*c,t[9]=-o*s,t[2]=f-u*c,t[6]=d+p*c,t[10]=a*s}else if("YXZ"===e.order){var m=s*l,g=s*h,v=c*l,y=c*h;t[0]=m+y*o,t[4]=v*o-g,t[8]=a*c,t[1]=a*h,t[5]=a*l,t[9]=-o,t[2]=g*o-v,t[6]=y+m*o,t[10]=a*s}else if("ZXY"===e.order){m=s*l,g=s*h,v=c*l,y=c*h;t[0]=m-y*o,t[4]=-a*h,t[8]=v+g*o,t[1]=g+v*o,t[5]=a*l,t[9]=y-m*o,t[2]=-a*c,t[6]=o,t[10]=a*s}else if("ZYX"===e.order){u=a*l,p=a*h,d=o*l,f=o*h;t[0]=s*l,t[4]=d*c-p,t[8]=u*c+f,t[1]=s*h,t[5]=f*c+u,t[9]=p*c-d,t[2]=-c,t[6]=o*s,t[10]=a*s}else if("YZX"===e.order){var x=a*s,b=a*c,_=o*s,w=o*c;t[0]=s*l,t[4]=w-x*h,t[8]=_*h+b,t[1]=h,t[5]=a*l,t[9]=-o*l,t[2]=-c*l,t[6]=b*h+_,t[10]=x-w*h}else if("XZY"===e.order){x=a*s,b=a*c,_=o*s,w=o*c;t[0]=s*l,t[4]=-h,t[8]=c*l,t[1]=x*h+w,t[5]=a*l,t[9]=b*h-_,t[2]=_*h-b,t[6]=o*l,t[10]=w*h+x}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this},makeRotationFromQuaternion:function(e){return this.compose(sn,e,cn)},lookAt:function(e,t,n){var i=this.elements;return un.subVectors(e,t),0===un.lengthSq()&&(un.z=1),un.normalize(),ln.crossVectors(n,un),0===ln.lengthSq()&&(1===Math.abs(n.z)?un.x+=1e-4:un.z+=1e-4,un.normalize(),ln.crossVectors(n,un)),ln.normalize(),hn.crossVectors(un,ln),i[0]=ln.x,i[4]=hn.x,i[8]=un.x,i[1]=ln.y,i[5]=hn.y,i[9]=un.y,i[2]=ln.z,i[6]=hn.z,i[10]=un.z,this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(e,t)):this.multiplyMatrices(this,e)},premultiply:function(e){return this.multiplyMatrices(e,this)},multiplyMatrices:function(e,t){var n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[4],s=n[8],c=n[12],l=n[1],h=n[5],u=n[9],p=n[13],d=n[2],f=n[6],m=n[10],g=n[14],v=n[3],y=n[7],x=n[11],b=n[15],_=i[0],w=i[4],M=i[8],S=i[12],T=i[1],E=i[5],A=i[9],L=i[13],R=i[2],P=i[6],C=i[10],O=i[14],D=i[3],I=i[7],N=i[11],B=i[15];return r[0]=a*_+o*T+s*R+c*D,r[4]=a*w+o*E+s*P+c*I,r[8]=a*M+o*A+s*C+c*N,r[12]=a*S+o*L+s*O+c*B,r[1]=l*_+h*T+u*R+p*D,r[5]=l*w+h*E+u*P+p*I,r[9]=l*M+h*A+u*C+p*N,r[13]=l*S+h*L+u*O+p*B,r[2]=d*_+f*T+m*R+g*D,r[6]=d*w+f*E+m*P+g*I,r[10]=d*M+f*A+m*C+g*N,r[14]=d*S+f*L+m*O+g*B,r[3]=v*_+y*T+x*R+b*D,r[7]=v*w+y*E+x*P+b*I,r[11]=v*M+y*A+x*C+b*N,r[15]=v*S+y*L+x*O+b*B,this},multiplyScalar:function(e){var t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this},determinant:function(){var e=this.elements,t=e[0],n=e[4],i=e[8],r=e[12],a=e[1],o=e[5],s=e[9],c=e[13],l=e[2],h=e[6],u=e[10],p=e[14];return e[3]*(+r*s*h-i*c*h-r*o*u+n*c*u+i*o*p-n*s*p)+e[7]*(+t*s*p-t*c*u+r*a*u-i*a*p+i*c*l-r*s*l)+e[11]*(+t*c*h-t*o*p-r*a*h+n*a*p+r*o*l-n*c*l)+e[15]*(-i*o*l-t*s*h+t*o*u+i*a*h-n*a*u+n*s*l)},transpose:function(){var e,t=this.elements;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this},setPosition:function(e,t,n){var i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=n),this},getInverse:function(e,t){var n=this.elements,i=e.elements,r=i[0],a=i[1],o=i[2],s=i[3],c=i[4],l=i[5],h=i[6],u=i[7],p=i[8],d=i[9],f=i[10],m=i[11],g=i[12],v=i[13],y=i[14],x=i[15],b=d*y*u-v*f*u+v*h*m-l*y*m-d*h*x+l*f*x,_=g*f*u-p*y*u-g*h*m+c*y*m+p*h*x-c*f*x,w=p*v*u-g*d*u+g*l*m-c*v*m-p*l*x+c*d*x,M=g*d*h-p*v*h-g*l*f+c*v*f+p*l*y-c*d*y,S=r*b+a*_+o*w+s*M;if(0===S){var T="THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";if(!0===t)throw new Error(T);return console.warn(T),this.identity()}var E=1/S;return n[0]=b*E,n[1]=(v*f*s-d*y*s-v*o*m+a*y*m+d*o*x-a*f*x)*E,n[2]=(l*y*s-v*h*s+v*o*u-a*y*u-l*o*x+a*h*x)*E,n[3]=(d*h*s-l*f*s-d*o*u+a*f*u+l*o*m-a*h*m)*E,n[4]=_*E,n[5]=(p*y*s-g*f*s+g*o*m-r*y*m-p*o*x+r*f*x)*E,n[6]=(g*h*s-c*y*s-g*o*u+r*y*u+c*o*x-r*h*x)*E,n[7]=(c*f*s-p*h*s+p*o*u-r*f*u-c*o*m+r*h*m)*E,n[8]=w*E,n[9]=(g*d*s-p*v*s-g*a*m+r*v*m+p*a*x-r*d*x)*E,n[10]=(c*v*s-g*l*s+g*a*u-r*v*u-c*a*x+r*l*x)*E,n[11]=(p*l*s-c*d*s-p*a*u+r*d*u+c*a*m-r*l*m)*E,n[12]=M*E,n[13]=(p*v*o-g*d*o+g*a*f-r*v*f-p*a*y+r*d*y)*E,n[14]=(g*l*o-c*v*o-g*a*h+r*v*h+c*a*y-r*l*y)*E,n[15]=(c*d*o-p*l*o+p*a*h-r*d*h-c*a*f+r*l*f)*E,this},scale:function(e){var t=this.elements,n=e.x,i=e.y,r=e.z;return t[0]*=n,t[4]*=i,t[8]*=r,t[1]*=n,t[5]*=i,t[9]*=r,t[2]*=n,t[6]*=i,t[10]*=r,t[3]*=n,t[7]*=i,t[11]*=r,this},getMaxScaleOnAxis:function(){var e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,i))},makeTranslation:function(e,t,n){return this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this},makeRotationX:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this},makeRotationY:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this},makeRotationZ:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this},makeRotationAxis:function(e,t){var n=Math.cos(t),i=Math.sin(t),r=1-n,a=e.x,o=e.y,s=e.z,c=r*a,l=r*o;return this.set(c*a+n,c*o-i*s,c*s+i*o,0,c*o+i*s,l*o+n,l*s-i*a,0,c*s-i*o,l*s+i*a,r*s*s+n,0,0,0,0,1),this},makeScale:function(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this},makeShear:function(e,t,n){return this.set(1,t,n,0,e,1,n,0,e,t,1,0,0,0,0,1),this},compose:function(e,t,n){var i=this.elements,r=t._x,a=t._y,o=t._z,s=t._w,c=r+r,l=a+a,h=o+o,u=r*c,p=r*l,d=r*h,f=a*l,m=a*h,g=o*h,v=s*c,y=s*l,x=s*h,b=n.x,_=n.y,w=n.z;return i[0]=(1-(f+g))*b,i[1]=(p+x)*b,i[2]=(d-y)*b,i[3]=0,i[4]=(p-x)*_,i[5]=(1-(u+g))*_,i[6]=(m+v)*_,i[7]=0,i[8]=(d+y)*w,i[9]=(m-v)*w,i[10]=(1-(u+f))*w,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this},decompose:function(e,t,n){var i=this.elements,r=an.set(i[0],i[1],i[2]).length(),a=an.set(i[4],i[5],i[6]).length(),o=an.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],on.copy(this);var s=1/r,c=1/a,l=1/o;return on.elements[0]*=s,on.elements[1]*=s,on.elements[2]*=s,on.elements[4]*=c,on.elements[5]*=c,on.elements[6]*=c,on.elements[8]*=l,on.elements[9]*=l,on.elements[10]*=l,t.setFromRotationMatrix(on),n.x=r,n.y=a,n.z=o,this},makePerspective:function(e,t,n,i,r,a){void 0===a&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");var o=this.elements,s=2*r/(t-e),c=2*r/(n-i),l=(t+e)/(t-e),h=(n+i)/(n-i),u=-(a+r)/(a-r),p=-2*a*r/(a-r);return o[0]=s,o[4]=0,o[8]=l,o[12]=0,o[1]=0,o[5]=c,o[9]=h,o[13]=0,o[2]=0,o[6]=0,o[10]=u,o[14]=p,o[3]=0,o[7]=0,o[11]=-1,o[15]=0,this},makeOrthographic:function(e,t,n,i,r,a){var o=this.elements,s=1/(t-e),c=1/(n-i),l=1/(a-r),h=(t+e)*s,u=(n+i)*c,p=(a+r)*l;return o[0]=2*s,o[4]=0,o[8]=0,o[12]=-h,o[1]=0,o[5]=2*c,o[9]=0,o[13]=-u,o[2]=0,o[6]=0,o[10]=-2*l,o[14]=-p,o[3]=0,o[7]=0,o[11]=0,o[15]=1,this},equals:function(e){for(var t=this.elements,n=e.elements,i=0;i<16;i++)if(t[i]!==n[i])return!1;return!0},fromArray:function(e,t){void 0===t&&(t=0);for(var n=0;n<16;n++)this.elements[n]=e[n+t];return this},toArray:function(e,t){void 0===e&&(e=[]),void 0===t&&(t=0);var n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}});var dn=new pn,fn=new en;function mn(e,t,n,i){this._x=e||0,this._y=t||0,this._z=n||0,this._order=i||mn.DefaultOrder}function gn(){this.mask=1}mn.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"],mn.DefaultOrder="XYZ",Object.defineProperties(mn.prototype,{x:{get:function(){return this._x},set:function(e){this._x=e,this._onChangeCallback()}},y:{get:function(){return this._y},set:function(e){this._y=e,this._onChangeCallback()}},z:{get:function(){return this._z},set:function(e){this._z=e,this._onChangeCallback()}},order:{get:function(){return this._order},set:function(e){this._order=e,this._onChangeCallback()}}}),Object.assign(mn.prototype,{isEuler:!0,set:function(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._order=i||this._order,this._onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this},setFromRotationMatrix:function(e,t,n){var i=Wt.clamp,r=e.elements,a=r[0],o=r[4],s=r[8],c=r[1],l=r[5],h=r[9],u=r[2],p=r[6],d=r[10];return"XYZ"===(t=t||this._order)?(this._y=Math.asin(i(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(-h,d),this._z=Math.atan2(-o,a)):(this._x=Math.atan2(p,l),this._z=0)):"YXZ"===t?(this._x=Math.asin(-i(h,-1,1)),Math.abs(h)<.9999999?(this._y=Math.atan2(s,d),this._z=Math.atan2(c,l)):(this._y=Math.atan2(-u,a),this._z=0)):"ZXY"===t?(this._x=Math.asin(i(p,-1,1)),Math.abs(p)<.9999999?(this._y=Math.atan2(-u,d),this._z=Math.atan2(-o,l)):(this._y=0,this._z=Math.atan2(c,a))):"ZYX"===t?(this._y=Math.asin(-i(u,-1,1)),Math.abs(u)<.9999999?(this._x=Math.atan2(p,d),this._z=Math.atan2(c,a)):(this._x=0,this._z=Math.atan2(-o,l))):"YZX"===t?(this._z=Math.asin(i(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(-h,l),this._y=Math.atan2(-u,a)):(this._x=0,this._y=Math.atan2(s,d))):"XZY"===t?(this._z=Math.asin(-i(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(p,l),this._y=Math.atan2(s,a)):(this._x=Math.atan2(-h,d),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+t),this._order=t,!1!==n&&this._onChangeCallback(),this},setFromQuaternion:function(e,t,n){return dn.makeRotationFromQuaternion(e),this.setFromRotationMatrix(dn,t,n)},setFromVector3:function(e,t){return this.set(e.x,e.y,e.z,t||this._order)},reorder:function(e){return fn.setFromEuler(this),this.setFromQuaternion(fn,e)},equals:function(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order},fromArray:function(e){return this._x=e[0],this._y=e[1],this._z=e[2],void 0!==e[3]&&(this._order=e[3]),this._onChangeCallback(),this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e},toVector3:function(e){return e?e.set(this._x,this._y,this._z):new rn(this._x,this._y,this._z)},_onChange:function(e){return this._onChangeCallback=e,this},_onChangeCallback:function(){}}),Object.assign(gn.prototype,{set:function(e){this.mask=1<1){for(var t=0;t1){for(var t=0;t0){i.children=[];for(s=0;s0&&(n.geometries=u),p.length>0&&(n.materials=p),d.length>0&&(n.textures=d),f.length>0&&(n.images=f),o.length>0&&(n.shapes=o)}return n.object=i,n;function m(e){var t=[];for(var n in e){var i=e[n];delete i.metadata,t.push(i)}return t}},clone:function(e){return(new this.constructor).copy(this,e)},copy:function(e,t){if(void 0===t&&(t=!0),this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.userData=JSON.parse(JSON.stringify(e.userData)),!0===t)for(var n=0;ns)return!1}return!0}Object.assign(Wn.prototype,{isBox3:!0,set:function(e,t){return this.min.copy(e),this.max.copy(t),this},setFromArray:function(e){for(var t=1/0,n=1/0,i=1/0,r=-1/0,a=-1/0,o=-1/0,s=0,c=e.length;sr&&(r=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(t,n,i),this.max.set(r,a,o),this},setFromBufferAttribute:function(e){for(var t=1/0,n=1/0,i=1/0,r=-1/0,a=-1/0,o=-1/0,s=0,c=e.count;sr&&(r=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(t,n,i),this.max.set(r,a,o),this},setFromPoints:function(e){this.makeEmpty();for(var t=0,n=e.length;tthis.max.x||e.ythis.max.y||e.zthis.max.z)},containsBox:function(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z},getParameter:function(e,t){return void 0===t&&(console.warn("THREE.Box3: .getParameter() target is now required"),t=new rn),t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(e){return!(e.max.xthis.max.x||e.max.ythis.max.y||e.max.zthis.max.z)},intersectsSphere:function(e){return this.clampPoint(e.center,Dn),Dn.distanceToSquared(e.center)<=e.radius*e.radius},intersectsPlane:function(e){var t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant},intersectsTriangle:function(e){if(this.isEmpty())return!1;this.getCenter(Hn),Vn.subVectors(this.max,Hn),Nn.subVectors(e.a,Hn),Bn.subVectors(e.b,Hn),zn.subVectors(e.c,Hn),Fn.subVectors(Bn,Nn),Un.subVectors(zn,Bn),Gn.subVectors(Nn,zn);var t=[0,-Fn.z,Fn.y,0,-Un.z,Un.y,0,-Gn.z,Gn.y,Fn.z,0,-Fn.x,Un.z,0,-Un.x,Gn.z,0,-Gn.x,-Fn.y,Fn.x,0,-Un.y,Un.x,0,-Gn.y,Gn.x,0];return!!qn(t,Nn,Bn,zn,Vn)&&(!!qn(t=[1,0,0,0,1,0,0,0,1],Nn,Bn,zn,Vn)&&(kn.crossVectors(Fn,Un),qn(t=[kn.x,kn.y,kn.z],Nn,Bn,zn,Vn)))},clampPoint:function(e,t){return void 0===t&&(console.warn("THREE.Box3: .clampPoint() target is now required"),t=new rn),t.copy(e).clamp(this.min,this.max)},distanceToPoint:function(e){return Dn.copy(e).clamp(this.min,this.max).sub(e).length()},getBoundingSphere:function(e){return void 0===e&&console.error("THREE.Box3: .getBoundingSphere() target is now required"),this.getCenter(e.center),e.radius=.5*this.getSize(Dn).length(),e},intersect:function(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this},union:function(e){return this.min.min(e.min),this.max.max(e.max),this},applyMatrix4:function(e){return this.isEmpty()?this:(On[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),On[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),On[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),On[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),On[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),On[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),On[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),On[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(On),this)},translate:function(e){return this.min.add(e),this.max.add(e),this},equals:function(e){return e.min.equals(this.min)&&e.max.equals(this.max)}});var Xn=new Wn;function Yn(e,t){this.center=void 0!==e?e:new rn,this.radius=void 0!==t?t:0}Object.assign(Yn.prototype,{set:function(e,t){return this.center.copy(e),this.radius=t,this},setFromPoints:function(e,t){var n=this.center;void 0!==t?n.copy(t):Xn.setFromPoints(e).getCenter(n);for(var i=0,r=0,a=e.length;rthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t},getBoundingBox:function(e){return void 0===e&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),e=new Wn),e.set(this.center,this.center),e.expandByScalar(this.radius),e},applyMatrix4:function(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this},translate:function(e){return this.center.add(e),this},equals:function(e){return e.center.equals(this.center)&&e.radius===this.radius}});var Zn=new rn,Jn=new rn,Qn=new rn,Kn=new rn,$n=new rn,ei=new rn,ti=new rn;function ni(e,t){this.origin=void 0!==e?e:new rn,this.direction=void 0!==t?t:new rn(0,0,-1)}Object.assign(ni.prototype,{set:function(e,t){return this.origin.copy(e),this.direction.copy(t),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this},at:function(e,t){return void 0===t&&(console.warn("THREE.Ray: .at() target is now required"),t=new rn),t.copy(this.direction).multiplyScalar(e).add(this.origin)},lookAt:function(e){return this.direction.copy(e).sub(this.origin).normalize(),this},recast:function(e){return this.origin.copy(this.at(e,Zn)),this},closestPointToPoint:function(e,t){void 0===t&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"),t=new rn),t.subVectors(e,this.origin);var n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.direction).multiplyScalar(n).add(this.origin)},distanceToPoint:function(e){return Math.sqrt(this.distanceSqToPoint(e))},distanceSqToPoint:function(e){var t=Zn.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Zn.copy(this.direction).multiplyScalar(t).add(this.origin),Zn.distanceToSquared(e))},distanceSqToSegment:function(e,t,n,i){Jn.copy(e).add(t).multiplyScalar(.5),Qn.copy(t).sub(e).normalize(),Kn.copy(this.origin).sub(Jn);var r,a,o,s,c=.5*e.distanceTo(t),l=-this.direction.dot(Qn),h=Kn.dot(this.direction),u=-Kn.dot(Qn),p=Kn.lengthSq(),d=Math.abs(1-l*l);if(d>0)if(a=l*h-u,s=c*d,(r=l*u-h)>=0)if(a>=-s)if(a<=s){var f=1/d;o=(r*=f)*(r+l*(a*=f)+2*h)+a*(l*r+a+2*u)+p}else a=c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;else a=-c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;else a<=-s?o=-(r=Math.max(0,-(-l*c+h)))*r+(a=r>0?-c:Math.min(Math.max(-c,-u),c))*(a+2*u)+p:a<=s?(r=0,o=(a=Math.min(Math.max(-c,-u),c))*(a+2*u)+p):o=-(r=Math.max(0,-(l*c+h)))*r+(a=r>0?c:Math.min(Math.max(-c,-u),c))*(a+2*u)+p;else a=l>0?-c:c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;return n&&n.copy(this.direction).multiplyScalar(r).add(this.origin),i&&i.copy(Qn).multiplyScalar(a).add(Jn),o},intersectSphere:function(e,t){Zn.subVectors(e.center,this.origin);var n=Zn.dot(this.direction),i=Zn.dot(Zn)-n*n,r=e.radius*e.radius;if(i>r)return null;var a=Math.sqrt(r-i),o=n-a,s=n+a;return o<0&&s<0?null:o<0?this.at(s,t):this.at(o,t)},intersectsSphere:function(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius},distanceToPlane:function(e){var t=e.normal.dot(this.direction);if(0===t)return 0===e.distanceToPoint(this.origin)?0:null;var n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null},intersectPlane:function(e,t){var n=this.distanceToPlane(e);return null===n?null:this.at(n,t)},intersectsPlane:function(e){var t=e.distanceToPoint(this.origin);return 0===t||e.normal.dot(this.direction)*t<0},intersectBox:function(e,t){var n,i,r,a,o,s,c=1/this.direction.x,l=1/this.direction.y,h=1/this.direction.z,u=this.origin;return c>=0?(n=(e.min.x-u.x)*c,i=(e.max.x-u.x)*c):(n=(e.max.x-u.x)*c,i=(e.min.x-u.x)*c),l>=0?(r=(e.min.y-u.y)*l,a=(e.max.y-u.y)*l):(r=(e.max.y-u.y)*l,a=(e.min.y-u.y)*l),n>a||r>i?null:((r>n||n!=n)&&(n=r),(a=0?(o=(e.min.z-u.z)*h,s=(e.max.z-u.z)*h):(o=(e.max.z-u.z)*h,s=(e.min.z-u.z)*h),n>s||o>i?null:((o>n||n!=n)&&(n=o),(s=0?n:i,t)))},intersectsBox:function(e){return null!==this.intersectBox(e,Zn)},intersectTriangle:function(e,t,n,i,r){$n.subVectors(t,e),ei.subVectors(n,e),ti.crossVectors($n,ei);var a,o=this.direction.dot(ti);if(o>0){if(i)return null;a=1}else{if(!(o<0))return null;a=-1,o=-o}Kn.subVectors(this.origin,e);var s=a*this.direction.dot(ei.crossVectors(Kn,ei));if(s<0)return null;var c=a*this.direction.dot($n.cross(Kn));if(c<0)return null;if(s+c>o)return null;var l=-a*Kn.dot(ti);return l<0?null:this.at(l/o,r)},applyMatrix4:function(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this},equals:function(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}});var ii=new rn,ri=new rn,ai=new Xt;function oi(e,t){this.normal=void 0!==e?e:new rn(1,0,0),this.constant=void 0!==t?t:0}Object.assign(oi.prototype,{isPlane:!0,set:function(e,t){return this.normal.copy(e),this.constant=t,this},setComponents:function(e,t,n,i){return this.normal.set(e,t,n),this.constant=i,this},setFromNormalAndCoplanarPoint:function(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this},setFromCoplanarPoints:function(e,t,n){var i=ii.subVectors(n,t).cross(ri.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(i,e),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.normal.copy(e.normal),this.constant=e.constant,this},normalize:function(){var e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this},negate:function(){return this.constant*=-1,this.normal.negate(),this},distanceToPoint:function(e){return this.normal.dot(e)+this.constant},distanceToSphere:function(e){return this.distanceToPoint(e.center)-e.radius},projectPoint:function(e,t){return void 0===t&&(console.warn("THREE.Plane: .projectPoint() target is now required"),t=new rn),t.copy(this.normal).multiplyScalar(-this.distanceToPoint(e)).add(e)},intersectLine:function(e,t){void 0===t&&(console.warn("THREE.Plane: .intersectLine() target is now required"),t=new rn);var n=e.delta(ii),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(e.start)?t.copy(e.start):void 0;var r=-(e.start.dot(this.normal)+this.constant)/i;return r<0||r>1?void 0:t.copy(n).multiplyScalar(r).add(e.start)},intersectsLine:function(e){var t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0},intersectsBox:function(e){return e.intersectsPlane(this)},intersectsSphere:function(e){return e.intersectsPlane(this)},coplanarPoint:function(e){return void 0===e&&(console.warn("THREE.Plane: .coplanarPoint() target is now required"),e=new rn),e.copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(e,t){var n=t||ai.getNormalMatrix(e),i=this.coplanarPoint(ii).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this},translate:function(e){return this.constant-=e.dot(this.normal),this},equals:function(e){return e.normal.equals(this.normal)&&e.constant===this.constant}});var si=new rn,ci=new rn,li=new rn,hi=new rn,ui=new rn,pi=new rn,di=new rn,fi=new rn,mi=new rn,gi=new rn;function vi(e,t,n){this.a=void 0!==e?e:new rn,this.b=void 0!==t?t:new rn,this.c=void 0!==n?n:new rn}Object.assign(vi,{getNormal:function(e,t,n,i){void 0===i&&(console.warn("THREE.Triangle: .getNormal() target is now required"),i=new rn),i.subVectors(n,t),si.subVectors(e,t),i.cross(si);var r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)},getBarycoord:function(e,t,n,i,r){si.subVectors(i,t),ci.subVectors(n,t),li.subVectors(e,t);var a=si.dot(si),o=si.dot(ci),s=si.dot(li),c=ci.dot(ci),l=ci.dot(li),h=a*c-o*o;if(void 0===r&&(console.warn("THREE.Triangle: .getBarycoord() target is now required"),r=new rn),0===h)return r.set(-2,-1,-1);var u=1/h,p=(c*s-o*l)*u,d=(a*l-o*s)*u;return r.set(1-p-d,d,p)},containsPoint:function(e,t,n,i){return vi.getBarycoord(e,t,n,i,hi),hi.x>=0&&hi.y>=0&&hi.x+hi.y<=1},getUV:function(e,t,n,i,r,a,o,s){return this.getBarycoord(e,t,n,i,hi),s.set(0,0),s.addScaledVector(r,hi.x),s.addScaledVector(a,hi.y),s.addScaledVector(o,hi.z),s},isFrontFacing:function(e,t,n,i){return si.subVectors(n,t),ci.subVectors(e,t),si.cross(ci).dot(i)<0}}),Object.assign(vi.prototype,{set:function(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this},setFromPointsAndIndices:function(e,t,n,i){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[i]),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this},getArea:function(){return si.subVectors(this.c,this.b),ci.subVectors(this.a,this.b),.5*si.cross(ci).length()},getMidpoint:function(e){return void 0===e&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),e=new rn),e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},getNormal:function(e){return vi.getNormal(this.a,this.b,this.c,e)},getPlane:function(e){return void 0===e&&(console.warn("THREE.Triangle: .getPlane() target is now required"),e=new oi),e.setFromCoplanarPoints(this.a,this.b,this.c)},getBarycoord:function(e,t){return vi.getBarycoord(e,this.a,this.b,this.c,t)},getUV:function(e,t,n,i,r){return vi.getUV(e,this.a,this.b,this.c,t,n,i,r)},containsPoint:function(e){return vi.containsPoint(e,this.a,this.b,this.c)},isFrontFacing:function(e){return vi.isFrontFacing(this.a,this.b,this.c,e)},intersectsBox:function(e){return e.intersectsTriangle(this)},closestPointToPoint:function(e,t){void 0===t&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),t=new rn);var n,i,r=this.a,a=this.b,o=this.c;ui.subVectors(a,r),pi.subVectors(o,r),fi.subVectors(e,r);var s=ui.dot(fi),c=pi.dot(fi);if(s<=0&&c<=0)return t.copy(r);mi.subVectors(e,a);var l=ui.dot(mi),h=pi.dot(mi);if(l>=0&&h<=l)return t.copy(a);var u=s*h-l*c;if(u<=0&&s>=0&&l<=0)return n=s/(s-l),t.copy(r).addScaledVector(ui,n);gi.subVectors(e,o);var p=ui.dot(gi),d=pi.dot(gi);if(d>=0&&p<=d)return t.copy(o);var f=p*c-s*d;if(f<=0&&c>=0&&d<=0)return i=c/(c-d),t.copy(r).addScaledVector(pi,i);var m=l*d-p*h;if(m<=0&&h-l>=0&&p-d>=0)return di.subVectors(o,a),i=(h-l)/(h-l+(p-d)),t.copy(a).addScaledVector(di,i);var g=1/(m+f+u);return n=f*g,i=u*g,t.copy(r).addScaledVector(ui,n).addScaledVector(pi,i)},equals:function(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}});var yi={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},xi={h:0,s:0,l:0},bi={h:0,s:0,l:0};function _i(e,t,n){return void 0===t&&void 0===n?this.set(e):this.setRGB(e,t,n)}function wi(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+6*(t-e)*(2/3-n):e}function Mi(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function Si(e){return e<.0031308?12.92*e:1.055*Math.pow(e,.41666)-.055}function Ti(e,t,n,i,r,a){this.a=e,this.b=t,this.c=n,this.normal=i&&i.isVector3?i:new rn,this.vertexNormals=Array.isArray(i)?i:[],this.color=r&&r.isColor?r:new _i,this.vertexColors=Array.isArray(r)?r:[],this.materialIndex=void 0!==a?a:0}Object.assign(_i.prototype,{isColor:!0,r:1,g:1,b:1,set:function(e){return e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e),this},setScalar:function(e){return this.r=e,this.g=e,this.b=e,this},setHex:function(e){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(255&e)/255,this},setRGB:function(e,t,n){return this.r=e,this.g=t,this.b=n,this},setHSL:function(e,t,n){if(e=Wt.euclideanModulo(e,1),t=Wt.clamp(t,0,1),n=Wt.clamp(n,0,1),0===t)this.r=this.g=this.b=n;else{var i=n<=.5?n*(1+t):n+t-n*t,r=2*n-i;this.r=wi(r,i,e+1/3),this.g=wi(r,i,e),this.b=wi(r,i,e-1/3)}return this},setStyle:function(e){function t(t){void 0!==t&&parseFloat(t)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}var n;if(n=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(e)){var i,r=n[1],a=n[2];switch(r){case"rgb":case"rgba":if(i=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(255,parseInt(i[1],10))/255,this.g=Math.min(255,parseInt(i[2],10))/255,this.b=Math.min(255,parseInt(i[3],10))/255,t(i[5]),this;if(i=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(100,parseInt(i[1],10))/100,this.g=Math.min(100,parseInt(i[2],10))/100,this.b=Math.min(100,parseInt(i[3],10))/100,t(i[5]),this;break;case"hsl":case"hsla":if(i=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a)){var o=parseFloat(i[1])/360,s=parseInt(i[2],10)/100,c=parseInt(i[3],10)/100;return t(i[5]),this.setHSL(o,s,c)}}}else if(n=/^\#([A-Fa-f0-9]+)$/.exec(e)){var l=n[1],h=l.length;if(3===h)return this.r=parseInt(l.charAt(0)+l.charAt(0),16)/255,this.g=parseInt(l.charAt(1)+l.charAt(1),16)/255,this.b=parseInt(l.charAt(2)+l.charAt(2),16)/255,this;if(6===h)return this.r=parseInt(l.charAt(0)+l.charAt(1),16)/255,this.g=parseInt(l.charAt(2)+l.charAt(3),16)/255,this.b=parseInt(l.charAt(4)+l.charAt(5),16)/255,this}return e&&e.length>0?this.setColorName(e):this},setColorName:function(e){var t=yi[e];return void 0!==t?this.setHex(t):console.warn("THREE.Color: Unknown color "+e),this},clone:function(){return new this.constructor(this.r,this.g,this.b)},copy:function(e){return this.r=e.r,this.g=e.g,this.b=e.b,this},copyGammaToLinear:function(e,t){return void 0===t&&(t=2),this.r=Math.pow(e.r,t),this.g=Math.pow(e.g,t),this.b=Math.pow(e.b,t),this},copyLinearToGamma:function(e,t){void 0===t&&(t=2);var n=t>0?1/t:1;return this.r=Math.pow(e.r,n),this.g=Math.pow(e.g,n),this.b=Math.pow(e.b,n),this},convertGammaToLinear:function(e){return this.copyGammaToLinear(this,e),this},convertLinearToGamma:function(e){return this.copyLinearToGamma(this,e),this},copySRGBToLinear:function(e){return this.r=Mi(e.r),this.g=Mi(e.g),this.b=Mi(e.b),this},copyLinearToSRGB:function(e){return this.r=Si(e.r),this.g=Si(e.g),this.b=Si(e.b),this},convertSRGBToLinear:function(){return this.copySRGBToLinear(this),this},convertLinearToSRGB:function(){return this.copyLinearToSRGB(this),this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(e){void 0===e&&(console.warn("THREE.Color: .getHSL() target is now required"),e={h:0,s:0,l:0});var t,n,i=this.r,r=this.g,a=this.b,o=Math.max(i,r,a),s=Math.min(i,r,a),c=(s+o)/2;if(s===o)t=0,n=0;else{var l=o-s;switch(n=c<=.5?l/(o+s):l/(2-o-s),o){case i:t=(r-a)/l+(r0&&(n.alphaTest=this.alphaTest),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=this.premultipliedAlpha),!0===this.wireframe&&(n.wireframe=this.wireframe),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.morphTargets&&(n.morphTargets=!0),!0===this.morphNormals&&(n.morphNormals=!0),!0===this.skinning&&(n.skinning=!0),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),"{}"!==JSON.stringify(this.userData)&&(n.userData=this.userData),t){var r=i(e.textures),a=i(e.images);r.length>0&&(n.textures=r),a.length>0&&(n.images=a)}return n},clone:function(){return(new this.constructor).copy(this)},copy:function(e){this.name=e.name,this.fog=e.fog,this.blending=e.blending,this.side=e.side,this.flatShading=e.flatShading,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;var t=e.clippingPlanes,n=null;if(null!==t){var i=t.length;n=new Array(i);for(var r=0;r!==i;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.premultipliedAlpha=e.premultipliedAlpha,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),Object.defineProperty(Ai.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Li.prototype=Object.create(Ai.prototype),Li.prototype.constructor=Li,Li.prototype.isMeshBasicMaterial=!0,Li.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this};var Ri=new rn;function Pi(e,t,n){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.name="",this.array=e,this.itemSize=t,this.count=void 0!==e?e.length/t:0,this.normalized=!0===n,this.usage=Ut,this.updateRange={offset:0,count:-1},this.version=0}function Ci(e,t,n){Pi.call(this,new Int8Array(e),t,n)}function Oi(e,t,n){Pi.call(this,new Uint8Array(e),t,n)}function Di(e,t,n){Pi.call(this,new Uint8ClampedArray(e),t,n)}function Ii(e,t,n){Pi.call(this,new Int16Array(e),t,n)}function Ni(e,t,n){Pi.call(this,new Uint16Array(e),t,n)}function Bi(e,t,n){Pi.call(this,new Int32Array(e),t,n)}function zi(e,t,n){Pi.call(this,new Uint32Array(e),t,n)}function Fi(e,t,n){Pi.call(this,new Float32Array(e),t,n)}function Ui(e,t,n){Pi.call(this,new Float64Array(e),t,n)}function Gi(){this.vertices=[],this.normals=[],this.colors=[],this.uvs=[],this.uvs2=[],this.groups=[],this.morphTargets={},this.skinWeights=[],this.skinIndices=[],this.boundingBox=null,this.boundingSphere=null,this.verticesNeedUpdate=!1,this.normalsNeedUpdate=!1,this.colorsNeedUpdate=!1,this.uvsNeedUpdate=!1,this.groupsNeedUpdate=!1}function Hi(e){if(0===e.length)return-1/0;for(var t=e[0],n=1,i=e.length;nt&&(t=e[n]);return t}Object.defineProperty(Pi.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.assign(Pi.prototype,{isBufferAttribute:!0,onUploadCallback:function(){},setUsage:function(e){return this.usage=e,this},copy:function(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this},copyAt:function(e,t,n){e*=this.itemSize,n*=t.itemSize;for(var i=0,r=this.itemSize;i0,o=r[1]&&r[1].length>0,s=e.morphTargets,c=s.length;if(c>0){t=[];for(var l=0;l0){h=[];for(l=0;l0&&0===n.length&&console.error("THREE.DirectGeometry: Faceless geometries are not supported.");for(l=0;l65535?zi:Ni)(e,1):this.index=e},getAttribute:function(e){return this.attributes[e]},setAttribute:function(e,t){return this.attributes[e]=t,this},deleteAttribute:function(e){return delete this.attributes[e],this},addGroup:function(e,t,n){this.groups.push({start:e,count:t,materialIndex:void 0!==n?n:0})},clearGroups:function(){this.groups=[]},setDrawRange:function(e,t){this.drawRange.start=e,this.drawRange.count=t},applyMatrix4:function(e){var t=this.attributes.position;void 0!==t&&(t.applyMatrix4(e),t.needsUpdate=!0);var n=this.attributes.normal;if(void 0!==n){var i=(new Xt).getNormalMatrix(e);n.applyNormalMatrix(i),n.needsUpdate=!0}var r=this.attributes.tangent;return void 0!==r&&(r.transformDirection(e),r.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},rotateX:function(e){return ki.makeRotationX(e),this.applyMatrix4(ki),this},rotateY:function(e){return ki.makeRotationY(e),this.applyMatrix4(ki),this},rotateZ:function(e){return ki.makeRotationZ(e),this.applyMatrix4(ki),this},translate:function(e,t,n){return ki.makeTranslation(e,t,n),this.applyMatrix4(ki),this},scale:function(e,t,n){return ki.makeScale(e,t,n),this.applyMatrix4(ki),this},lookAt:function(e){return ji.lookAt(e),ji.updateMatrix(),this.applyMatrix4(ji.matrix),this},center:function(){return this.computeBoundingBox(),this.boundingBox.getCenter(Wi).negate(),this.translate(Wi.x,Wi.y,Wi.z),this},setFromObject:function(e){var t=e.geometry;if(e.isPoints||e.isLine){var n=new Fi(3*t.vertices.length,3),i=new Fi(3*t.colors.length,3);if(this.setAttribute("position",n.copyVector3sArray(t.vertices)),this.setAttribute("color",i.copyColorsArray(t.colors)),t.lineDistances&&t.lineDistances.length===t.vertices.length){var r=new Fi(t.lineDistances.length,1);this.setAttribute("lineDistance",r.copyArray(t.lineDistances))}null!==t.boundingSphere&&(this.boundingSphere=t.boundingSphere.clone()),null!==t.boundingBox&&(this.boundingBox=t.boundingBox.clone())}else e.isMesh&&t&&t.isGeometry&&this.fromGeometry(t);return this},setFromPoints:function(e){for(var t=[],n=0,i=e.length;n0){var n=new Float32Array(3*e.normals.length);this.setAttribute("normal",new Pi(n,3).copyVector3sArray(e.normals))}if(e.colors.length>0){var i=new Float32Array(3*e.colors.length);this.setAttribute("color",new Pi(i,3).copyColorsArray(e.colors))}if(e.uvs.length>0){var r=new Float32Array(2*e.uvs.length);this.setAttribute("uv",new Pi(r,2).copyVector2sArray(e.uvs))}if(e.uvs2.length>0){var a=new Float32Array(2*e.uvs2.length);this.setAttribute("uv2",new Pi(a,2).copyVector2sArray(e.uvs2))}for(var o in this.groups=e.groups,e.morphTargets){for(var s=[],c=e.morphTargets[o],l=0,h=c.length;l0){var d=new Fi(4*e.skinIndices.length,4);this.setAttribute("skinIndex",d.copyVector4sArray(e.skinIndices))}if(e.skinWeights.length>0){var f=new Fi(4*e.skinWeights.length,4);this.setAttribute("skinWeight",f.copyVector4sArray(e.skinWeights))}return null!==e.boundingSphere&&(this.boundingSphere=e.boundingSphere.clone()),null!==e.boundingBox&&(this.boundingBox=e.boundingBox.clone()),this},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new Wn);var e=this.attributes.position,t=this.morphAttributes.position;if(void 0!==e){if(this.boundingBox.setFromBufferAttribute(e),t)for(var n=0,i=t.length;n0&&(e.userData=this.userData),void 0!==this.parameters){var t=this.parameters;for(var n in t)void 0!==t[n]&&(e[n]=t[n]);return e}e.data={attributes:{}};var i=this.index;null!==i&&(e.data.index={type:i.array.constructor.name,array:Array.prototype.slice.call(i.array)});var r=this.attributes;for(var n in r){var a=(p=r[n]).toJSON();""!==p.name&&(a.name=p.name),e.data.attributes[n]=a}var o={},s=!1;for(var n in this.morphAttributes){for(var c=this.morphAttributes[n],l=[],h=0,u=c.length;h0&&(o[n]=l,s=!0)}s&&(e.data.morphAttributes=o,e.data.morphTargetsRelative=this.morphTargetsRelative);var d=this.groups;d.length>0&&(e.data.groups=JSON.parse(JSON.stringify(d)));var f=this.boundingSphere;return null!==f&&(e.data.boundingSphere={center:f.center.toArray(),radius:f.radius}),e},clone:function(){return(new Zi).copy(this)},copy:function(e){var t,n,i;this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.name=e.name;var r=e.index;null!==r&&this.setIndex(r.clone());var a=e.attributes;for(t in a){var o=a[t];this.setAttribute(t,o.clone())}var s=e.morphAttributes;for(t in s){var c=[],l=s[t];for(n=0,i=l.length;nn.far?null:{distance:h,point:pr.clone(),object:e}}function mr(e,t,n,i,r,a,o,s,c,l,h,u){$i.fromBufferAttribute(r,l),er.fromBufferAttribute(r,h),tr.fromBufferAttribute(r,u);var p=e.morphTargetInfluences;if(t.morphTargets&&a&&p){ar.set(0,0,0),or.set(0,0,0),sr.set(0,0,0);for(var d=0,f=a.length;d0){var o=r[a[0]];if(void 0!==o)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},e=0,t=o.length;e0&&console.error("THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}},raycast:function(e,t){var n,i=this.geometry,r=this.material,a=this.matrixWorld;if(void 0!==r&&(null===i.boundingSphere&&i.computeBoundingSphere(),Ki.copy(i.boundingSphere),Ki.applyMatrix4(a),!1!==e.ray.intersectsSphere(Ki)&&(Ji.getInverse(a),Qi.copy(e.ray).applyMatrix4(Ji),null===i.boundingBox||!1!==Qi.intersectsBox(i.boundingBox))))if(i.isBufferGeometry){var o,s,c,l,h,u,p,d,f,m=i.index,g=i.attributes.position,v=i.morphAttributes.position,y=i.morphTargetsRelative,x=i.attributes.uv,b=i.attributes.uv2,_=i.groups,w=i.drawRange;if(null!==m)if(Array.isArray(r))for(l=0,u=_.length;l0&&(E=P);for(var C=0,O=R.length;C0)for(l=0;l0&&(this.normalsNeedUpdate=!0)},computeFlatVertexNormals:function(){var e,t,n;for(this.computeFaceNormals(),e=0,t=this.faces.length;e0&&(this.normalsNeedUpdate=!0)},computeMorphNormals:function(){var e,t,n,i,r;for(n=0,i=this.faces.length;n=0;n--){var f=p[n];for(this.faces.splice(f,1),o=0,s=this.faceVertexUvs.length;o0,g=d.vertexNormals.length>0,v=1!==d.color.r||1!==d.color.g||1!==d.color.b,y=d.vertexColors.length>0,x=0;if(x=M(x,0,0),x=M(x,1,!0),x=M(x,2,!1),x=M(x,3,f),x=M(x,4,m),x=M(x,5,g),x=M(x,6,v),x=M(x,7,y),o.push(x),o.push(d.a,d.b,d.c),o.push(d.materialIndex),f){var b=this.faceVertexUvs[0][r];o.push(E(b[0]),E(b[1]),E(b[2]))}if(m&&o.push(S(d.normal)),g){var _=d.vertexNormals;o.push(S(_[0]),S(_[1]),S(_[2]))}if(v&&o.push(T(d.color)),y){var w=d.vertexColors;o.push(T(w[0]),T(w[1]),T(w[2]))}}function M(e,t,n){return n?e|1<0&&(e.data.colors=l),u.length>0&&(e.data.uvs=[u]),e.data.faces=o,e},clone:function(){return(new br).copy(this)},copy:function(e){var t,n,i,r,a,o;this.vertices=[],this.colors=[],this.faces=[],this.faceVertexUvs=[[]],this.morphTargets=[],this.morphNormals=[],this.skinWeights=[],this.skinIndices=[],this.lineDistances=[],this.boundingBox=null,this.boundingSphere=null,this.name=e.name;var s=e.vertices;for(t=0,n=s.length;t0?1:-1,h.push(R.x,R.y,R.z),u.push(y/m),u.push(1-x/g),A+=1}}for(x=0;x0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader;var r={};for(var a in this.extensions)!0===this.extensions[a]&&(r[a]=!0);return Object.keys(r).length>0&&(t.extensions=r),t},Rr.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Rr,isCamera:!0,copy:function(e,t){return Pn.prototype.copy.call(this,e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this},getWorldDirection:function(e){void 0===e&&(console.warn("THREE.Camera: .getWorldDirection() target is now required"),e=new rn),this.updateMatrixWorld(!0);var t=this.matrixWorld.elements;return e.set(-t[8],-t[9],-t[10]).normalize()},updateMatrixWorld:function(e){Pn.prototype.updateMatrixWorld.call(this,e),this.matrixWorldInverse.getInverse(this.matrixWorld)},updateWorldMatrix:function(e,t){Pn.prototype.updateWorldMatrix.call(this,e,t),this.matrixWorldInverse.getInverse(this.matrixWorld)},clone:function(){return(new this.constructor).copy(this)}}),Pr.prototype=Object.assign(Object.create(Rr.prototype),{constructor:Pr,isPerspectiveCamera:!0,copy:function(e,t){return Rr.prototype.copy.call(this,e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=null===e.view?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this},setFocalLength:function(e){var t=.5*this.getFilmHeight()/e;this.fov=2*Wt.RAD2DEG*Math.atan(t),this.updateProjectionMatrix()},getFocalLength:function(){var e=Math.tan(.5*Wt.DEG2RAD*this.fov);return.5*this.getFilmHeight()/e},getEffectiveFOV:function(){return 2*Wt.RAD2DEG*Math.atan(Math.tan(.5*Wt.DEG2RAD*this.fov)/this.zoom)},getFilmWidth:function(){return this.filmGauge*Math.min(this.aspect,1)},getFilmHeight:function(){return this.filmGauge/Math.max(this.aspect,1)},setViewOffset:function(e,t,n,i,r,a){this.aspect=e/t,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()},clearViewOffset:function(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()},updateProjectionMatrix:function(){var e=this.near,t=e*Math.tan(.5*Wt.DEG2RAD*this.fov)/this.zoom,n=2*t,i=this.aspect*n,r=-.5*i,a=this.view;if(null!==this.view&&this.view.enabled){var o=a.fullWidth,s=a.fullHeight;r+=a.offsetX*i/o,t-=a.offsetY*n/s,i*=a.width/o,n*=a.height/s}var c=this.filmOffset;0!==c&&(r+=e*c/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-n,e,this.far),this.projectionMatrixInverse.getInverse(this.projectionMatrix)},toJSON:function(e){var t=Pn.prototype.toJSON.call(this,e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,null!==this.view&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}});var Cr=90,Or=1;function Dr(e,t,n,i){Pn.call(this),this.type="CubeCamera";var r=new Pr(Cr,Or,e,t);r.up.set(0,-1,0),r.lookAt(new rn(1,0,0)),this.add(r);var a=new Pr(Cr,Or,e,t);a.up.set(0,-1,0),a.lookAt(new rn(-1,0,0)),this.add(a);var o=new Pr(Cr,Or,e,t);o.up.set(0,0,1),o.lookAt(new rn(0,1,0)),this.add(o);var s=new Pr(Cr,Or,e,t);s.up.set(0,0,-1),s.lookAt(new rn(0,-1,0)),this.add(s);var c=new Pr(Cr,Or,e,t);c.up.set(0,-1,0),c.lookAt(new rn(0,0,1)),this.add(c);var l=new Pr(Cr,Or,e,t);l.up.set(0,-1,0),l.lookAt(new rn(0,0,-1)),this.add(l),i=i||{format:Se,magFilter:ce,minFilter:ce},this.renderTarget=new Ir(n,i),this.renderTarget.texture.name="CubeCamera",this.update=function(e,t){null===this.parent&&this.updateMatrixWorld();var n=e.getRenderTarget(),i=this.renderTarget,h=i.texture.generateMipmaps;i.texture.generateMipmaps=!1,e.setRenderTarget(i,0),e.render(t,r),e.setRenderTarget(i,1),e.render(t,a),e.setRenderTarget(i,2),e.render(t,o),e.setRenderTarget(i,3),e.render(t,s),e.setRenderTarget(i,4),e.render(t,c),i.texture.generateMipmaps=h,e.setRenderTarget(i,5),e.render(t,l),e.setRenderTarget(n)},this.clear=function(e,t,n,i){for(var r=e.getRenderTarget(),a=this.renderTarget,o=0;o<6;o++)e.setRenderTarget(a,o),e.clear(t,n,i);e.setRenderTarget(r)}}function Ir(e,t,n){Number.isInteger(t)&&(console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"),t=n),Kt.call(this,e,e,t)}function Nr(e,t,n,i,r,a,o,s,c,l,h,u){Jt.call(this,null,a,o,s,c,l,i,r,h,u),this.image={data:e||null,width:t||1,height:n||1},this.magFilter=void 0!==c?c:ae,this.minFilter=void 0!==l?l:ae,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1,this.needsUpdate=!0}Dr.prototype=Object.create(Pn.prototype),Dr.prototype.constructor=Dr,Ir.prototype=Object.create(Kt.prototype),Ir.prototype.constructor=Ir,Ir.prototype.isWebGLCubeRenderTarget=!0,Ir.prototype.fromEquirectangularTexture=function(e,t){this.texture.type=t.type,this.texture.format=t.format,this.texture.encoding=t.encoding;var n=new Cn,i={uniforms:{tEquirect:{value:null}},vertexShader:["varying vec3 vWorldDirection;","vec3 transformDirection( in vec3 dir, in mat4 matrix ) {","\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );","}","void main() {","\tvWorldDirection = transformDirection( position, modelMatrix );","\t#include ","\t#include ","}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;","varying vec3 vWorldDirection;","#define RECIPROCAL_PI 0.31830988618","#define RECIPROCAL_PI2 0.15915494","void main() {","\tvec3 direction = normalize( vWorldDirection );","\tvec2 sampleUV;","\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;","\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;","\tgl_FragColor = texture2D( tEquirect, sampleUV );","}"].join("\n")},r=new Lr({type:"CubemapFromEquirect",uniforms:Mr(i.uniforms),vertexShader:i.vertexShader,fragmentShader:i.fragmentShader,side:c,blending:h});r.uniforms.tEquirect.value=t;var a=new dr(new wr(5,5,5),r);n.add(a);var o=new Dr(1,10,1);return o.renderTarget=this,o.renderTarget.texture.name="CubeCameraTexture",o.update(e,n),a.geometry.dispose(),a.material.dispose(),this},Nr.prototype=Object.create(Jt.prototype),Nr.prototype.constructor=Nr,Nr.prototype.isDataTexture=!0;var Br=new Yn,zr=new rn;function Fr(e,t,n,i,r,a){this.planes=[void 0!==e?e:new oi,void 0!==t?t:new oi,void 0!==n?n:new oi,void 0!==i?i:new oi,void 0!==r?r:new oi,void 0!==a?a:new oi]}Object.assign(Fr.prototype,{set:function(e,t,n,i,r,a){var o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(i),o[4].copy(r),o[5].copy(a),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){for(var t=this.planes,n=0;n<6;n++)t[n].copy(e.planes[n]);return this},setFromProjectionMatrix:function(e){var t=this.planes,n=e.elements,i=n[0],r=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],h=n[7],u=n[8],p=n[9],d=n[10],f=n[11],m=n[12],g=n[13],v=n[14],y=n[15];return t[0].setComponents(o-i,h-s,f-u,y-m).normalize(),t[1].setComponents(o+i,h+s,f+u,y+m).normalize(),t[2].setComponents(o+r,h+c,f+p,y+g).normalize(),t[3].setComponents(o-r,h-c,f-p,y-g).normalize(),t[4].setComponents(o-a,h-l,f-d,y-v).normalize(),t[5].setComponents(o+a,h+l,f+d,y+v).normalize(),this},intersectsObject:function(e){var t=e.geometry;return null===t.boundingSphere&&t.computeBoundingSphere(),Br.copy(t.boundingSphere).applyMatrix4(e.matrixWorld),this.intersectsSphere(Br)},intersectsSprite:function(e){return Br.center.set(0,0,0),Br.radius=.7071067811865476,Br.applyMatrix4(e.matrixWorld),this.intersectsSphere(Br)},intersectsSphere:function(e){for(var t=this.planes,n=e.center,i=-e.radius,r=0;r<6;r++){if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,zr.y=i.normal.y>0?e.max.y:e.min.y,zr.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(zr)<0)return!1}return!0},containsPoint:function(e){for(var t=this.planes,n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}});var Ur={common:{diffuse:{value:new _i(15658734)},opacity:{value:1},map:{value:null},uvTransform:{value:new Xt},uv2Transform:{value:new Xt},alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new qt(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new _i(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new _i(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},uvTransform:{value:new Xt}},sprite:{diffuse:{value:new _i(15658734)},opacity:{value:1},center:{value:new qt(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null},uvTransform:{value:new Xt}}};function Gr(){var e=null,t=!1,n=null;function i(r,a){!1!==t&&(n(r,a),e.requestAnimationFrame(i))}return{start:function(){!0!==t&&null!==n&&(e.requestAnimationFrame(i),t=!0)},stop:function(){t=!1},setAnimationLoop:function(e){n=e},setContext:function(t){e=t}}}function Hr(e,t){var n=t.isWebGL2,i=new WeakMap;return{get:function(e){return e.isInterleavedBufferAttribute&&(e=e.data),i.get(e)},remove:function(t){t.isInterleavedBufferAttribute&&(t=t.data);var n=i.get(t);n&&(e.deleteBuffer(n.buffer),i.delete(t))},update:function(t,r){t.isInterleavedBufferAttribute&&(t=t.data);var a=i.get(t);void 0===a?i.set(t,function(t,n){var i=t.array,r=t.usage,a=e.createBuffer();e.bindBuffer(n,a),e.bufferData(n,i,r),t.onUploadCallback();var o=5126;return i instanceof Float32Array?o=5126:i instanceof Float64Array?console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array."):i instanceof Uint16Array?o=5123:i instanceof Int16Array?o=5122:i instanceof Uint32Array?o=5125:i instanceof Int32Array?o=5124:i instanceof Int8Array?o=5120:i instanceof Uint8Array&&(o=5121),{buffer:a,type:o,bytesPerElement:i.BYTES_PER_ELEMENT,version:t.version}}(t,r)):a.version 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\tvarying vec3 vViewPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\tvViewPosition = - mvPosition.xyz;\n#endif",color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == - 1.0;\n}",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_maxMipLevel 8.0\n#define cubeUV_minMipLevel 4.0\n#define cubeUV_maxTileSize 256.0\n#define cubeUV_minTileSize 16.0\nfloat getFace(vec3 direction) {\n vec3 absDirection = abs(direction);\n float face = -1.0;\n if (absDirection.x > absDirection.z) {\n if (absDirection.x > absDirection.y)\n face = direction.x > 0.0 ? 0.0 : 3.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n } else {\n if (absDirection.z > absDirection.y)\n face = direction.z > 0.0 ? 2.0 : 5.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n }\n return face;\n}\nvec2 getUV(vec3 direction, float face) {\n vec2 uv;\n if (face == 0.0) {\n uv = vec2(-direction.z, direction.y) / abs(direction.x);\n } else if (face == 1.0) {\n uv = vec2(direction.x, -direction.z) / abs(direction.y);\n } else if (face == 2.0) {\n uv = direction.xy / abs(direction.z);\n } else if (face == 3.0) {\n uv = vec2(direction.z, direction.y) / abs(direction.x);\n } else if (face == 4.0) {\n uv = direction.xz / abs(direction.y);\n } else {\n uv = vec2(-direction.x, direction.y) / abs(direction.z);\n }\n return 0.5 * (uv + 1.0);\n}\nvec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {\n float face = getFace(direction);\n float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);\n mipInt = max(mipInt, cubeUV_minMipLevel);\n float faceSize = exp2(mipInt);\n float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);\n vec2 uv = getUV(direction, face) * (faceSize - 1.0);\n vec2 f = fract(uv);\n uv += 0.5 - f;\n if (face > 2.0) {\n uv.y += faceSize;\n face -= 3.0;\n }\n uv.x += face * faceSize;\n if(mipInt < cubeUV_maxMipLevel){\n uv.y += 2.0 * cubeUV_maxTileSize;\n }\n uv.y += filterInt * 2.0 * cubeUV_minTileSize;\n uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);\n uv *= texelSize;\n vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x += texelSize;\n vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.y += texelSize;\n vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x -= texelSize;\n vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n vec3 tm = mix(tl, tr, f.x);\n vec3 bm = mix(bl, br, f.x);\n return mix(tm, bm, f.y);\n}\n#define r0 1.0\n#define v0 0.339\n#define m0 -2.0\n#define r1 0.8\n#define v1 0.276\n#define m1 -1.0\n#define r4 0.4\n#define v4 0.046\n#define m4 2.0\n#define r5 0.305\n#define v5 0.016\n#define m5 3.0\n#define r6 0.21\n#define v6 0.0038\n#define m6 4.0\nfloat roughnessToMip(float roughness) {\n float mip = 0.0;\n if (roughness >= r1) {\n mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;\n } else if (roughness >= r4) {\n mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;\n } else if (roughness >= r5) {\n mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;\n } else if (roughness >= r6) {\n mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;\n } else {\n mip = -2.0 * log2(1.16 * roughness); }\n return mip;\n}\nvec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) {\n float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel);\n float mipF = fract(mip);\n float mipInt = floor(mip);\n vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt);\n if (mipF == 0.0) {\n return vec4(color0, 1.0);\n } else {\n vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0);\n return vec4(mix(color0, color1, mipF), 1.0);\n }\n}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\t\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t vec3 reflectVec = reflect( -viewDir, normal );\n\t\t reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t vec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) { \n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = saturate( clearcoat );\tmaterial.clearcoatRoughness = max( clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif",normal_fragment_begin:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;",normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif",clearcoat_normalmap_pars_fragment:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );\n}",uv_pars_fragment:"#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSPARENCY\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSPARENCY\n\tuniform float transparency;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSPARENCY\n\t\tdiffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}",normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"},Wr={basic:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.fog]),vertexShader:jr.meshbasic_vert,fragmentShader:jr.meshbasic_frag},lambert:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)}}]),vertexShader:jr.meshlambert_vert,fragmentShader:jr.meshlambert_frag},phong:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},specular:{value:new _i(1118481)},shininess:{value:30}}]),vertexShader:jr.meshphong_vert,fragmentShader:jr.meshphong_frag},standard:{uniforms:Sr([Ur.common,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.roughnessmap,Ur.metalnessmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:jr.meshphysical_vert,fragmentShader:jr.meshphysical_frag},toon:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.gradientmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},specular:{value:new _i(1118481)},shininess:{value:30}}]),vertexShader:jr.meshtoon_vert,fragmentShader:jr.meshtoon_frag},matcap:{uniforms:Sr([Ur.common,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.fog,{matcap:{value:null}}]),vertexShader:jr.meshmatcap_vert,fragmentShader:jr.meshmatcap_frag},points:{uniforms:Sr([Ur.points,Ur.fog]),vertexShader:jr.points_vert,fragmentShader:jr.points_frag},dashed:{uniforms:Sr([Ur.common,Ur.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:jr.linedashed_vert,fragmentShader:jr.linedashed_frag},depth:{uniforms:Sr([Ur.common,Ur.displacementmap]),vertexShader:jr.depth_vert,fragmentShader:jr.depth_frag},normal:{uniforms:Sr([Ur.common,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,{opacity:{value:1}}]),vertexShader:jr.normal_vert,fragmentShader:jr.normal_frag},sprite:{uniforms:Sr([Ur.sprite,Ur.fog]),vertexShader:jr.sprite_vert,fragmentShader:jr.sprite_frag},background:{uniforms:{uvTransform:{value:new Xt},t2D:{value:null}},vertexShader:jr.background_vert,fragmentShader:jr.background_frag},cube:{uniforms:Sr([Ur.envmap,{opacity:{value:1}}]),vertexShader:jr.cube_vert,fragmentShader:jr.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:jr.equirect_vert,fragmentShader:jr.equirect_frag},distanceRGBA:{uniforms:Sr([Ur.common,Ur.displacementmap,{referencePosition:{value:new rn},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:jr.distanceRGBA_vert,fragmentShader:jr.distanceRGBA_frag},shadow:{uniforms:Sr([Ur.lights,Ur.fog,{color:{value:new _i(0)},opacity:{value:1}}]),vertexShader:jr.shadow_vert,fragmentShader:jr.shadow_frag}};function qr(e,t,n,i){var r,a,o=new _i(0),l=0,h=null,u=0,p=null;function d(e,n){t.buffers.color.setClear(e.r,e.g,e.b,n,i)}return{getClearColor:function(){return o},setClearColor:function(e,t){o.set(e),d(o,l=void 0!==t?t:1)},getClearAlpha:function(){return l},setClearAlpha:function(e){d(o,l=e)},render:function(t,i,f,m){var g=i.background,v=e.xr,y=v.getSession&&v.getSession();if(y&&"additive"===y.environmentBlendMode&&(g=null),null===g?d(o,l):g&&g.isColor&&(d(g,1),m=!0),(e.autoClear||m)&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),g&&(g.isCubeTexture||g.isWebGLCubeRenderTarget||g.mapping===ee)){void 0===a&&((a=new dr(new wr(1,1,1),new Lr({type:"BackgroundCubeMaterial",uniforms:Mr(Wr.cube.uniforms),vertexShader:Wr.cube.vertexShader,fragmentShader:Wr.cube.fragmentShader,side:c,depthTest:!1,depthWrite:!1,fog:!1}))).geometry.deleteAttribute("normal"),a.geometry.deleteAttribute("uv"),a.onBeforeRender=function(e,t,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(a.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),n.update(a));var x=g.isWebGLCubeRenderTarget?g.texture:g;a.material.uniforms.envMap.value=x,a.material.uniforms.flipEnvMap.value=x.isCubeTexture?-1:1,h===g&&u===x.version&&p===e.toneMapping||(a.material.needsUpdate=!0,h=g,u=x.version,p=e.toneMapping),t.unshift(a,a.geometry,a.material,0,0,null)}else g&&g.isTexture&&(void 0===r&&((r=new dr(new kr(2,2),new Lr({type:"BackgroundMaterial",uniforms:Mr(Wr.background.uniforms),vertexShader:Wr.background.vertexShader,fragmentShader:Wr.background.fragmentShader,side:s,depthTest:!1,depthWrite:!1,fog:!1}))).geometry.deleteAttribute("normal"),Object.defineProperty(r.material,"map",{get:function(){return this.uniforms.t2D.value}}),n.update(r)),r.material.uniforms.t2D.value=g,!0===g.matrixAutoUpdate&&g.updateMatrix(),r.material.uniforms.uvTransform.value.copy(g.matrix),h===g&&u===g.version&&p===e.toneMapping||(r.material.needsUpdate=!0,h=g,u=g.version,p=e.toneMapping),t.unshift(r,r.geometry,r.material,0,0,null))}}}function Xr(e,t,n,i){var r,a=i.isWebGL2;this.setMode=function(e){r=e},this.render=function(t,i){e.drawArrays(r,t,i),n.update(i,r)},this.renderInstances=function(i,o,s,c){if(0!==c){var l,h;if(a)l=e,h="drawArraysInstanced";else if(h="drawArraysInstancedANGLE",null===(l=t.get("ANGLE_instanced_arrays")))return void console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");l[h](r,o,s,c),n.update(s,r,c)}}}function Yr(e,t,n){var i;function r(t){if("highp"===t){if(e.getShaderPrecisionFormat(35633,36338).precision>0&&e.getShaderPrecisionFormat(35632,36338).precision>0)return"highp";t="mediump"}return"mediump"===t&&e.getShaderPrecisionFormat(35633,36337).precision>0&&e.getShaderPrecisionFormat(35632,36337).precision>0?"mediump":"lowp"}var a="undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext||"undefined"!=typeof WebGL2ComputeRenderingContext&&e instanceof WebGL2ComputeRenderingContext,o=void 0!==n.precision?n.precision:"highp",s=r(o);s!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",s,"instead."),o=s);var c=!0===n.logarithmicDepthBuffer,l=e.getParameter(34930),h=e.getParameter(35660),u=e.getParameter(3379),p=e.getParameter(34076),d=e.getParameter(34921),f=e.getParameter(36347),m=e.getParameter(36348),g=e.getParameter(36349),v=h>0,y=a||!!t.get("OES_texture_float");return{isWebGL2:a,getMaxAnisotropy:function(){if(void 0!==i)return i;var n=t.get("EXT_texture_filter_anisotropic");return i=null!==n?e.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0},getMaxPrecision:r,precision:o,logarithmicDepthBuffer:c,maxTextures:l,maxVertexTextures:h,maxTextureSize:u,maxCubemapSize:p,maxAttributes:d,maxVertexUniforms:f,maxVaryings:m,maxFragmentUniforms:g,vertexTextures:v,floatFragmentTextures:y,floatVertexTextures:v&&y,maxSamples:a?e.getParameter(36183):0}}function Zr(){var e=this,t=null,n=0,i=!1,r=!1,a=new oi,o=new Xt,s={value:null,needsUpdate:!1};function c(){s.value!==t&&(s.value=t,s.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function l(t,n,i,r){var c=null!==t?t.length:0,l=null;if(0!==c){if(l=s.value,!0!==r||null===l){var h=i+4*c,u=n.matrixWorldInverse;o.getNormalMatrix(u),(null===l||l.length65535?zi:Ni)(n,1);d.version=o,t.update(d,34963);var f=r.get(e);f&&t.remove(f),r.set(e,d)}return{get:function(e,t){var r=i.get(t);return r||(t.addEventListener("dispose",a),t.isBufferGeometry?r=t:t.isGeometry&&(void 0===t._bufferGeometry&&(t._bufferGeometry=(new Zi).setFromObject(e)),r=t._bufferGeometry),i.set(t,r),n.memory.geometries++,r)},update:function(e){var n=e.index,i=e.attributes;for(var r in null!==n&&t.update(n,34963),i)t.update(i[r],34962);var a=e.morphAttributes;for(var r in a)for(var o=a[r],s=0,c=o.length;s0)return e;var r=t*n,a=ha[r];if(void 0===a&&(a=new Float32Array(r),ha[r]=a),0!==t){i.toArray(a,0);for(var o=1,s=0;o!==t;++o)s+=n,e[o].toArray(a,s)}return a}function ga(e,t){if(e.length!==t.length)return!1;for(var n=0,i=e.length;n/gm;function uo(e){return e.replace(ho,po)}function po(e,t){var n=jr[t];if(void 0===n)throw new Error("Can not resolve #include <"+t+">");return uo(n)}var fo=/#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;function mo(e){return e.replace(fo,go)}function go(e,t,n,i){for(var r="",a=parseInt(t);a0?e.gammaFactor:1,b=n.isWebGL2?"":function(e){return[e.extensionDerivatives||e.envMapCubeUV||e.bumpMap||e.tangentSpaceNormalMap||e.clearcoatNormalMap||e.flatShading||"physical"===e.shaderID?"#extension GL_OES_standard_derivatives : enable":"",(e.extensionFragDepth||e.logarithmicDepthBuffer)&&e.rendererExtensionFragDepth?"#extension GL_EXT_frag_depth : enable":"",e.extensionDrawBuffers&&e.rendererExtensionDrawBuffers?"#extension GL_EXT_draw_buffers : require":"",(e.extensionShaderTextureLOD||e.envMap)&&e.rendererExtensionShaderTextureLod?"#extension GL_EXT_shader_texture_lod : enable":""].filter(so).join("\n")}(n),_=function(e){var t=[];for(var n in e){var i=e[n];!1!==i&&t.push("#define "+n+" "+i)}return t.join("\n")}(p),w=u.createProgram();if(n.isRawShaderMaterial?((i=[_].filter(so).join("\n")).length>0&&(i+="\n"),(s=[b,_].filter(so).join("\n")).length>0&&(s+="\n")):(i=[vo(n),"#define SHADER_NAME "+n.shaderName,_,n.instancing?"#define USE_INSTANCING":"",n.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+x,"#define MAX_BONES "+n.maxBones,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+v:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.displacementMap&&n.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.useVertexTexture?"#define BONE_TEXTURE":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+m:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(so).join("\n"),s=[b,vo(n),"#define SHADER_NAME "+n.shaderName,_,n.alphaTest?"#define ALPHATEST "+n.alphaTest+(n.alphaTest%1?"":".0"):"","#define GAMMA_FACTOR "+x,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+g:"",n.envMap?"#define "+v:"",n.envMap?"#define "+y:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.sheen?"#define USE_SHEEN":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+m:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"",(n.extensionShaderTextureLOD||n.envMap)&&n.rendererExtensionShaderTextureLod?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==k?"#define TONE_MAPPING":"",n.toneMapping!==k?jr.tonemapping_pars_fragment:"",n.toneMapping!==k?oo("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.outputEncoding||n.mapEncoding||n.matcapEncoding||n.envMapEncoding||n.emissiveMapEncoding||n.lightMapEncoding?jr.encodings_pars_fragment:"",n.mapEncoding?ao("mapTexelToLinear",n.mapEncoding):"",n.matcapEncoding?ao("matcapTexelToLinear",n.matcapEncoding):"",n.envMapEncoding?ao("envMapTexelToLinear",n.envMapEncoding):"",n.emissiveMapEncoding?ao("emissiveMapTexelToLinear",n.emissiveMapEncoding):"",n.lightMapEncoding?ao("lightMapTexelToLinear",n.lightMapEncoding):"",n.outputEncoding?(c="linearToOutputTexel",l=n.outputEncoding,h=io(l),"vec4 "+c+"( vec4 value ) { return LinearTo"+h[0]+h[1]+"; }"):"",n.depthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(so).join("\n")),d=lo(d=co(d=uo(d),n),n),f=lo(f=co(f=uo(f),n),n),d=mo(d),f=mo(f),n.isWebGL2&&!n.isRawShaderMaterial){var M=!1,S=/^\s*#version\s+300\s+es\s*\n/;n.isShaderMaterial&&null!==d.match(S)&&null!==f.match(S)&&(M=!0,d=d.replace(S,""),f=f.replace(S,"")),i=["#version 300 es\n","#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+i,s=["#version 300 es\n","#define varying in",M?"":"out highp vec4 pc_fragColor;",M?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+s}var T,E,A=s+f,L=to(u,35633,i+d),R=to(u,35632,A);if(u.attachShader(w,L),u.attachShader(w,R),void 0!==n.index0AttributeName?u.bindAttribLocation(w,0,n.index0AttributeName):!0===n.morphTargets&&u.bindAttribLocation(w,0,"position"),u.linkProgram(w),e.debug.checkShaderErrors){var P=u.getProgramInfoLog(w).trim(),C=u.getShaderInfoLog(L).trim(),O=u.getShaderInfoLog(R).trim(),D=!0,I=!0;if(!1===u.getProgramParameter(w,35714)){D=!1;var N=ro(u,L,"vertex"),B=ro(u,R,"fragment");console.error("THREE.WebGLProgram: shader error: ",u.getError(),"35715",u.getProgramParameter(w,35715),"gl.getProgramInfoLog",P,N,B)}else""!==P?console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",P):""!==C&&""!==O||(I=!1);I&&(this.diagnostics={runnable:D,programLog:P,vertexShader:{log:C,prefix:i},fragmentShader:{log:O,prefix:s}})}return u.detachShader(w,L),u.detachShader(w,R),u.deleteShader(L),u.deleteShader(R),this.getUniforms=function(){return void 0===T&&(T=new eo(u,w)),T},this.getAttributes=function(){return void 0===E&&(E=function(e,t){for(var n={},i=e.getProgramParameter(t,35721),r=0;r0,maxBones:S,useVertexTexture:o,morphTargets:i.morphTargets,morphNormals:i.morphNormals,maxMorphTargets:e.maxMorphTargets,maxMorphNormals:e.maxMorphNormals,numDirLights:d.directional.length,numPointLights:d.point.length,numSpotLights:d.spot.length,numRectAreaLights:d.rectArea.length,numHemiLights:d.hemi.length,numDirLightShadows:d.directionalShadowMap.length,numPointLightShadows:d.pointShadowMap.length,numSpotLightShadows:d.spotShadowMap.length,numClippingPlanes:v,numClipIntersection:y,dithering:i.dithering,shadowMapEnabled:e.shadowMap.enabled&&m.length>0,shadowMapType:e.shadowMap.type,toneMapping:i.toneMapped?e.toneMapping:k,physicallyCorrectLights:e.physicallyCorrectLights,premultipliedAlpha:i.premultipliedAlpha,alphaTest:i.alphaTest,doubleSided:i.side===l,flipSided:i.side===c,depthPacking:void 0!==i.depthPacking&&i.depthPacking,index0AttributeName:i.index0AttributeName,extensionDerivatives:i.extensions&&i.extensions.derivatives,extensionFragDepth:i.extensions&&i.extensions.fragDepth,extensionDrawbuffers:i.extensions&&i.extensions.drawBuffers,extensionShaderTextureLOD:i.extensions&&i.extensions.shaderTextureLOD,rendererExtensionFragDepth:r||null!==t.get("EXT_frag_depth"),rendererExtensionDrawBuffers:r||null!==t.get("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:r||null!==t.get("EXT_shader_texture_lod"),onBeforeCompile:i.onBeforeCompile}},this.getProgramCacheKey=function(t){var n=[];if(t.shaderID?n.push(t.shaderID):(n.push(t.fragmentShader),n.push(t.vertexShader)),void 0!==t.defines)for(var i in t.defines)n.push(i),n.push(t.defines[i]);if(void 0===t.isRawShaderMaterial){for(var r=0;r1&&n.sort(e||_o),i.length>1&&i.sort(t||wo)}}}function So(){var e=new WeakMap;function t(n){var i=n.target;i.removeEventListener("dispose",t),e.delete(i)}return{get:function(n,i){var r,a=e.get(n);return void 0===a?(r=new Mo,e.set(n,new WeakMap),e.get(n).set(i,r),n.addEventListener("dispose",t)):void 0===(r=a.get(i))&&(r=new Mo,a.set(i,r)),r},dispose:function(){e=new WeakMap}}}function To(){var e={};return{get:function(t){if(void 0!==e[t.id])return e[t.id];var n;switch(t.type){case"DirectionalLight":n={direction:new rn,color:new _i};break;case"SpotLight":n={position:new rn,direction:new rn,color:new _i,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new rn,color:new _i,distance:0,decay:0};break;case"HemisphereLight":n={direction:new rn,skyColor:new _i,groundColor:new _i};break;case"RectAreaLight":n={color:new _i,position:new rn,halfWidth:new rn,halfHeight:new rn}}return e[t.id]=n,n}}}var Eo=0;function Ao(e,t){return(t.castShadow?1:0)-(e.castShadow?1:0)}function Lo(){for(var e,t=new To,n=(e={},{get:function(t){if(void 0!==e[t.id])return e[t.id];var n;switch(t.type){case"DirectionalLight":case"SpotLight":n={shadowBias:0,shadowRadius:1,shadowMapSize:new qt};break;case"PointLight":n={shadowBias:0,shadowRadius:1,shadowMapSize:new qt,shadowCameraNear:1,shadowCameraFar:1e3}}return e[t.id]=n,n}}),i={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadow:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[],point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[]},r=0;r<9;r++)i.probe.push(new rn);var a=new rn,o=new pn,s=new pn;return{setup:function(e,r,c){for(var l=0,h=0,u=0,p=0;p<9;p++)i.probe[p].set(0,0,0);var d=0,f=0,m=0,g=0,v=0,y=0,x=0,b=0,_=c.matrixWorldInverse;e.sort(Ao),p=0;for(var w=e.length;p0:!0===c.isGeometry&&(p=c.morphTargets&&c.morphTargets.length>0));var d=!1;!0===t.isSkinnedMesh&&(!0===n.skinning?d=!0:console.warn("THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:",t)),l=h(p,d,!0===t.isInstancedMesh)}else l=u;if(e.localClippingEnabled&&!0===n.clipShadows&&0!==n.clippingPlanes.length){var f=l.uuid,v=n.uuid,y=m[f];void 0===y&&(y={},m[f]=y);var x=y[v];void 0===x&&(x=l.clone(),y[v]=x),l=x}return l.visible=n.visible,l.wireframe=n.wireframe,l.side=s===o?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:g[n.side],l.clipShadows=n.clipShadows,l.clippingPlanes=n.clippingPlanes,l.clipIntersection=n.clipIntersection,l.wireframeLinewidth=n.wireframeLinewidth,l.linewidth=n.linewidth,!0===i.isPointLight&&!0===l.isMeshDistanceMaterial&&(l.referencePosition.setFromMatrixPosition(i.matrixWorld),l.nearDistance=r,l.farDistance=a),l}function E(n,r,a,s,c){if(!1!==n.visible){if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&c===o)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(a.matrixWorldInverse,n.matrixWorld);var l=t.update(n),h=n.material;if(Array.isArray(h))for(var u=l.groups,p=0,d=u.length;pn||a.y>n)&&(console.warn("THREE.WebGLShadowMap:",v,"has shadow exceeding max texture size, reducing"),a.x>n&&(u.x=Math.floor(n/x.x),a.x=u.x*x.x,y.mapSize.x=u.x),a.y>n&&(u.y=Math.floor(n/x.y),a.y=u.y*x.y,y.mapSize.y=u.y)),null===y.map&&!y.isPointLightShadow&&this.type===o){var b={minFilter:ce,magFilter:ce,format:Te};y.map=new Kt(a.x,a.y,b),y.map.texture.name=v.name+".shadowMap",y.mapPass=new Kt(a.x,a.y,b),y.camera.updateProjectionMatrix()}if(null===y.map){b={minFilter:ae,magFilter:ae,format:Te};y.map=new Kt(a.x,a.y,b),y.map.texture.name=v.name+".shadowMap",y.camera.updateProjectionMatrix()}e.setRenderTarget(y.map),e.clear();for(var M=y.getViewportCount(),S=0;S=1):-1!==ue.indexOf("OpenGL ES")&&(he=parseFloat(/^OpenGL\ ES\ ([0-9])/.exec(ue)[1]),le=he>=2);var pe=null,de={},fe=new Qt,me=new Qt;function ge(t,n,i){var r=new Uint8Array(4),a=e.createTexture();e.bindTexture(t,a),e.texParameteri(t,10241,9728),e.texParameteri(t,10240,9728);for(var o=0;oi||e.height>i)&&(r=i/Math.max(e.width,e.height)),r<1||!0===t){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap){var a=t?Wt.floorPowerOfTwo:Math.floor,o=a(r*e.width),c=a(r*e.height);void 0===s&&(s=m(o,c));var l=n?m(o,c):s;return l.width=o,l.height=c,l.getContext("2d").drawImage(e,0,0,o,c),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+e.width+"x"+e.height+") to ("+o+"x"+c+")."),l}return"data"in e&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+e.width+"x"+e.height+")."),e}return e}function v(e){return Wt.isPowerOfTwo(e.width)&&Wt.isPowerOfTwo(e.height)}function y(e,t){return e.generateMipmaps&&t&&e.minFilter!==ae&&e.minFilter!==ce}function x(t,n,r,a){e.generateMipmap(t),i.get(n).__maxMipLevel=Math.log(Math.max(r,a))*Math.LOG2E}function b(n,i,r){if(!1===c)return i;if(null!==n){if(void 0!==e[n])return e[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}var a=i;return 6403===i&&(5126===r&&(a=33326),5131===r&&(a=33325),5121===r&&(a=33321)),6407===i&&(5126===r&&(a=34837),5131===r&&(a=34843),5121===r&&(a=32849)),6408===i&&(5126===r&&(a=34836),5131===r&&(a=34842),5121===r&&(a=32856)),33325===a||33326===a||34842===a||34836===a?t.get("EXT_color_buffer_float"):34843!==a&&34837!==a||console.warn("THREE.WebGLRenderer: Floating point textures with RGB format not supported. Please use RGBA instead."),a}function _(e){return e===ae||e===oe||e===se?9728:9729}function w(t){var n=t.target;n.removeEventListener("dispose",w),function(t){var n=i.get(t);if(void 0===n.__webglInit)return;e.deleteTexture(n.__webglTexture),i.remove(t)}(n),n.isVideoTexture&&d.delete(n),o.memory.textures--}function M(t){var n=t.target;n.removeEventListener("dispose",M),function(t){var n=i.get(t),r=i.get(t.texture);if(!t)return;void 0!==r.__webglTexture&&e.deleteTexture(r.__webglTexture);t.depthTexture&&t.depthTexture.dispose();if(t.isWebGLCubeRenderTarget)for(var a=0;a<6;a++)e.deleteFramebuffer(n.__webglFramebuffer[a]),n.__webglDepthbuffer&&e.deleteRenderbuffer(n.__webglDepthbuffer[a]);else e.deleteFramebuffer(n.__webglFramebuffer),n.__webglDepthbuffer&&e.deleteRenderbuffer(n.__webglDepthbuffer);i.remove(t.texture),i.remove(t)}(n),o.memory.textures--}var S=0;function T(e,t){var r=i.get(e);if(e.isVideoTexture&&function(e){var t=o.render.frame;d.get(e)!==t&&(d.set(e,t),e.update())}(e),e.version>0&&r.__version!==e.version){var a=e.image;if(void 0===a)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined");else{if(!1!==a.complete)return void O(r,e,t);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.activeTexture(33984+t),n.bindTexture(3553,r.__webglTexture)}function E(t,r){if(6===t.image.length){var o=i.get(t);if(t.version>0&&o.__version!==t.version){C(o,t),n.activeTexture(33984+r),n.bindTexture(34067,o.__webglTexture),e.pixelStorei(37440,t.flipY);for(var s=t&&(t.isCompressedTexture||t.image[0].isCompressedTexture),l=t.image[0]&&t.image[0].isDataTexture,u=[],p=0;p<6;p++)u[p]=s||l?l?t.image[p].image:t.image[p]:g(t.image[p],!1,!0,h);var d,f=u[0],m=v(f)||c,_=a.convert(t.format),w=a.convert(t.type),M=b(t.internalFormat,_,w);if(P(34067,t,m),s){for(p=0;p<6;p++){d=u[p].mipmaps;for(var S=0;S1||i.get(a).__currentAnisotropy)&&(e.texParameterf(n,s.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(a.anisotropy,r.getMaxAnisotropy())),i.get(a).__currentAnisotropy=a.anisotropy)}}function C(t,n){void 0===t.__webglInit&&(t.__webglInit=!0,n.addEventListener("dispose",w),t.__webglTexture=e.createTexture(),o.memory.textures++)}function O(t,i,r){var o=3553;i.isDataTexture2DArray&&(o=35866),i.isDataTexture3D&&(o=32879),C(t,i),n.activeTexture(33984+r),n.bindTexture(o,t.__webglTexture),e.pixelStorei(37440,i.flipY),e.pixelStorei(37441,i.premultiplyAlpha),e.pixelStorei(3317,i.unpackAlignment);var s=function(e){return!c&&(e.wrapS!==ie||e.wrapT!==ie||e.minFilter!==ae&&e.minFilter!==ce)}(i)&&!1===v(i.image),l=g(i.image,s,!1,u),h=v(l)||c,p=a.convert(i.format),d=a.convert(i.type),f=b(i.internalFormat,p,d);P(o,i,h);var m,_=i.mipmaps;if(i.isDepthTexture){if(f=6402,i.type===ve){if(!1===c)throw new Error("Float Depth Texture only supported in WebGL2.0");f=36012}else c&&(f=33189);i.format===Re&&6402===f&&i.type!==fe&&i.type!==ge&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),i.type=fe,d=a.convert(i.type)),i.format===Pe&&(f=34041,i.type!==we&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),i.type=we,d=a.convert(i.type))),n.texImage2D(3553,0,f,l.width,l.height,0,p,d,null)}else if(i.isDataTexture)if(_.length>0&&h){for(var w=0,M=_.length;w0&&h){for(w=0,M=_.length;w=l&&console.warn("THREE.WebGLTextures: Trying to use "+e+" texture units while this GPU supports only "+l),S+=1,e},this.resetTextureUnits=function(){S=0},this.setTexture2D=T,this.setTexture2DArray=function(e,t){var r=i.get(e);e.version>0&&r.__version!==e.version?O(r,e,t):(n.activeTexture(33984+t),n.bindTexture(35866,r.__webglTexture))},this.setTexture3D=function(e,t){var r=i.get(e);e.version>0&&r.__version!==e.version?O(r,e,t):(n.activeTexture(33984+t),n.bindTexture(32879,r.__webglTexture))},this.setTextureCube=E,this.setTextureCubeDynamic=A,this.setupRenderTarget=function(t){var r=i.get(t),s=i.get(t.texture);t.addEventListener("dispose",M),s.__webglTexture=e.createTexture(),o.memory.textures++;var l=!0===t.isWebGLCubeRenderTarget,h=!0===t.isWebGLMultisampleRenderTarget,u=v(t)||c;if(l){r.__webglFramebuffer=[];for(var p=0;p<6;p++)r.__webglFramebuffer[p]=e.createFramebuffer()}else if(r.__webglFramebuffer=e.createFramebuffer(),h)if(c){r.__webglMultisampledFramebuffer=e.createFramebuffer(),r.__webglColorRenderbuffer=e.createRenderbuffer(),e.bindRenderbuffer(36161,r.__webglColorRenderbuffer);var d=a.convert(t.texture.format),f=a.convert(t.texture.type),m=b(t.texture.internalFormat,d,f),g=B(t);e.renderbufferStorageMultisample(36161,g,m,t.width,t.height),e.bindFramebuffer(36160,r.__webglMultisampledFramebuffer),e.framebufferRenderbuffer(36160,36064,36161,r.__webglColorRenderbuffer),e.bindRenderbuffer(36161,null),t.depthBuffer&&(r.__webglDepthRenderbuffer=e.createRenderbuffer(),I(r.__webglDepthRenderbuffer,t,!0)),e.bindFramebuffer(36160,null)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.");if(l){for(n.bindTexture(34067,s.__webglTexture),P(34067,t.texture,u),p=0;p<6;p++)D(r.__webglFramebuffer[p],t,36064,34069+p);y(t.texture,u)&&x(34067,t.texture,t.width,t.height),n.bindTexture(34067,null)}else n.bindTexture(3553,s.__webglTexture),P(3553,t.texture,u),D(r.__webglFramebuffer,t,36064,3553),y(t.texture,u)&&x(3553,t.texture,t.width,t.height),n.bindTexture(3553,null);t.depthBuffer&&N(t)},this.updateRenderTargetMipmap=function(e){var t=e.texture;if(y(t,v(e)||c)){var r=e.isWebGLCubeRenderTarget?34067:3553,a=i.get(t).__webglTexture;n.bindTexture(r,a),x(r,t,e.width,e.height),n.bindTexture(r,null)}},this.updateMultisampleRenderTarget=function(t){if(t.isWebGLMultisampleRenderTarget)if(c){var n=i.get(t);e.bindFramebuffer(36008,n.__webglMultisampledFramebuffer),e.bindFramebuffer(36009,n.__webglFramebuffer);var r=t.width,a=t.height,o=16384;t.depthBuffer&&(o|=256),t.stencilBuffer&&(o|=1024),e.blitFramebuffer(0,0,r,a,0,0,r,a,o,9728)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.")},this.safeSetTexture2D=function(e,t){e&&e.isWebGLRenderTarget&&(!1===z&&(console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."),z=!0),e=e.texture),T(e,t)},this.safeSetTextureCube=function(e,t){e&&e.isWebGLCubeRenderTarget&&(!1===F&&(console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."),F=!0),e=e.texture),e&&e.isCubeTexture||Array.isArray(e.image)&&6===e.image.length?E(e,t):A(e,t)}}function Fo(e,t,n){var i=n.isWebGL2;return{convert:function(e){var n;if(e===ue)return 5121;if(e===xe)return 32819;if(e===be)return 32820;if(e===_e)return 33635;if(e===pe)return 5120;if(e===de)return 5122;if(e===fe)return 5123;if(e===me)return 5124;if(e===ge)return 5125;if(e===ve)return 5126;if(e===ye)return i?5131:null!==(n=t.get("OES_texture_half_float"))?n.HALF_FLOAT_OES:null;if(e===Me)return 6406;if(e===Se)return 6407;if(e===Te)return 6408;if(e===Ee)return 6409;if(e===Ae)return 6410;if(e===Re)return 6402;if(e===Pe)return 34041;if(e===Ce)return 6403;if(e===Oe)return 36244;if(e===De)return 33319;if(e===Ie)return 33320;if(e===Ne)return 36248;if(e===Be)return 36249;if(e===ze||e===Fe||e===Ue||e===Ge){if(null===(n=t.get("WEBGL_compressed_texture_s3tc")))return null;if(e===ze)return n.COMPRESSED_RGB_S3TC_DXT1_EXT;if(e===Fe)return n.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(e===Ue)return n.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(e===Ge)return n.COMPRESSED_RGBA_S3TC_DXT5_EXT}if(e===He)return null!==(n=t.get("EXT_texture_compression_bptc"))?n.COMPRESSED_RGBA_BPTC_UNORM_EXT:null;if(e===Ve||e===ke||e===je||e===We){if(null===(n=t.get("WEBGL_compressed_texture_pvrtc")))return null;if(e===Ve)return n.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(e===ke)return n.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(e===je)return n.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(e===We)return n.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}if(e===qe)return null!==(n=t.get("WEBGL_compressed_texture_etc1"))?n.COMPRESSED_RGB_ETC1_WEBGL:null;if((e===Xe||e===Ye)&&null!==(n=t.get("WEBGL_compressed_texture_etc"))){if(e===Xe)return n.COMPRESSED_RGB8_ETC2;if(e===Ye)return n.COMPRESSED_RGBA8_ETC2_EAC}return e===Ze||e===Je||e===Qe||e===Ke||e===$e||e===et||e===tt||e===nt||e===it||e===rt||e===at||e===ot||e===st||e===ct||e===lt||e===ht||e===ut||e===pt||e===dt||e===ft||e===mt||e===gt||e===vt||e===yt||e===xt||e===bt||e===_t||e===wt?null!==(n=t.get("WEBGL_compressed_texture_astc"))?e:null:e===we?i?34042:null!==(n=t.get("WEBGL_depth_texture"))?n.UNSIGNED_INT_24_8_WEBGL:null:void 0}}}function Uo(e){Pr.call(this),this.cameras=e||[]}function Go(){Pn.call(this),this.type="Group"}function Ho(e,t){var n=this,i=null,r=1,a=null,o="local-floor",s=null,c=[],l=new Map,h=new Pr;h.layers.enable(1),h.viewport=new Qt;var u=new Pr;u.layers.enable(2),u.viewport=new Qt;var p=new Uo([h,u]);p.layers.enable(1),p.layers.enable(2);var d=null,f=null;function m(e){var t=l.get(e.inputSource);t&&(t.targetRay&&t.targetRay.dispatchEvent({type:e.type}),t.grip&&t.grip.dispatchEvent({type:e.type}))}function g(){l.forEach(function(e,t){e.targetRay&&(e.targetRay.dispatchEvent({type:"disconnected",data:t}),e.targetRay.visible=!1),e.grip&&(e.grip.dispatchEvent({type:"disconnected",data:t}),e.grip.visible=!1)}),l.clear(),e.setFramebuffer(null),e.setRenderTarget(e.getRenderTarget()),M.stop(),n.isPresenting=!1,n.dispatchEvent({type:"sessionend"})}function v(e){a=e,M.setContext(i),M.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}function y(e){for(var t=i.inputSources,n=0;n=0){var l=r[s];if(void 0!==l){var h=l.normalized,u=l.itemSize,p=_.get(l);if(void 0===p)continue;var d=p.buffer,y=p.type,x=p.bytesPerElement;if(l.isInterleavedBufferAttribute){var b=l.data,w=b.stride,M=l.offset;b&&b.isInstancedInterleavedBuffer?(v.enableAttributeAndDivisor(c,b.meshPerAttribute),void 0===t.maxInstancedCount&&(t.maxInstancedCount=b.meshPerAttribute*b.count)):v.enableAttribute(c),f.bindBuffer(34962,d),f.vertexAttribPointer(c,u,y,h,w*x,M*x)}else l.isInstancedBufferAttribute?(v.enableAttributeAndDivisor(c,l.meshPerAttribute),void 0===t.maxInstancedCount&&(t.maxInstancedCount=l.meshPerAttribute*l.count)):v.enableAttribute(c),f.bindBuffer(34962,d),f.vertexAttribPointer(c,u,y,h,0,0)}else if("instanceMatrix"===s){var p=_.get(e.instanceMatrix);if(void 0===p)continue;var d=p.buffer,y=p.type;v.enableAttributeAndDivisor(c+0,1),v.enableAttributeAndDivisor(c+1,1),v.enableAttributeAndDivisor(c+2,1),v.enableAttributeAndDivisor(c+3,1),f.bindBuffer(34962,d),f.vertexAttribPointer(c+0,4,y,!1,64,0),f.vertexAttribPointer(c+1,4,y,!1,64,16),f.vertexAttribPointer(c+2,4,y,!1,64,32),f.vertexAttribPointer(c+3,4,y,!1,64,48)}else if(void 0!==o){var S=o[s];if(void 0!==S)switch(S.length){case 2:f.vertexAttrib2fv(c,S);break;case 3:f.vertexAttrib3fv(c,S);break;case 4:f.vertexAttrib4fv(c,S);break;default:f.vertexAttrib1fv(c,S)}}}}v.disableUnusedAttributes()}(r,n,i,s),null!==l&&f.bindBuffer(34963,u.buffer));var y=null!==l?l.count:h.count,x=n.drawRange.start*p,b=n.drawRange.count*p,M=null!==a?a.start*p:0,S=null!==a?a.count*p:1/0,T=Math.max(x,M),E=Math.min(y,x+b,M+S)-1,A=Math.max(0,E-T+1);if(0!==A){if(r.isMesh)!0===i.wireframe?(v.setLineWidth(i.wireframeLinewidth*se()),d.setMode(1)):d.setMode(4);else if(r.isLine){var C=i.linewidth;void 0===C&&(C=1),v.setLineWidth(C*se()),r.isLineSegments?d.setMode(1):r.isLineLoop?d.setMode(2):d.setMode(3)}else r.isPoints?d.setMode(0):r.isSprite&&d.setMode(4);r.isInstancedMesh?d.renderInstances(n,T,A,r.count):n.isInstancedBufferGeometry?d.renderInstances(n,T,A,n.maxInstancedCount):d.render(T,A)}},this.compile=function(e,t){(d=E.get(e,t)).init(),e.traverse(function(e){e.isLight&&(d.pushLight(e),e.castShadow&&d.pushShadow(e))}),d.setupLights(t);var n={};e.traverse(function(t){if(t.material)if(Array.isArray(t.material))for(var i=0;i=0&&e.numSupportedMorphTargets++}if(e.morphNormals){e.numSupportedMorphNormals=0;for(p=0;p=0&&e.numSupportedMorphNormals++}var f=i.uniforms;(e.isShaderMaterial||e.isRawShaderMaterial)&&!0!==e.clipping||(i.numClippingPlanes=ne.numPlanes,i.numIntersection=ne.numIntersection,f.clippingPlanes=ne.uniform),i.fog=t.fog,i.needsLights=function(e){return e.isMeshLambertMaterial||e.isMeshToonMaterial||e.isMeshPhongMaterial||e.isMeshStandardMaterial||e.isShadowMaterial||e.isShaderMaterial&&!0===e.lights}(e),i.lightsStateVersion=o,i.needsLights&&(f.ambientLightColor.value=r.state.ambient,f.lightProbe.value=r.state.probe,f.directionalLights.value=r.state.directional,f.directionalLightShadows.value=r.state.directionalShadow,f.spotLights.value=r.state.spot,f.spotLightShadows.value=r.state.spotShadow,f.rectAreaLights.value=r.state.rectArea,f.pointLights.value=r.state.point,f.pointLightShadows.value=r.state.pointShadow,f.hemisphereLights.value=r.state.hemi,f.directionalShadowMap.value=r.state.directionalShadowMap,f.directionalShadowMatrix.value=r.state.directionalShadowMatrix,f.spotShadowMap.value=r.state.spotShadowMap,f.spotShadowMatrix.value=r.state.spotShadowMatrix,f.pointShadowMap.value=r.state.pointShadowMap,f.pointShadowMatrix.value=r.state.pointShadowMatrix);var m=i.program.getUniforms(),g=eo.seqWithValue(m.seq,f);i.uniformsList=g}function Ee(e,t,n,i){b.resetTextureUnits();var r=t.fog,a=n.isMeshStandardMaterial?t.environment:null,o=x.get(n),s=d.state.lights;if(ie&&(re||e!==H)){var l=e===H&&n.id===U;ne.setState(n.clippingPlanes,n.clipIntersection,n.clipShadows,e,o,l)}n.version===o.__version?void 0===o.program?Se(n,t,i):n.fog&&o.fog!==r?Se(n,t,i):o.environment!==a?Se(n,t,i):o.needsLights&&o.lightsStateVersion!==s.state.version?Se(n,t,i):void 0===o.numClippingPlanes||o.numClippingPlanes===ne.numPlanes&&o.numIntersection===ne.numIntersection?o.outputEncoding!==O.outputEncoding&&Se(n,t,i):Se(n,t,i):(Se(n,t,i),o.__version=n.version);var h,u,p=!1,m=!1,y=!1,_=o.program,w=_.getUniforms(),M=o.uniforms;if(v.useProgram(_.program)&&(p=!0,m=!0,y=!0),n.id!==U&&(U=n.id,m=!0),p||H!==e){if(w.setValue(f,"projectionMatrix",e.projectionMatrix),g.logarithmicDepthBuffer&&w.setValue(f,"logDepthBufFC",2/(Math.log(e.far+1)/Math.LN2)),H!==e&&(H=e,m=!0,y=!0),n.isShaderMaterial||n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshStandardMaterial||n.envMap){var S=w.map.cameraPosition;void 0!==S&&S.setValue(f,oe.setFromMatrixPosition(e.matrixWorld))}(n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshLambertMaterial||n.isMeshBasicMaterial||n.isMeshStandardMaterial||n.isShaderMaterial)&&w.setValue(f,"isOrthographic",!0===e.isOrthographicCamera),(n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshLambertMaterial||n.isMeshBasicMaterial||n.isMeshStandardMaterial||n.isShaderMaterial||n.skinning)&&w.setValue(f,"viewMatrix",e.matrixWorldInverse)}if(n.skinning){w.setOptional(f,i,"bindMatrix"),w.setOptional(f,i,"bindMatrixInverse");var T=i.skeleton;if(T){var E=T.bones;if(g.floatVertexTextures){if(void 0===T.boneTexture){var A=Math.sqrt(4*E.length);A=Wt.ceilPowerOfTwo(A),A=Math.max(A,4);var L=new Float32Array(A*A*4);L.set(T.boneMatrices);var R=new Nr(L,A,A,Te,ve);T.boneMatrices=L,T.boneTexture=R,T.boneTextureSize=A}w.setValue(f,"boneTexture",T.boneTexture,b),w.setValue(f,"boneTextureSize",T.boneTextureSize)}else w.setOptional(f,T,"boneMatrices")}}return(m||o.receiveShadow!==i.receiveShadow)&&(o.receiveShadow=i.receiveShadow,w.setValue(f,"receiveShadow",i.receiveShadow)),m&&(w.setValue(f,"toneMappingExposure",O.toneMappingExposure),w.setValue(f,"toneMappingWhitePoint",O.toneMappingWhitePoint),o.needsLights&&(u=y,(h=M).ambientLightColor.needsUpdate=u,h.lightProbe.needsUpdate=u,h.directionalLights.needsUpdate=u,h.directionalLightShadows.needsUpdate=u,h.pointLights.needsUpdate=u,h.pointLightShadows.needsUpdate=u,h.spotLights.needsUpdate=u,h.spotLightShadows.needsUpdate=u,h.rectAreaLights.needsUpdate=u,h.hemisphereLights.needsUpdate=u),r&&n.fog&&function(e,t){e.fogColor.value.copy(t.color),t.isFog?(e.fogNear.value=t.near,e.fogFar.value=t.far):t.isFogExp2&&(e.fogDensity.value=t.density)}(M,r),n.isMeshBasicMaterial?Ae(M,n):n.isMeshLambertMaterial?(Ae(M,n),function(e,t){t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap)}(M,n)):n.isMeshToonMaterial?(Ae(M,n),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4),t.gradientMap&&(e.gradientMap.value=t.gradientMap);t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshPhongMaterial?(Ae(M,n),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4),t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshStandardMaterial?(Ae(M,n,a),n.isMeshPhysicalMaterial?function(e,t,n){Le(e,t,n),e.reflectivity.value=t.reflectivity,e.clearcoat.value=t.clearcoat,e.clearcoatRoughness.value=t.clearcoatRoughness,t.sheen&&e.sheen.value.copy(t.sheen);t.clearcoatNormalMap&&(e.clearcoatNormalScale.value.copy(t.clearcoatNormalScale),e.clearcoatNormalMap.value=t.clearcoatNormalMap,t.side===c&&e.clearcoatNormalScale.value.negate());e.transparency.value=t.transparency}(M,n,a):Le(M,n,a)):n.isMeshMatcapMaterial?(Ae(M,n),function(e,t){t.matcap&&(e.matcap.value=t.matcap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshDepthMaterial?(Ae(M,n),function(e,t){t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshDistanceMaterial?(Ae(M,n),function(e,t){t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias);e.referencePosition.value.copy(t.referencePosition),e.nearDistance.value=t.nearDistance,e.farDistance.value=t.farDistance}(M,n)):n.isMeshNormalMaterial?(Ae(M,n),function(e,t){t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isLineBasicMaterial?(function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity}(M,n),n.isLineDashedMaterial&&function(e,t){e.dashSize.value=t.dashSize,e.totalSize.value=t.dashSize+t.gapSize,e.scale.value=t.scale}(M,n)):n.isPointsMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.size.value=t.size*Z,e.scale.value=.5*Y,t.map&&(e.map.value=t.map);t.alphaMap&&(e.alphaMap.value=t.alphaMap);var n;t.map?n=t.map:t.alphaMap&&(n=t.alphaMap);void 0!==n&&(!0===n.matrixAutoUpdate&&n.updateMatrix(),e.uvTransform.value.copy(n.matrix))}(M,n):n.isSpriteMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.rotation.value=t.rotation,t.map&&(e.map.value=t.map);t.alphaMap&&(e.alphaMap.value=t.alphaMap);var n;t.map?n=t.map:t.alphaMap&&(n=t.alphaMap);void 0!==n&&(!0===n.matrixAutoUpdate&&n.updateMatrix(),e.uvTransform.value.copy(n.matrix))}(M,n):n.isShadowMaterial&&(M.color.value.copy(n.color),M.opacity.value=n.opacity),void 0!==M.ltc_1&&(M.ltc_1.value=Ur.LTC_1),void 0!==M.ltc_2&&(M.ltc_2.value=Ur.LTC_2),eo.upload(f,o.uniformsList,M,b),n.isShaderMaterial&&(n.uniformsNeedUpdate=!1)),n.isShaderMaterial&&!0===n.uniformsNeedUpdate&&(eo.upload(f,o.uniformsList,M,b),n.uniformsNeedUpdate=!1),n.isSpriteMaterial&&w.setValue(f,"center",i.center),w.setValue(f,"modelViewMatrix",i.modelViewMatrix),w.setValue(f,"normalMatrix",i.normalMatrix),w.setValue(f,"modelMatrix",i.matrixWorld),_}function Ae(e,t,n){e.opacity.value=t.opacity,t.color&&e.diffuse.value.copy(t.color),t.emissive&&e.emissive.value.copy(t.emissive).multiplyScalar(t.emissiveIntensity),t.map&&(e.map.value=t.map),t.alphaMap&&(e.alphaMap.value=t.alphaMap),t.specularMap&&(e.specularMap.value=t.specularMap);var i,r,a=t.envMap||n;a&&(e.envMap.value=a,e.flipEnvMap.value=a.isCubeTexture?-1:1,e.reflectivity.value=t.reflectivity,e.refractionRatio.value=t.refractionRatio,e.maxMipLevel.value=x.get(a).__maxMipLevel),t.lightMap&&(e.lightMap.value=t.lightMap,e.lightMapIntensity.value=t.lightMapIntensity),t.aoMap&&(e.aoMap.value=t.aoMap,e.aoMapIntensity.value=t.aoMapIntensity),t.map?i=t.map:t.specularMap?i=t.specularMap:t.displacementMap?i=t.displacementMap:t.normalMap?i=t.normalMap:t.bumpMap?i=t.bumpMap:t.roughnessMap?i=t.roughnessMap:t.metalnessMap?i=t.metalnessMap:t.alphaMap?i=t.alphaMap:t.emissiveMap&&(i=t.emissiveMap),void 0!==i&&(i.isWebGLRenderTarget&&(i=i.texture),!0===i.matrixAutoUpdate&&i.updateMatrix(),e.uvTransform.value.copy(i.matrix)),t.aoMap?r=t.aoMap:t.lightMap&&(r=t.lightMap),void 0!==r&&(r.isWebGLRenderTarget&&(r=r.texture),!0===r.matrixAutoUpdate&&r.updateMatrix(),e.uv2Transform.value.copy(r.matrix))}function Le(e,t,n){e.roughness.value=t.roughness,e.metalness.value=t.metalness,t.roughnessMap&&(e.roughnessMap.value=t.roughnessMap),t.metalnessMap&&(e.metalnessMap.value=t.metalnessMap),t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap),t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1)),t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate()),t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias),(t.envMap||n)&&(e.envMapIntensity.value=t.envMapIntensity)}_e.setAnimationLoop(function(e){he.isPresenting||be&&be(e)}),"undefined"!=typeof window&&_e.setContext(window),this.setAnimationLoop=function(e){be=e,he.setAnimationLoop(e),_e.start()},this.render=function(e,t){var n,i;if(void 0!==arguments[2]&&(console.warn("THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead."),n=arguments[2]),void 0!==arguments[3]&&(console.warn("THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead."),i=arguments[3]),t&&t.isCamera){if(!D){G.geometry=null,G.program=null,G.wireframe=!1,U=-1,H=null,!0===e.autoUpdate&&e.updateMatrixWorld(),null===t.parent&&t.updateMatrixWorld(),he.enabled&&he.isPresenting&&(t=he.getCamera(t)),(d=E.get(e,t)).init(),e.onBeforeRender(O,e,t,n||z),ae.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),te.setFromProjectionMatrix(ae),re=this.localClippingEnabled,ie=ne.init(this.clippingPlanes,re,t),(p=T.get(e,t)).init(),function e(t,n,i,r){if(!1===t.visible)return;var a=t.layers.test(n.layers);if(a)if(t.isGroup)i=t.renderOrder;else if(t.isLOD)!0===t.autoUpdate&&t.update(n);else if(t.isLight)d.pushLight(t),t.castShadow&&d.pushShadow(t);else if(t.isSprite){if(!t.frustumCulled||te.intersectsSprite(t)){r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae);var o=M.update(t),s=t.material;s.visible&&p.push(t,o,s,i,oe.z,null)}}else if(t.isImmediateRenderObject)r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae),p.push(t,null,t.material,i,oe.z,null);else if((t.isMesh||t.isLine||t.isPoints)&&(t.isSkinnedMesh&&t.skeleton.frame!==y.render.frame&&(t.skeleton.update(),t.skeleton.frame=y.render.frame),!t.frustumCulled||te.intersectsObject(t))){r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae);var o=M.update(t),s=t.material;if(Array.isArray(s))for(var c=o.groups,l=0,h=c.length;l=0&&t<=e.width-i&&n>=0&&n<=e.height-r&&f.readPixels(t,n,i,r,C.convert(h),C.convert(u),a):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.")}finally{c&&f.bindFramebuffer(36160,F)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")},this.copyFramebufferToTexture=function(e,t,n){void 0===n&&(n=0);var i=Math.pow(2,-n),r=Math.floor(t.image.width*i),a=Math.floor(t.image.height*i),o=C.convert(t.format);b.setTexture2D(t,0),f.copyTexImage2D(3553,n,o,e.x,e.y,r,a,0),v.unbindTexture()},this.copyTextureToTexture=function(e,t,n,i){var r=t.image.width,a=t.image.height,o=C.convert(n.format),s=C.convert(n.type);b.setTexture2D(n,0),t.isDataTexture?f.texSubImage2D(3553,i||0,e.x,e.y,r,a,o,s,t.image.data):f.texSubImage2D(3553,i||0,e.x,e.y,o,s,t.image),v.unbindTexture()},this.initTexture=function(e){b.setTexture2D(e,0),v.unbindTexture()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}function ko(e,t){this.name="",this.color=new _i(e),this.density=void 0!==t?t:25e-5}function jo(e,t,n){this.name="",this.color=new _i(e),this.near=void 0!==t?t:1,this.far=void 0!==n?n:1e3}function Wo(e,t){this.array=e,this.stride=t,this.count=void 0!==e?e.length/t:0,this.usage=Ut,this.updateRange={offset:0,count:-1},this.version=0}Uo.prototype=Object.assign(Object.create(Pr.prototype),{constructor:Uo,isArrayCamera:!0}),Go.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Go,isGroup:!0}),Object.assign(Ho.prototype,Ht.prototype),Object.assign(ko.prototype,{isFogExp2:!0,clone:function(){return new ko(this.color,this.density)},toJSON:function(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}}),Object.assign(jo.prototype,{isFog:!0,clone:function(){return new jo(this.color,this.near,this.far)},toJSON:function(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}}),Object.defineProperty(Wo.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.assign(Wo.prototype,{isInterleavedBuffer:!0,onUploadCallback:function(){},setUsage:function(e){return this.usage=e,this},copy:function(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this},copyAt:function(e,t,n){e*=this.stride,n*=t.stride;for(var i=0,r=this.stride;ie.far||t.push({distance:s,point:Jo.clone(),uv:vi.getUV(Jo,ns,is,rs,as,os,ss,new qt),face:null,object:this})}},clone:function(){return new this.constructor(this.material).copy(this)},copy:function(e){return Pn.prototype.copy.call(this,e),void 0!==e.center&&this.center.copy(e.center),this}});var hs=new rn,us=new rn;function ps(){Pn.call(this),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]}}),this.autoUpdate=!0}function ds(e,t){e&&e.isGeometry&&console.error("THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."),dr.call(this,e,t),this.type="SkinnedMesh",this.bindMode="attached",this.bindMatrix=new pn,this.bindMatrixInverse=new pn}ps.prototype=Object.assign(Object.create(Pn.prototype),{constructor:ps,isLOD:!0,copy:function(e){Pn.prototype.copy.call(this,e,!1);for(var t=e.levels,n=0,i=t.length;n0){for(var n=1,i=t.length;n0){hs.setFromMatrixPosition(this.matrixWorld);var n=e.ray.origin.distanceTo(hs);this.getObjectForDistance(n).raycast(e,t)}},update:function(e){var t=this.levels;if(t.length>1){hs.setFromMatrixPosition(e.matrixWorld),us.setFromMatrixPosition(this.matrixWorld);var n=hs.distanceTo(us)/e.zoom;t[0].object.visible=!0;for(var i=1,r=t.length;i=t[i].distance;i++)t[i-1].object.visible=!1,t[i].object.visible=!0;for(this._currentLevel=i-1;i0&&(bs[0].instanceId=r,bs[0].object=this,t.push(bs[0]),bs.length=0)},setMatrixAt:function(e,t){t.toArray(this.instanceMatrix.array,16*e)},updateMorphTargets:function(){}}),Ms.prototype=Object.create(Ai.prototype),Ms.prototype.constructor=Ms,Ms.prototype.isLineBasicMaterial=!0,Ms.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this};var Ss=new rn,Ts=new rn,Es=new pn,As=new ni,Ls=new Yn;function Rs(e,t,n){1===n&&console.error("THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead."),Pn.call(this),this.type="Line",this.geometry=void 0!==e?e:new Zi,this.material=void 0!==t?t:new Ms}Rs.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Rs,isLine:!0,computeLineDistances:function(){var e=this.geometry;if(e.isBufferGeometry)if(null===e.index){for(var t=e.attributes.position,n=[0],i=1,r=t.count;io))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}else for(m=0,g=d.length/3-1;mo))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}}else if(n.isGeometry){var x=n.vertices,b=x.length;for(m=0;mo))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}}}},clone:function(){return new this.constructor(this.geometry,this.material).copy(this)}});var Ps=new rn,Cs=new rn;function Os(e,t){Rs.call(this,e,t),this.type="LineSegments"}function Ds(e,t){Rs.call(this,e,t),this.type="LineLoop"}function Is(e){Ai.call(this),this.type="PointsMaterial",this.color=new _i(16777215),this.map=null,this.alphaMap=null,this.size=1,this.sizeAttenuation=!0,this.morphTargets=!1,this.setValues(e)}Os.prototype=Object.assign(Object.create(Rs.prototype),{constructor:Os,isLineSegments:!0,computeLineDistances:function(){var e=this.geometry;if(e.isBufferGeometry)if(null===e.index){for(var t=e.attributes.position,n=[],i=0,r=t.count;ir.far)return;a.push({distance:l,distanceToRay:Math.sqrt(s),point:c,index:t,face:null,object:o})}}function Hs(e,t,n,i,r,a,o,s,c){Jt.call(this,e,t,n,i,r,a,o,s,c),this.format=void 0!==o?o:Se,this.minFilter=void 0!==a?a:ce,this.magFilter=void 0!==r?r:ce,this.generateMipmaps=!1}function Vs(e,t,n,i,r,a,o,s,c,l,h,u){Jt.call(this,null,a,o,s,c,l,i,r,h,u),this.image={width:t,height:n},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}function ks(e,t,n,i,r,a,o,s,c){Jt.call(this,e,t,n,i,r,a,o,s,c),this.needsUpdate=!0}function js(e,t,n,i,r,a,o,s,c,l){if((l=void 0!==l?l:Re)!==Re&&l!==Pe)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===n&&l===Re&&(n=fe),void 0===n&&l===Pe&&(n=we),Jt.call(this,null,i,r,a,o,s,l,n,c),this.image={width:e,height:t},this.magFilter=void 0!==o?o:ae,this.minFilter=void 0!==s?s:ae,this.flipY=!1,this.generateMipmaps=!1}function Ws(e){Zi.call(this),this.type="WireframeGeometry";var t,n,i,r,a,o,s,c,l,h,u=[],p=[0,0],d={},f=["a","b","c"];if(e&&e.isGeometry){var m=e.faces;for(t=0,i=m.length;t=0?(e(g-1e-5,m,u),p.subVectors(h,u)):(e(g+1e-5,m,u),p.subVectors(u,h)),m-1e-5>=0?(e(g,m-1e-5,u),d.subVectors(h,u)):(e(g,m+1e-5,u),d.subVectors(u,h)),l.crossVectors(p,d).normalize(),s.push(l.x,l.y,l.z),c.push(g,m)}}for(i=0;i.9&&o<.1&&(t<.2&&(a[e+0]+=1),n<.2&&(a[e+2]+=1),i<.2&&(a[e+4]+=1))}}()}(),this.setAttribute("position",new Fi(r,3)),this.setAttribute("normal",new Fi(r.slice(),3)),this.setAttribute("uv",new Fi(a,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}function Js(e,t){br.call(this),this.type="TetrahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new Qs(e,t)),this.mergeVertices()}function Qs(e,t){Zs.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],e,t),this.type="TetrahedronBufferGeometry",this.parameters={radius:e,detail:t}}function Ks(e,t){br.call(this),this.type="OctahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new $s(e,t)),this.mergeVertices()}function $s(e,t){Zs.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],e,t),this.type="OctahedronBufferGeometry",this.parameters={radius:e,detail:t}}function ec(e,t){br.call(this),this.type="IcosahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new tc(e,t)),this.mergeVertices()}function tc(e,t){var n=(1+Math.sqrt(5))/2,i=[-1,n,0,1,n,0,-1,-n,0,1,-n,0,0,-1,n,0,1,n,0,-1,-n,0,1,-n,n,0,-1,n,0,1,-n,0,-1,-n,0,1];Zs.call(this,i,[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],e,t),this.type="IcosahedronBufferGeometry",this.parameters={radius:e,detail:t}}function nc(e,t){br.call(this),this.type="DodecahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new ic(e,t)),this.mergeVertices()}function ic(e,t){var n=(1+Math.sqrt(5))/2,i=1/n,r=[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i];Zs.call(this,r,[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,t),this.type="DodecahedronBufferGeometry",this.parameters={radius:e,detail:t}}function rc(e,t,n,i,r,a){br.call(this),this.type="TubeGeometry",this.parameters={path:e,tubularSegments:t,radius:n,radialSegments:i,closed:r},void 0!==a&&console.warn("THREE.TubeGeometry: taper has been removed.");var o=new ac(e,t,n,i,r);this.tangents=o.tangents,this.normals=o.normals,this.binormals=o.binormals,this.fromBufferGeometry(o),this.mergeVertices()}function ac(e,t,n,i,r){Zi.call(this),this.type="TubeBufferGeometry",this.parameters={path:e,tubularSegments:t,radius:n,radialSegments:i,closed:r},t=t||64,n=n||1,i=i||8,r=r||!1;var a=e.computeFrenetFrames(t,r);this.tangents=a.tangents,this.normals=a.normals,this.binormals=a.binormals;var o,s,c=new rn,l=new rn,h=new qt,u=new rn,p=[],d=[],f=[],m=[];function g(r){u=e.getPointAt(r/t,u);var o=a.normals[r],h=a.binormals[r];for(s=0;s<=i;s++){var f=s/i*Math.PI*2,m=Math.sin(f),g=-Math.cos(f);l.x=g*o.x+m*h.x,l.y=g*o.y+m*h.y,l.z=g*o.z+m*h.z,l.normalize(),d.push(l.x,l.y,l.z),c.x=u.x+n*l.x,c.y=u.y+n*l.y,c.z=u.z+n*l.z,p.push(c.x,c.y,c.z)}}!function(){for(o=0;o0){var o=r[a[0]];if(void 0!==o)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},e=0,t=o.length;e0&&console.error("THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}},clone:function(){return new this.constructor(this.geometry,this.material).copy(this)}}),Hs.prototype=Object.assign(Object.create(Jt.prototype),{constructor:Hs,isVideoTexture:!0,update:function(){var e=this.image;e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}),Vs.prototype=Object.create(Jt.prototype),Vs.prototype.constructor=Vs,Vs.prototype.isCompressedTexture=!0,ks.prototype=Object.create(Jt.prototype),ks.prototype.constructor=ks,ks.prototype.isCanvasTexture=!0,js.prototype=Object.create(Jt.prototype),js.prototype.constructor=js,js.prototype.isDepthTexture=!0,Ws.prototype=Object.create(Zi.prototype),Ws.prototype.constructor=Ws,qs.prototype=Object.create(br.prototype),qs.prototype.constructor=qs,Xs.prototype=Object.create(Zi.prototype),Xs.prototype.constructor=Xs,Ys.prototype=Object.create(br.prototype),Ys.prototype.constructor=Ys,Zs.prototype=Object.create(Zi.prototype),Zs.prototype.constructor=Zs,Js.prototype=Object.create(br.prototype),Js.prototype.constructor=Js,Qs.prototype=Object.create(Zs.prototype),Qs.prototype.constructor=Qs,Ks.prototype=Object.create(br.prototype),Ks.prototype.constructor=Ks,$s.prototype=Object.create(Zs.prototype),$s.prototype.constructor=$s,ec.prototype=Object.create(br.prototype),ec.prototype.constructor=ec,tc.prototype=Object.create(Zs.prototype),tc.prototype.constructor=tc,nc.prototype=Object.create(br.prototype),nc.prototype.constructor=nc,ic.prototype=Object.create(Zs.prototype),ic.prototype.constructor=ic,rc.prototype=Object.create(br.prototype),rc.prototype.constructor=rc,ac.prototype=Object.create(Zi.prototype),ac.prototype.constructor=ac,ac.prototype.toJSON=function(){var e=Zi.prototype.toJSON.call(this);return e.path=this.parameters.path.toJSON(),e},oc.prototype=Object.create(br.prototype),oc.prototype.constructor=oc,sc.prototype=Object.create(Zi.prototype),sc.prototype.constructor=sc,cc.prototype=Object.create(br.prototype),cc.prototype.constructor=cc,lc.prototype=Object.create(Zi.prototype),lc.prototype.constructor=lc;var hc=function(e,t,n){n=n||2;var i,r,a,o,s,c,l,h=t&&t.length,u=h?t[0]*n:e.length,p=uc(e,0,u,n,!0),d=[];if(!p||p.next===p.prev)return d;if(h&&(p=function(e,t,n,i){var r,a,o,s,c,l=[];for(r=0,a=t.length;r80*n){i=a=e[0],r=o=e[1];for(var f=n;fa&&(a=s),c>o&&(o=c);l=0!==(l=Math.max(a-i,o-r))?1/l:0}return dc(p,d,n,i,r,l),d};function uc(e,t,n,i,r){var a,o;if(r===function(e,t,n,i){for(var r=0,a=t,o=n-i;a0)for(a=t;a=t;a-=i)o=Rc(a,e[a],e[a+1],o);return o&&Tc(o,o.next)&&(Pc(o),o=o.next),o}function pc(e,t){if(!e)return e;t||(t=e);var n,i=e;do{if(n=!1,i.steiner||!Tc(i,i.next)&&0!==Sc(i.prev,i,i.next))i=i.next;else{if(Pc(i),(i=t=i.prev)===i.next)break;n=!0}}while(n||i!==t);return t}function dc(e,t,n,i,r,a,o){if(e){!o&&a&&function(e,t,n,i){var r=e;do{null===r.z&&(r.z=bc(r.x,r.y,t,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==e);r.prevZ.nextZ=null,r.prevZ=null,function(e){var t,n,i,r,a,o,s,c,l=1;do{for(n=e,e=null,a=null,o=0;n;){for(o++,i=n,s=0,t=0;t0||c>0&&i;)0!==s&&(0===c||!i||n.z<=i.z)?(r=n,n=n.nextZ,s--):(r=i,i=i.nextZ,c--),a?a.nextZ=r:e=r,r.prevZ=a,a=r;n=i}a.nextZ=null,l*=2}while(o>1)}(r)}(e,i,r,a);for(var s,c,l=e;e.prev!==e.next;)if(s=e.prev,c=e.next,a?mc(e,i,r,a):fc(e))t.push(s.i/n),t.push(e.i/n),t.push(c.i/n),Pc(e),e=c.next,l=c.next;else if((e=c)===l){o?1===o?dc(e=gc(e,t,n),t,n,i,r,a,2):2===o&&vc(e,t,n,i,r,a):dc(pc(e),t,n,i,r,a,1);break}}}function fc(e){var t=e.prev,n=e,i=e.next;if(Sc(t,n,i)>=0)return!1;for(var r=e.next.next;r!==e.prev;){if(wc(t.x,t.y,n.x,n.y,i.x,i.y,r.x,r.y)&&Sc(r.prev,r,r.next)>=0)return!1;r=r.next}return!0}function mc(e,t,n,i){var r=e.prev,a=e,o=e.next;if(Sc(r,a,o)>=0)return!1;for(var s=r.xa.x?r.x>o.x?r.x:o.x:a.x>o.x?a.x:o.x,h=r.y>a.y?r.y>o.y?r.y:o.y:a.y>o.y?a.y:o.y,u=bc(s,c,t,n,i),p=bc(l,h,t,n,i),d=e.prevZ,f=e.nextZ;d&&d.z>=u&&f&&f.z<=p;){if(d!==e.prev&&d!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,d.x,d.y)&&Sc(d.prev,d,d.next)>=0)return!1;if(d=d.prevZ,f!==e.prev&&f!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,f.x,f.y)&&Sc(f.prev,f,f.next)>=0)return!1;f=f.nextZ}for(;d&&d.z>=u;){if(d!==e.prev&&d!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,d.x,d.y)&&Sc(d.prev,d,d.next)>=0)return!1;d=d.prevZ}for(;f&&f.z<=p;){if(f!==e.prev&&f!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,f.x,f.y)&&Sc(f.prev,f,f.next)>=0)return!1;f=f.nextZ}return!0}function gc(e,t,n){var i=e;do{var r=i.prev,a=i.next.next;!Tc(r,a)&&Ec(r,i,i.next,a)&&Ac(r,a)&&Ac(a,r)&&(t.push(r.i/n),t.push(i.i/n),t.push(a.i/n),Pc(i),Pc(i.next),i=e=a),i=i.next}while(i!==e);return i}function vc(e,t,n,i,r,a){var o=e;do{for(var s=o.next.next;s!==o.prev;){if(o.i!==s.i&&Mc(o,s)){var c=Lc(o,s);return o=pc(o,o.next),c=pc(c,c.next),dc(o,t,n,i,r,a),void dc(c,t,n,i,r,a)}s=s.next}o=o.next}while(o!==e)}function yc(e,t){return e.x-t.x}function xc(e,t){if(t=function(e,t){var n,i=t,r=e.x,a=e.y,o=-1/0;do{if(a<=i.y&&a>=i.next.y&&i.next.y!==i.y){var s=i.x+(a-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(s<=r&&s>o){if(o=s,s===r){if(a===i.y)return i;if(a===i.next.y)return i.next}n=i.x=i.x&&i.x>=h&&r!==i.x&&wc(an.x)&&Ac(i,e)&&(n=i,p=c),i=i.next;return n}(e,t)){var n=Lc(t,e);pc(n,n.next)}}function bc(e,t,n,i,r){return(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=32767*(e-n)*r)|e<<8))|e<<4))|e<<2))|e<<1))|(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=32767*(t-i)*r)|t<<8))|t<<4))|t<<2))|t<<1))<<1}function _c(e){var t=e,n=e;do{(t.x=0&&(e-o)*(i-s)-(n-o)*(t-s)>=0&&(n-o)*(a-s)-(r-o)*(i-s)>=0}function Mc(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!function(e,t){var n=e;do{if(n.i!==e.i&&n.next.i!==e.i&&n.i!==t.i&&n.next.i!==t.i&&Ec(n,n.next,e,t))return!0;n=n.next}while(n!==e);return!1}(e,t)&&Ac(e,t)&&Ac(t,e)&&function(e,t){var n=e,i=!1,r=(e.x+t.x)/2,a=(e.y+t.y)/2;do{n.y>a!=n.next.y>a&&n.next.y!==n.y&&r<(n.next.x-n.x)*(a-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==e);return i}(e,t)}function Sc(e,t,n){return(t.y-e.y)*(n.x-t.x)-(t.x-e.x)*(n.y-t.y)}function Tc(e,t){return e.x===t.x&&e.y===t.y}function Ec(e,t,n,i){return!!(Tc(e,n)&&Tc(t,i)||Tc(e,i)&&Tc(n,t))||Sc(e,t,n)>0!=Sc(e,t,i)>0&&Sc(n,i,e)>0!=Sc(n,i,t)>0}function Ac(e,t){return Sc(e.prev,e,e.next)<0?Sc(e,t,e.next)>=0&&Sc(e,e.prev,t)>=0:Sc(e,t,e.prev)<0||Sc(e,e.next,t)<0}function Lc(e,t){var n=new Cc(e.i,e.x,e.y),i=new Cc(t.i,t.x,t.y),r=e.next,a=t.prev;return e.next=t,t.prev=e,n.next=r,r.prev=n,i.next=n,n.prev=i,a.next=i,i.prev=a,i}function Rc(e,t,n,i){var r=new Cc(e,t,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function Pc(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function Cc(e,t,n){this.i=e,this.x=t,this.y=n,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}var Oc={area:function(e){for(var t=e.length,n=0,i=t-1,r=0;r2&&e[t-1].equals(e[0])&&e.pop()}function Ic(e,t){for(var n=0;nNumber.EPSILON){var p=Math.sqrt(h),d=Math.sqrt(c*c+l*l),f=t.x-s/p,m=t.y+o/p,g=((n.x-l/d-f)*l-(n.y+c/d-m)*c)/(o*l-s*c),v=(i=f+o*g-e.x)*i+(r=m+s*g-e.y)*r;if(v<=2)return new qt(i,r);a=Math.sqrt(v/2)}else{var y=!1;o>Number.EPSILON?c>Number.EPSILON&&(y=!0):o<-Number.EPSILON?c<-Number.EPSILON&&(y=!0):Math.sign(s)===Math.sign(l)&&(y=!0),y?(i=-s,r=o,a=Math.sqrt(h)):(i=o,r=s,a=Math.sqrt(h/2))}return new qt(i/a,r/a)}for(var G=[],H=0,V=R.length,k=V-1,j=H+1;H=0;C--){for(D=C/d,I=h*Math.cos(D*Math.PI/2),O=u*Math.sin(D*Math.PI/2)+p,H=0,V=R.length;H=0;){n=H,(i=H-1)<0&&(i=e.length-1);var r=0,a=s+2*d;for(r=0;r0)&&f.push(w,M,T),(c!==n-1||l0&&v(!0),t>0&&v(!1)),this.setIndex(l),this.setAttribute("position",new Fi(h,3)),this.setAttribute("normal",new Fi(u,3)),this.setAttribute("uv",new Fi(p,2))}function $c(e,t,n,i,r,a,o){Qc.call(this,0,e,t,n,i,r,a,o),this.type="ConeGeometry",this.parameters={radius:e,height:t,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:a,thetaLength:o}}function el(e,t,n,i,r,a,o){Kc.call(this,0,e,t,n,i,r,a,o),this.type="ConeBufferGeometry",this.parameters={radius:e,height:t,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:a,thetaLength:o}}function tl(e,t,n,i){br.call(this),this.type="CircleGeometry",this.parameters={radius:e,segments:t,thetaStart:n,thetaLength:i},this.fromBufferGeometry(new nl(e,t,n,i)),this.mergeVertices()}function nl(e,t,n,i){Zi.call(this),this.type="CircleBufferGeometry",this.parameters={radius:e,segments:t,thetaStart:n,thetaLength:i},e=e||1,t=void 0!==t?Math.max(3,t):8,n=void 0!==n?n:0,i=void 0!==i?i:2*Math.PI;var r,a,o=[],s=[],c=[],l=[],h=new rn,u=new qt;for(s.push(0,0,0),c.push(0,0,1),l.push(.5,.5),a=0,r=3;a<=t;a++,r+=3){var p=n+a/t*i;h.x=e*Math.cos(p),h.y=e*Math.sin(p),s.push(h.x,h.y,h.z),c.push(0,0,1),u.x=(s[r]/e+1)/2,u.y=(s[r+1]/e+1)/2,l.push(u.x,u.y)}for(r=1;r<=t;r++)o.push(r,r+1,0);this.setIndex(o),this.setAttribute("position",new Fi(s,3)),this.setAttribute("normal",new Fi(c,3)),this.setAttribute("uv",new Fi(l,2))}Uc.prototype=Object.create(br.prototype),Uc.prototype.constructor=Uc,Gc.prototype=Object.create(Bc.prototype),Gc.prototype.constructor=Gc,Hc.prototype=Object.create(br.prototype),Hc.prototype.constructor=Hc,Vc.prototype=Object.create(Zi.prototype),Vc.prototype.constructor=Vc,kc.prototype=Object.create(br.prototype),kc.prototype.constructor=kc,jc.prototype=Object.create(Zi.prototype),jc.prototype.constructor=jc,Wc.prototype=Object.create(br.prototype),Wc.prototype.constructor=Wc,qc.prototype=Object.create(Zi.prototype),qc.prototype.constructor=qc,Xc.prototype=Object.create(br.prototype),Xc.prototype.constructor=Xc,Xc.prototype.toJSON=function(){var e=br.prototype.toJSON.call(this);return Zc(this.parameters.shapes,e)},Yc.prototype=Object.create(Zi.prototype),Yc.prototype.constructor=Yc,Yc.prototype.toJSON=function(){var e=Zi.prototype.toJSON.call(this);return Zc(this.parameters.shapes,e)},Jc.prototype=Object.create(Zi.prototype),Jc.prototype.constructor=Jc,Qc.prototype=Object.create(br.prototype),Qc.prototype.constructor=Qc,Kc.prototype=Object.create(Zi.prototype),Kc.prototype.constructor=Kc,$c.prototype=Object.create(Qc.prototype),$c.prototype.constructor=$c,el.prototype=Object.create(Kc.prototype),el.prototype.constructor=el,tl.prototype=Object.create(br.prototype),tl.prototype.constructor=tl,nl.prototype=Object.create(Zi.prototype),nl.prototype.constructor=nl;var il=Object.freeze({__proto__:null,WireframeGeometry:Ws,ParametricGeometry:qs,ParametricBufferGeometry:Xs,TetrahedronGeometry:Js,TetrahedronBufferGeometry:Qs,OctahedronGeometry:Ks,OctahedronBufferGeometry:$s,IcosahedronGeometry:ec,IcosahedronBufferGeometry:tc,DodecahedronGeometry:nc,DodecahedronBufferGeometry:ic,PolyhedronGeometry:Ys,PolyhedronBufferGeometry:Zs,TubeGeometry:rc,TubeBufferGeometry:ac,TorusKnotGeometry:oc,TorusKnotBufferGeometry:sc,TorusGeometry:cc,TorusBufferGeometry:lc,TextGeometry:Uc,TextBufferGeometry:Gc,SphereGeometry:Hc,SphereBufferGeometry:Vc,RingGeometry:kc,RingBufferGeometry:jc,PlaneGeometry:Vr,PlaneBufferGeometry:kr,LatheGeometry:Wc,LatheBufferGeometry:qc,ShapeGeometry:Xc,ShapeBufferGeometry:Yc,ExtrudeGeometry:Nc,ExtrudeBufferGeometry:Bc,EdgesGeometry:Jc,ConeGeometry:$c,ConeBufferGeometry:el,CylinderGeometry:Qc,CylinderBufferGeometry:Kc,CircleGeometry:tl,CircleBufferGeometry:nl,BoxGeometry:_r,BoxBufferGeometry:wr});function rl(e){Ai.call(this),this.type="ShadowMaterial",this.color=new _i(0),this.transparent=!0,this.setValues(e)}function al(e){Lr.call(this,e),this.type="RawShaderMaterial"}function ol(e){Ai.call(this),this.defines={STANDARD:""},this.type="MeshStandardMaterial",this.color=new _i(16777215),this.roughness=1,this.metalness=0,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.roughnessMap=null,this.metalnessMap=null,this.alphaMap=null,this.envMap=null,this.envMapIntensity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.vertexTangents=!1,this.setValues(e)}function sl(e){ol.call(this),this.defines={STANDARD:"",PHYSICAL:""},this.type="MeshPhysicalMaterial",this.reflectivity=.5,this.clearcoat=0,this.clearcoatRoughness=0,this.sheen=null,this.clearcoatNormalScale=new qt(1,1),this.clearcoatNormalMap=null,this.transparency=0,this.setValues(e)}function cl(e){Ai.call(this),this.type="MeshPhongMaterial",this.color=new _i(16777215),this.specular=new _i(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=G,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function ll(e){Ai.call(this),this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new _i(16777215),this.specular=new _i(1118481),this.shininess=30,this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function hl(e){Ai.call(this),this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function ul(e){Ai.call(this),this.type="MeshLambertMaterial",this.color=new _i(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=G,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function pl(e){Ai.call(this),this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new _i(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function dl(e){Ms.call(this),this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}rl.prototype=Object.create(Ai.prototype),rl.prototype.constructor=rl,rl.prototype.isShadowMaterial=!0,rl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this},al.prototype=Object.create(Lr.prototype),al.prototype.constructor=al,al.prototype.isRawShaderMaterial=!0,ol.prototype=Object.create(Ai.prototype),ol.prototype.constructor=ol,ol.prototype.isMeshStandardMaterial=!0,ol.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.defines={STANDARD:""},this.color.copy(e.color),this.roughness=e.roughness,this.metalness=e.metalness,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.roughnessMap=e.roughnessMap,this.metalnessMap=e.metalnessMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapIntensity=e.envMapIntensity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this.vertexTangents=e.vertexTangents,this},sl.prototype=Object.create(ol.prototype),sl.prototype.constructor=sl,sl.prototype.isMeshPhysicalMaterial=!0,sl.prototype.copy=function(e){return ol.prototype.copy.call(this,e),this.defines={STANDARD:"",PHYSICAL:""},this.reflectivity=e.reflectivity,this.clearcoat=e.clearcoat,this.clearcoatRoughness=e.clearcoatRoughness,e.sheen?this.sheen=(this.sheen||new _i).copy(e.sheen):this.sheen=null,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.transparency=e.transparency,this},cl.prototype=Object.create(Ai.prototype),cl.prototype.constructor=cl,cl.prototype.isMeshPhongMaterial=!0,cl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},ll.prototype=Object.create(Ai.prototype),ll.prototype.constructor=ll,ll.prototype.isMeshToonMaterial=!0,ll.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},hl.prototype=Object.create(Ai.prototype),hl.prototype.constructor=hl,hl.prototype.isMeshNormalMaterial=!0,hl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},ul.prototype=Object.create(Ai.prototype),ul.prototype.constructor=ul,ul.prototype.isMeshLambertMaterial=!0,ul.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},pl.prototype=Object.create(Ai.prototype),pl.prototype.constructor=pl,pl.prototype.isMeshMatcapMaterial=!0,pl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},dl.prototype=Object.create(Ms.prototype),dl.prototype.constructor=dl,dl.prototype.isLineDashedMaterial=!0,dl.prototype.copy=function(e){return Ms.prototype.copy.call(this,e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this};var fl=Object.freeze({__proto__:null,ShadowMaterial:rl,SpriteMaterial:Zo,RawShaderMaterial:al,ShaderMaterial:Lr,PointsMaterial:Is,MeshPhysicalMaterial:sl,MeshStandardMaterial:ol,MeshPhongMaterial:cl,MeshToonMaterial:ll,MeshNormalMaterial:hl,MeshLambertMaterial:ul,MeshDepthMaterial:Co,MeshDistanceMaterial:Oo,MeshBasicMaterial:Li,MeshMatcapMaterial:pl,LineDashedMaterial:dl,LineBasicMaterial:Ms,Material:Ai}),ml={arraySlice:function(e,t,n){return ml.isTypedArray(e)?new e.constructor(e.subarray(t,void 0!==n?n:e.length)):e.slice(t,n)},convertArray:function(e,t,n){return!e||!n&&e.constructor===t?e:"number"==typeof t.BYTES_PER_ELEMENT?new t(e):Array.prototype.slice.call(e)},isTypedArray:function(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)},getKeyframeOrder:function(e){for(var t=e.length,n=new Array(t),i=0;i!==t;++i)n[i]=i;return n.sort(function(t,n){return e[t]-e[n]}),n},sortedArray:function(e,t,n){for(var i=e.length,r=new e.constructor(i),a=0,o=0;o!==i;++a)for(var s=n[a]*t,c=0;c!==t;++c)r[o++]=e[s+c];return r},flattenJSON:function(e,t,n,i){for(var r=1,a=e[0];void 0!==a&&void 0===a[i];)a=e[r++];if(void 0!==a){var o=a[i];if(void 0!==o)if(Array.isArray(o))do{void 0!==(o=a[i])&&(t.push(a.time),n.push.apply(n,o)),a=e[r++]}while(void 0!==a);else if(void 0!==o.toArray)do{void 0!==(o=a[i])&&(t.push(a.time),o.toArray(n,n.length)),a=e[r++]}while(void 0!==a);else do{void 0!==(o=a[i])&&(t.push(a.time),n.push(o)),a=e[r++]}while(void 0!==a)}},subclip:function(e,t,n,i,r){r=r||30;var a=e.clone();a.name=t;for(var o=[],s=0;s=i)){h.push(c.times[p]);for(var f=0;fa.tracks[s].times[0]&&(m=a.tracks[s].times[0]);for(s=0;s=r)break e;var s=t[1];e=(r=t[--n-1]))break t}a=n,n=0}for(;n>>1;et;)--a;if(++a,0!==r||a!==i){r>=a&&(r=(a=Math.max(a,1))-1);var o=this.getValueSize();this.times=ml.arraySlice(n,r,a),this.values=ml.arraySlice(this.values,r*o,a*o)}return this},validate:function(){var e=!0,t=this.getValueSize();t-Math.floor(t)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);var n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);for(var a=null,o=0;o!==r;o++){var s=n[o];if("number"==typeof s&&isNaN(s)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,o,s),e=!1;break}if(null!==a&&a>s){console.error("THREE.KeyframeTrack: Out of order keys.",this,o,s,a),e=!1;break}a=s}if(void 0!==i&&ml.isTypedArray(i)){o=0;for(var c=i.length;o!==c;++o){var l=i[o];if(isNaN(l)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,o,l),e=!1;break}}}return e},optimize:function(){for(var e=ml.arraySlice(this.times),t=ml.arraySlice(this.values),n=this.getValueSize(),i=2302===this.getInterpolation(),r=1,a=e.length-1,o=1;o0){e[r]=e[a];for(f=a*n,m=r*n,p=0;p!==n;++p)t[m+p]=t[f+p];++r}return r!==e.length?(this.times=ml.arraySlice(e,0,r),this.values=ml.arraySlice(t,0,r*n)):(this.times=e,this.values=t),this},clone:function(){var e=ml.arraySlice(this.times,0),t=ml.arraySlice(this.values,0),n=new(0,this.constructor)(this.name,e,t);return n.createInterpolant=this.createInterpolant,n}}),_l.prototype=Object.assign(Object.create(bl.prototype),{constructor:_l,ValueTypeName:"bool",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),wl.prototype=Object.assign(Object.create(bl.prototype),{constructor:wl,ValueTypeName:"color"}),Ml.prototype=Object.assign(Object.create(bl.prototype),{constructor:Ml,ValueTypeName:"number"}),Sl.prototype=Object.assign(Object.create(gl.prototype),{constructor:Sl,interpolate_:function(e,t,n,i){for(var r=this.resultBuffer,a=this.sampleValues,o=this.valueSize,s=e*o,c=(n-t)/(i-t),l=s+o;s!==l;s+=4)en.slerpFlat(r,0,a,s-o,a,s,c);return r}}),Tl.prototype=Object.assign(Object.create(bl.prototype),{constructor:Tl,ValueTypeName:"quaternion",DefaultInterpolation:2301,InterpolantFactoryMethodLinear:function(e){return new Sl(this.times,this.values,this.getValueSize(),e)},InterpolantFactoryMethodSmooth:void 0}),El.prototype=Object.assign(Object.create(bl.prototype),{constructor:El,ValueTypeName:"string",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),Al.prototype=Object.assign(Object.create(bl.prototype),{constructor:Al,ValueTypeName:"vector"}),Object.assign(Ll,{parse:function(e){for(var t=[],n=e.tracks,i=1/(e.fps||1),r=0,a=n.length;r!==a;++r)t.push(Rl(n[r]).scale(i));return new Ll(e.name,e.duration,t)},toJSON:function(e){for(var t=[],n=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid},r=0,a=n.length;r!==a;++r)t.push(bl.toJSON(n[r]));return i},CreateFromMorphTargetSequence:function(e,t,n,i){for(var r=t.length,a=[],o=0;o1){var l=i[u=c[1]];l||(i[u]=l=[]),l.push(s)}}var h=[];for(var u in i)h.push(Ll.CreateFromMorphTargetSequence(u,i[u],t,n));return h},parseAnimation:function(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;for(var n=function(e,t,n,i,r){if(0!==n.length){var a=[],o=[];ml.flattenJSON(n,a,o,i),0!==a.length&&r.push(new e(t,a,o))}},i=[],r=e.name||"default",a=e.length||-1,o=e.fps||30,s=e.hierarchy||[],c=0;c0||0===e.search(/^data\:image\/jpeg/);r.format=i?Se:Te,r.needsUpdate=!0,void 0!==t&&t(r)},n,i),r}}),Object.assign(Vl.prototype,{getPoint:function(){return console.warn("THREE.Curve: .getPoint() not implemented."),null},getPointAt:function(e,t){var n=this.getUtoTmapping(e);return this.getPoint(n,t)},getPoints:function(e){void 0===e&&(e=5);for(var t=[],n=0;n<=e;n++)t.push(this.getPoint(n/e));return t},getSpacedPoints:function(e){void 0===e&&(e=5);for(var t=[],n=0;n<=e;n++)t.push(this.getPointAt(n/e));return t},getLength:function(){var e=this.getLengths();return e[e.length-1]},getLengths:function(e){if(void 0===e&&(e=this.arcLengthDivisions),this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var t,n,i=[],r=this.getPoint(0),a=0;for(i.push(0),n=1;n<=e;n++)a+=(t=this.getPoint(n/e)).distanceTo(r),i.push(a),r=t;return this.cacheArcLengths=i,i},updateArcLengths:function(){this.needsUpdate=!0,this.getLengths()},getUtoTmapping:function(e,t){var n,i=this.getLengths(),r=0,a=i.length;n=t||e*i[a-1];for(var o,s=0,c=a-1;s<=c;)if((o=i[r=Math.floor(s+(c-s)/2)]-n)<0)s=r+1;else{if(!(o>0)){c=r;break}c=r-1}if(i[r=c]===n)return r/(a-1);var l=i[r];return(r+(n-l)/(i[r+1]-l))/(a-1)},getTangent:function(e){var t=e-1e-4,n=e+1e-4;t<0&&(t=0),n>1&&(n=1);var i=this.getPoint(t);return this.getPoint(n).clone().sub(i).normalize()},getTangentAt:function(e){var t=this.getUtoTmapping(e);return this.getTangent(t)},computeFrenetFrames:function(e,t){var n,i,r,a=new rn,o=[],s=[],c=[],l=new rn,h=new pn;for(n=0;n<=e;n++)i=n/e,o[n]=this.getTangentAt(i),o[n].normalize();s[0]=new rn,c[0]=new rn;var u=Number.MAX_VALUE,p=Math.abs(o[0].x),d=Math.abs(o[0].y),f=Math.abs(o[0].z);for(p<=u&&(u=p,a.set(1,0,0)),d<=u&&(u=d,a.set(0,1,0)),f<=u&&a.set(0,0,1),l.crossVectors(o[0],a).normalize(),s[0].crossVectors(o[0],l),c[0].crossVectors(o[0],s[0]),n=1;n<=e;n++)s[n]=s[n-1].clone(),c[n]=c[n-1].clone(),l.crossVectors(o[n-1],o[n]),l.length()>Number.EPSILON&&(l.normalize(),r=Math.acos(Wt.clamp(o[n-1].dot(o[n]),-1,1)),s[n].applyMatrix4(h.makeRotationAxis(l,r))),c[n].crossVectors(o[n],s[n]);if(!0===t)for(r=Math.acos(Wt.clamp(s[0].dot(s[e]),-1,1)),r/=e,o[0].dot(l.crossVectors(s[0],s[e]))>0&&(r=-r),n=1;n<=e;n++)s[n].applyMatrix4(h.makeRotationAxis(o[n],r*n)),c[n].crossVectors(o[n],s[n]);return{tangents:o,normals:s,binormals:c}},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.arcLengthDivisions=e.arcLengthDivisions,this},toJSON:function(){var e={metadata:{version:4.5,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e},fromJSON:function(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}),kl.prototype=Object.create(Vl.prototype),kl.prototype.constructor=kl,kl.prototype.isEllipseCurve=!0,kl.prototype.getPoint=function(e,t){for(var n=t||new qt,i=2*Math.PI,r=this.aEndAngle-this.aStartAngle,a=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/c)+1)*c:0===u&&h===c-1&&(h=c-2,u=1),this.closed||h>0?n=s[(h-1)%c]:(ql.subVectors(s[0],s[1]).add(s[0]),n=ql),i=s[h%c],r=s[(h+1)%c],this.closed||h+2i.length-2?i.length-1:a+1],h=i[a>i.length-3?i.length-1:a+2];return n.set(Ql(o,s.x,c.x,l.x,h.x),Ql(o,s.y,c.y,l.y,h.y)),n},oh.prototype.copy=function(e){Vl.prototype.copy.call(this,e),this.points=[];for(var t=0,n=e.points.length;t=t){var r=n[i]-t,a=this.curves[i],o=a.getLength(),s=0===o?0:1-r/o;return a.getPointAt(s)}i++}return null},getLength:function(){var e=this.getCurveLengths();return e[e.length-1]},updateArcLengths:function(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var e=[],t=0,n=0,i=this.curves.length;n1&&!n[n.length-1].equals(n[0])&&n.push(n[0]),n},copy:function(e){Vl.prototype.copy.call(this,e),this.curves=[];for(var t=0,n=e.curves.length;t0){var l=c.getPoint(0);l.equals(this.currentPoint)||this.lineTo(l.x,l.y)}this.curves.push(c);var h=c.getPoint(1);return this.currentPoint.copy(h),this},copy:function(e){return ch.prototype.copy.call(this,e),this.currentPoint.copy(e.currentPoint),this},toJSON:function(){var e=ch.prototype.toJSON.call(this);return e.currentPoint=this.currentPoint.toArray(),e},fromJSON:function(e){return ch.prototype.fromJSON.call(this,e),this.currentPoint.fromArray(e.currentPoint),this}}),hh.prototype=Object.assign(Object.create(lh.prototype),{constructor:hh,getPointsHoles:function(e){for(var t=[],n=0,i=this.holes.length;n0:i.vertexColors=e.vertexColors),void 0!==e.uniforms)for(var r in e.uniforms){var a=e.uniforms[r];switch(i.uniforms[r]={},a.type){case"t":i.uniforms[r].value=n(a.value);break;case"c":i.uniforms[r].value=(new _i).setHex(a.value);break;case"v2":i.uniforms[r].value=(new qt).fromArray(a.value);break;case"v3":i.uniforms[r].value=(new rn).fromArray(a.value);break;case"v4":i.uniforms[r].value=(new Qt).fromArray(a.value);break;case"m3":i.uniforms[r].value=(new Xt).fromArray(a.value);case"m4":i.uniforms[r].value=(new pn).fromArray(a.value);break;default:i.uniforms[r].value=a.value}}if(void 0!==e.defines&&(i.defines=e.defines),void 0!==e.vertexShader&&(i.vertexShader=e.vertexShader),void 0!==e.fragmentShader&&(i.fragmentShader=e.fragmentShader),void 0!==e.extensions)for(var o in e.extensions)i.extensions[o]=e.extensions[o];if(void 0!==e.shading&&(i.flatShading=1===e.shading),void 0!==e.size&&(i.size=e.size),void 0!==e.sizeAttenuation&&(i.sizeAttenuation=e.sizeAttenuation),void 0!==e.map&&(i.map=n(e.map)),void 0!==e.matcap&&(i.matcap=n(e.matcap)),void 0!==e.alphaMap&&(i.alphaMap=n(e.alphaMap)),void 0!==e.bumpMap&&(i.bumpMap=n(e.bumpMap)),void 0!==e.bumpScale&&(i.bumpScale=e.bumpScale),void 0!==e.normalMap&&(i.normalMap=n(e.normalMap)),void 0!==e.normalMapType&&(i.normalMapType=e.normalMapType),void 0!==e.normalScale){var s=e.normalScale;!1===Array.isArray(s)&&(s=[s,s]),i.normalScale=(new qt).fromArray(s)}return void 0!==e.displacementMap&&(i.displacementMap=n(e.displacementMap)),void 0!==e.displacementScale&&(i.displacementScale=e.displacementScale),void 0!==e.displacementBias&&(i.displacementBias=e.displacementBias),void 0!==e.roughnessMap&&(i.roughnessMap=n(e.roughnessMap)),void 0!==e.metalnessMap&&(i.metalnessMap=n(e.metalnessMap)),void 0!==e.emissiveMap&&(i.emissiveMap=n(e.emissiveMap)),void 0!==e.emissiveIntensity&&(i.emissiveIntensity=e.emissiveIntensity),void 0!==e.specularMap&&(i.specularMap=n(e.specularMap)),void 0!==e.envMap&&(i.envMap=n(e.envMap)),void 0!==e.envMapIntensity&&(i.envMapIntensity=e.envMapIntensity),void 0!==e.reflectivity&&(i.reflectivity=e.reflectivity),void 0!==e.refractionRatio&&(i.refractionRatio=e.refractionRatio),void 0!==e.lightMap&&(i.lightMap=n(e.lightMap)),void 0!==e.lightMapIntensity&&(i.lightMapIntensity=e.lightMapIntensity),void 0!==e.aoMap&&(i.aoMap=n(e.aoMap)),void 0!==e.aoMapIntensity&&(i.aoMapIntensity=e.aoMapIntensity),void 0!==e.gradientMap&&(i.gradientMap=n(e.gradientMap)),void 0!==e.clearcoatNormalMap&&(i.clearcoatNormalMap=n(e.clearcoatNormalMap)),void 0!==e.clearcoatNormalScale&&(i.clearcoatNormalScale=(new qt).fromArray(e.clearcoatNormalScale)),i},setTextures:function(e){return this.textures=e,this}});var Sh={decodeText:function(e){if("undefined"!=typeof TextDecoder)return(new TextDecoder).decode(e);for(var t="",n=0,i=e.length;n0){var a=new Ul(new Cl(t));a.setCrossOrigin(this.crossOrigin);for(var o=0,s=e.length;o0?new ds(o,s):new dr(o,s);break;case"InstancedMesh":o=r(e.geometry),s=a(e.material);var c=e.count,l=e.instanceMatrix;(i=new ws(o,s,c)).instanceMatrix=new Pi(new Float32Array(l.array),16);break;case"LOD":i=new ps;break;case"Line":i=new Rs(r(e.geometry),a(e.material),e.mode);break;case"LineLoop":i=new Ds(r(e.geometry),a(e.material));break;case"LineSegments":i=new Os(r(e.geometry),a(e.material));break;case"PointCloud":case"Points":i=new Us(r(e.geometry),a(e.material));break;case"Sprite":i=new cs(a(e.material));break;case"Group":i=new Go;break;default:i=new Pn}if(i.uuid=e.uuid,void 0!==e.name&&(i.name=e.name),void 0!==e.matrix?(i.matrix.fromArray(e.matrix),void 0!==e.matrixAutoUpdate&&(i.matrixAutoUpdate=e.matrixAutoUpdate),i.matrixAutoUpdate&&i.matrix.decompose(i.position,i.quaternion,i.scale)):(void 0!==e.position&&i.position.fromArray(e.position),void 0!==e.rotation&&i.rotation.fromArray(e.rotation),void 0!==e.quaternion&&i.quaternion.fromArray(e.quaternion),void 0!==e.scale&&i.scale.fromArray(e.scale)),void 0!==e.castShadow&&(i.castShadow=e.castShadow),void 0!==e.receiveShadow&&(i.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.bias&&(i.shadow.bias=e.shadow.bias),void 0!==e.shadow.radius&&(i.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&i.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(i.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(i.visible=e.visible),void 0!==e.frustumCulled&&(i.frustumCulled=e.frustumCulled),void 0!==e.renderOrder&&(i.renderOrder=e.renderOrder),void 0!==e.userData&&(i.userData=e.userData),void 0!==e.layers&&(i.layers.mask=e.layers),void 0!==e.children)for(var h=e.children,u=0;uNumber.EPSILON){if(l<0&&(o=t[a],c=-c,s=t[r],l=-l),e.ys.y)continue;if(e.y===o.y){if(e.x===o.x)return!0}else{var h=l*(e.x-o.x)-c*(e.y-o.y);if(0===h)return!0;if(h<0)continue;i=!i}}else{if(e.y!==o.y)continue;if(s.x<=e.x&&e.x<=o.x||o.x<=e.x&&e.x<=s.x)return!0}}return i}var r=Oc.isClockWise,a=this.subPaths;if(0===a.length)return[];if(!0===t)return n(a);var o,s,c,l=[];if(1===a.length)return s=a[0],(c=new hh).curves=s.curves,l.push(c),l;var h=!r(a[0].getPoints());h=e?!h:h;var u,p,d=[],f=[],m=[],g=0;f[g]=void 0,m[g]=[];for(var v=0,y=a.length;v1){for(var x=!1,b=[],_=0,w=f.length;_0&&(x||(m=d))}v=0;for(var L=f.length;v0){this.source.connect(this.filters[0]);for(var e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(var e=1,t=this.filters.length;e=.5)for(var a=0;a!==r;++a)e[t+a]=e[n+a]},_slerp:function(e,t,n,i){en.slerpFlat(e,t,e,t,e,n,i)},_lerp:function(e,t,n,i,r){for(var a=1-i,o=0;o!==r;++o){var s=t+o;e[s]=e[s]*a+e[n+o]*i}}});var cu=new RegExp("[\\[\\]\\.:\\/]","g"),lu="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",hu=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]"),uu=/(WCOD+)?/.source.replace("WCOD",lu),pu=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),du=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"),fu=new RegExp("^"+hu+uu+pu+du+"$"),mu=["material","materials","bones"];function gu(e,t,n){var i=n||vu.parseTrackName(t);this._targetGroup=e,this._bindings=e.subscribe_(t,i)}function vu(e,t,n){this.path=t,this.parsedPath=n||vu.parseTrackName(t),this.node=vu.findNode(e,this.parsedPath.nodeName)||e,this.rootNode=e}function yu(){this.uuid=Wt.generateUUID(),this._objects=Array.prototype.slice.call(arguments),this.nCachedObjects_=0;var e={};this._indicesByUUID=e;for(var t=0,n=arguments.length;t!==n;++t)e[arguments[t].uuid]=t;this._paths=[],this._parsedPaths=[],this._bindings=[],this._bindingsIndicesByPath={};var i=this;this.stats={objects:{get total(){return i._objects.length},get inUse(){return this.total-i.nCachedObjects_}},get bindingsPerObject(){return i._bindings.length}}}function xu(e,t,n){this._mixer=e,this._clip=t,this._localRoot=n||null;for(var i=t.tracks,r=i.length,a=new Array(r),o={endingStart:St,endingEnd:St},s=0;s!==r;++s){var c=i[s].createInterpolant(null);a[s]=c,c.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(r),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=Mt,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}function bu(e){this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}function _u(e){"string"==typeof e&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),e=arguments[1]),this.value=e}function wu(e,t,n){Wo.call(this,e,t),this.meshPerAttribute=n||1}function Mu(e,t,n,i){this.ray=new ni(e,t),this.near=n||0,this.far=i||1/0,this.camera=null,this.layers=new gn,this.params={Mesh:{},Line:{threshold:1},LOD:{},Points:{threshold:1},Sprite:{}},Object.defineProperties(this.params,{PointCloud:{get:function(){return console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points."),this.Points}}})}function Su(e,t){return e.distance-t.distance}function Tu(e,t,n,i){if(e.layers.test(t.layers)&&e.raycast(t,n),!0===i)for(var r=e.children,a=0,o=r.length;a=t){var h=t++,u=e[h];n[u.uuid]=l,e[l]=u,n[c]=h,e[h]=s;for(var p=0,d=r;p!==d;++p){var f=i[p],m=f[h],g=f[l];f[l]=m,f[h]=g}}}this.nCachedObjects_=t},uncache:function(){for(var e=this._objects,t=e.length,n=this.nCachedObjects_,i=this._indicesByUUID,r=this._bindings,a=r.length,o=0,s=arguments.length;o!==s;++o){var c=arguments[o].uuid,l=i[c];if(void 0!==l)if(delete i[c],l0)for(var c=this._interpolants,l=this._propertyBindings,h=0,u=c.length;h!==u;++h)c[h].evaluate(o),l[h].accumulate(i,s)}else this._updateWeight(e)},_updateWeight:function(e){var t=0;if(this.enabled){t=this.weight;var n=this._weightInterpolant;if(null!==n){var i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=t,t},_updateTimeScale:function(e){var t=0;if(!this.paused){t=this.timeScale;var n=this._timeScaleInterpolant;if(null!==n)t*=n.evaluate(e)[0],e>n.parameterPositions[1]&&(this.stopWarping(),0===t?this.paused=!0:this.timeScale=t)}return this._effectiveTimeScale=t,t},_updateTime:function(e){var t=this.time+e,n=this._clip.duration,i=this.loop,r=this._loopCount,a=2202===i;if(0===e)return-1===r?t:a&&1==(1&r)?n-t:t;if(2200===i){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(t>=n)t=n;else{if(!(t<0)){this.time=t;break e}t=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=t,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(-1===r&&(e>=0?(r=0,this._setEndings(!0,0===this.repetitions,a)):this._setEndings(0===this.repetitions,!0,a)),t>=n||t<0){var o=Math.floor(t/n);t-=n*o,r+=Math.abs(o);var s=this.repetitions-r;if(s<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,t=e>0?n:0,this.time=t,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(1===s){var c=e<0;this._setEndings(c,!c,a)}else this._setEndings(!1,!1,a);this._loopCount=r,this.time=t,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:o})}}else this.time=t;if(a&&1==(1&r))return n-t}return t},_setEndings:function(e,t,n){var i=this._interpolantSettings;n?(i.endingStart=2401,i.endingEnd=2401):(i.endingStart=e?this.zeroSlopeAtStart?2401:St:2402,i.endingEnd=t?this.zeroSlopeAtEnd?2401:St:2402)},_scheduleFading:function(e,t,n){var i=this._mixer,r=i.time,a=this._weightInterpolant;null===a&&(a=i._lendControlInterpolant(),this._weightInterpolant=a);var o=a.parameterPositions,s=a.sampleValues;return o[0]=r,s[0]=t,o[1]=r+e,s[1]=n,this}}),bu.prototype=Object.assign(Object.create(Ht.prototype),{constructor:bu,_bindAction:function(e,t){var n=e._localRoot||this._root,i=e._clip.tracks,r=i.length,a=e._propertyBindings,o=e._interpolants,s=n.uuid,c=this._bindingsByRootAndName,l=c[s];void 0===l&&(l={},c[s]=l);for(var h=0;h!==r;++h){var u=i[h],p=u.name,d=l[p];if(void 0!==d)a[h]=d;else{if(void 0!==(d=a[h])){null===d._cacheIndex&&(++d.referenceCount,this._addInactiveBinding(d,s,p));continue}var f=t&&t._propertyBindings[h].binding.parsedPath;++(d=new su(vu.create(n,p,f),u.ValueTypeName,u.getValueSize())).referenceCount,this._addInactiveBinding(d,s,p),a[h]=d}o[h].resultBuffer=d.buffer}},_activateAction:function(e){if(!this._isActiveAction(e)){if(null===e._cacheIndex){var t=(e._localRoot||this._root).uuid,n=e._clip.uuid,i=this._actionsByClip[n];this._bindAction(e,i&&i.knownActions[0]),this._addInactiveAction(e,n,t)}for(var r=e._propertyBindings,a=0,o=r.length;a!==o;++a){var s=r[a];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(e)}},_deactivateAction:function(e){if(this._isActiveAction(e)){for(var t=e._propertyBindings,n=0,i=t.length;n!==i;++n){var r=t[n];0==--r.useCount&&(r.restoreOriginalState(),this._takeBackBinding(r))}this._takeBackAction(e)}},_initMemoryManager:function(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;var e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}},_isActiveAction:function(e){var t=e._cacheIndex;return null!==t&&tthis.max.x||e.ythis.max.y)},containsBox:function(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y},getParameter:function(e,t){return void 0===t&&(console.warn("THREE.Box2: .getParameter() target is now required"),t=new qt),t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(e){return!(e.max.xthis.max.x||e.max.ythis.max.y)},clampPoint:function(e,t){return void 0===t&&(console.warn("THREE.Box2: .clampPoint() target is now required"),t=new qt),t.copy(e).clamp(this.min,this.max)},distanceToPoint:function(e){return Lu.copy(e).clamp(this.min,this.max).sub(e).length()},intersect:function(e){return this.min.max(e.min),this.max.min(e.max),this},union:function(e){return this.min.min(e.min),this.max.max(e.max),this},translate:function(e){return this.min.add(e),this.max.add(e),this},equals:function(e){return e.min.equals(this.min)&&e.max.equals(this.max)}});var Pu=new rn,Cu=new rn;function Ou(e,t){this.start=void 0!==e?e:new rn,this.end=void 0!==t?t:new rn}function Du(e){Pn.call(this),this.material=e,this.render=function(){}}Object.assign(Ou.prototype,{set:function(e,t){return this.start.copy(e),this.end.copy(t),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.start.copy(e.start),this.end.copy(e.end),this},getCenter:function(e){return void 0===e&&(console.warn("THREE.Line3: .getCenter() target is now required"),e=new rn),e.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(e){return void 0===e&&(console.warn("THREE.Line3: .delta() target is now required"),e=new rn),e.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(e,t){return void 0===t&&(console.warn("THREE.Line3: .at() target is now required"),t=new rn),this.delta(t).multiplyScalar(e).add(this.start)},closestPointToPointParameter:function(e,t){Pu.subVectors(e,this.start),Cu.subVectors(this.end,this.start);var n=Cu.dot(Cu),i=Cu.dot(Pu)/n;return t&&(i=Wt.clamp(i,0,1)),i},closestPointToPoint:function(e,t,n){var i=this.closestPointToPointParameter(e,t);return void 0===n&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),n=new rn),this.delta(n).multiplyScalar(i).add(this.start)},applyMatrix4:function(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this},equals:function(e){return e.start.equals(this.start)&&e.end.equals(this.end)}}),Du.prototype=Object.create(Pn.prototype),Du.prototype.constructor=Du,Du.prototype.isImmediateRenderObject=!0;var Iu=new rn;function Nu(e,t){Pn.call(this),this.light=e,this.light.updateMatrixWorld(),this.matrix=e.matrixWorld,this.matrixAutoUpdate=!1,this.color=t;for(var n=new Zi,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1],r=0,a=1;r<32;r++,a++){var o=r/32*Math.PI*2,s=a/32*Math.PI*2;i.push(Math.cos(o),Math.sin(o),1,Math.cos(s),Math.sin(s),1)}n.setAttribute("position",new Fi(i,3));var c=new Ms({fog:!1});this.cone=new Os(n,c),this.add(this.cone),this.update()}Nu.prototype=Object.create(Pn.prototype),Nu.prototype.constructor=Nu,Nu.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},Nu.prototype.update=function(){this.light.updateMatrixWorld();var e=this.light.distance?this.light.distance:1e3,t=e*Math.tan(this.light.angle);this.cone.scale.set(t,t,e),Iu.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(Iu),void 0!==this.color?this.cone.material.color.set(this.color):this.cone.material.color.copy(this.light.color)};var Bu=new rn,zu=new pn,Fu=new pn;function Uu(e){for(var t=function e(t){var n=[];t&&t.isBone&&n.push(t);for(var i=0;i.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{sp.set(e.z,0,-e.x).normalize();var t=Math.acos(e.y);this.quaternion.setFromAxisAngle(sp,t)}},cp.prototype.setLength=function(e,t,n){void 0===t&&(t=.2*e),void 0===n&&(n=.2*t),this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(n,t,n),this.cone.position.y=e,this.cone.updateMatrix()},cp.prototype.setColor=function(e){this.line.material.color.set(e),this.cone.material.color.set(e)},cp.prototype.copy=function(e){return Pn.prototype.copy.call(this,e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this},cp.prototype.clone=function(){return(new this.constructor).copy(this)},lp.prototype=Object.create(Os.prototype),lp.prototype.constructor=lp;var hp=4,up=8,pp=Math.pow(2,up),dp=[.125,.215,.35,.446,.526,.582],fp=up-hp+1+dp.length,mp=20,gp={};gp[Tt]=0,gp[Et]=1,gp[Lt]=2,gp[Pt]=3,gp[Ct]=4,gp[Ot]=5,gp[At]=6;var vp,yp,xp,bp,_p=new yh,wp=(vp=mp,yp=new Float32Array(vp),xp=new rn(0,1,0),(bp=new al({defines:{n:vp},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:yp},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:xp},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform sampler2D envMap;\nuniform int samples;\nuniform float weights[n];\nuniform bool latitudinal;\nuniform float dTheta;\nuniform float mipInt;\nuniform vec3 poleAxis;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\n#define ENVMAP_TYPE_CUBE_UV\n#include \n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tfor (int i = 0; i < n; i++) {\n\t\tif (i >= samples)\n\t\t\tbreak;\n\t\tfor (int dir = -1; dir < 2; dir += 2) {\n\t\t\tif (i == 0 && dir == 1)\n\t\t\t\tcontinue;\n\t\t\tvec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection);\n\t\t\tif (all(equal(axis, vec3(0.0))))\n\t\t\t\taxis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection);\n\t\t\taxis = normalize(axis);\n\t\t\tfloat theta = dTheta * float(dir * i);\n\t\t\tfloat cosTheta = cos(theta);\n\t\t\t// Rodrigues' axis-angle rotation\n\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross(axis, vOutputDirection) * sin(theta)\n\t\t\t\t\t+ axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);\n\t\t\tgl_FragColor.rgb +=\n\t\t\t\t\tweights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);\n\t\t}\n\t}\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1})).type="SphericalGaussianBlur",bp),Mp=null,Sp=null,Tp=function(){for(var e=[],t=[],n=[],i=up,r=0;rup-hp?o=dp[r-up+hp-1]:0==r&&(o=0),n.push(o);for(var s=1/(a-1),c=-s/2,l=1+s/2,h=[c,c,l,c,l,l,c,c,l,l,c,l],u=new Float32Array(108),p=new Float32Array(72),d=new Float32Array(36),f=0;f<6;f++){var m=f%3*2/3-1,g=f>2?0:-1,v=[m,g,0,m+2/3,g,0,m+2/3,g+1,0,m,g,0,m+2/3,g+1,0,m,g+1,0];u.set(v,18*f),p.set(h,12*f);var y=[f,f,f,f,f,f];d.set(y,6*f)}var x=new Zi;x.setAttribute("position",new Pi(u,3)),x.setAttribute("uv",new Pi(p,2)),x.setAttribute("faceIndex",new Pi(d,1)),e.push(x),i>hp&&i--}return{_lodPlanes:e,_sizeLods:t,_sigmas:n}}(),Ep=Tp._lodPlanes,Ap=Tp._sizeLods,Lp=Tp._sigmas,Rp=null,Pp=null,Cp=null,Op=(1+Math.sqrt(5))/2,Dp=1/Op,Ip=[new rn(1,1,1),new rn(-1,1,1),new rn(1,1,-1),new rn(-1,1,-1),new rn(0,Op,Dp),new rn(0,Op,-Dp),new rn(Dp,0,Op),new rn(-Dp,0,Op),new rn(Op,Dp,0),new rn(-Op,Dp,0)];function Np(e){Pp=e,Fp(wp)}function Bp(e){var t={magFilter:ae,minFilter:ae,generateMipmaps:!1,type:e?e.type:ue,format:e?e.format:Le,encoding:e?e.encoding:Lt,depthBuffer:!1,stencilBuffer:!1},n=Up(t);return n.depthBuffer=!e,Rp=Up(t),n}function zp(e){Rp.dispose(),Pp.setRenderTarget(Cp),e.scissorTest=!1,e.setSize(e.width,e.height)}function Fp(e){var t=new Cn;t.add(new dr(Ep[0],e)),Pp.compile(t,_p)}function Up(e){var t=new Kt(3*pp,3*pp,e);return t.texture.mapping=ee,t.texture.name="PMREM.cubeUv",t.scissorTest=!0,t}function Gp(e,t,n,i,r){e.viewport.set(t,n,i,r),e.scissor.set(t,n,i,r)}function Hp(e){var t=Pp.autoClear;Pp.autoClear=!1;for(var n=1;nmp&&console.warn("sigmaRadians, "+r+", is too large and will clip, as it requested "+p+" samples when the maximum is set to "+mp);for(var d=[],f=0,m=0;mup-hp?i-up+hp:0),3*y,2*y),Pp.setRenderTarget(t),Pp.render(s,_p)}function jp(){var e=new al({uniforms:{envMap:{value:null},texelSize:{value:new qt(1,1)},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform sampler2D envMap;\nuniform vec2 texelSize;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tvec3 outputDirection = normalize(vOutputDirection);\n\tvec2 uv;\n\tuv.y = asin(clamp(outputDirection.y, -1.0, 1.0)) * RECIPROCAL_PI + 0.5;\n\tuv.x = atan(outputDirection.z, outputDirection.x) * RECIPROCAL_PI2 + 0.5;\n\tvec2 f = fract(uv / texelSize - 0.5);\n\tuv -= f * texelSize;\n\tvec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.x += texelSize.x;\n\tvec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.y += texelSize.y;\n\tvec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.x -= texelSize.x;\n\tvec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tvec3 tm = mix(tl, tr, f.x);\n\tvec3 bm = mix(bl, br, f.x);\n\tgl_FragColor.rgb = mix(tm, bm, f.y);\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1});return e.type="EquirectangularToCubeUV",e}function Wp(){var e=new al({uniforms:{envMap:{value:null},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform samplerCube envMap;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tgl_FragColor.rgb = envMapTexelToLinear(textureCube(envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ))).rgb;\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1});return e.type="CubemapToCubeUV",e}Np.prototype={constructor:Np,fromScene:function(e,t,n,i){void 0===t&&(t=0),void 0===n&&(n=.1),void 0===i&&(i=100),Cp=Pp.getRenderTarget();var r=Bp();return function(e,t,n,i){var r=new Pr(90,1,t,n),a=[1,1,1,1,-1,1],o=[1,1,-1,-1,-1,1],s=Pp.outputEncoding,c=Pp.toneMapping,l=Pp.toneMappingExposure,h=Pp.getClearColor(),u=Pp.getClearAlpha();Pp.toneMapping=j,Pp.toneMappingExposure=1,Pp.outputEncoding=Tt,e.scale.z*=-1;var p=e.background;if(p&&p.isColor){p.convertSRGBToLinear();var d=Math.max(p.r,p.g,p.b),f=Math.min(Math.max(Math.ceil(Math.log2(d)),-128),127);p=p.multiplyScalar(Math.pow(2,-f));var m=(f+128)/255;Pp.setClearColor(p,m),e.background=null}for(var g=0;g<6;g++){var v=g%3;0==v?(r.up.set(0,a[g],0),r.lookAt(o[g],0,0)):1==v?(r.up.set(0,0,a[g]),r.lookAt(0,o[g],0)):(r.up.set(0,a[g],0),r.lookAt(0,0,o[g])),Gp(i,v*pp,g>2?pp:0,pp,pp),Pp.setRenderTarget(i),Pp.render(e,r)}Pp.toneMapping=c,Pp.toneMappingExposure=l,Pp.outputEncoding=s,Pp.setClearColor(h,u),e.scale.z*=-1}(e,n,i,r),t>0&&Vp(r,0,0,t),Hp(r),zp(r),r},fromEquirectangular:function(e){return e.magFilter=ae,e.minFilter=ae,e.generateMipmaps=!1,this.fromCubemap(e)},fromCubemap:function(e){Cp=Pp.getRenderTarget();var t=Bp(e);return function(e,t){var n=new Cn;e.isCubeTexture?null==Sp&&(Sp=Wp()):null==Mp&&(Mp=jp());var i=e.isCubeTexture?Sp:Mp;n.add(new dr(Ep[0],i));var r=i.uniforms;r.envMap.value=e,e.isCubeTexture||r.texelSize.value.set(1/e.image.width,1/e.image.height);r.inputEncoding.value=gp[e.encoding],r.outputEncoding.value=gp[e.encoding],Gp(t,0,0,3*pp,2*pp),Pp.setRenderTarget(t),Pp.render(n,_p)}(e,t),Hp(t),zp(t),t},compileCubemapShader:function(){null==Sp&&Fp(Sp=Wp())},compileEquirectangularShader:function(){null==Mp&&Fp(Mp=jp())},dispose:function(){wp.dispose(),null!=Sp&&Sp.dispose(),null!=Mp&&Mp.dispose();for(var e=0;e0?1:+e}),"name"in Function.prototype==!1&&Object.defineProperty(Function.prototype,"name",{get:function(){return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]}}),void 0===Object.assign&&(Object.assign=function(e){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1;n>8&255]+Vt[e>>16&255]+Vt[e>>24&255]+"-"+Vt[255&t]+Vt[t>>8&255]+"-"+Vt[t>>16&15|64]+Vt[t>>24&255]+"-"+Vt[63&n|128]+Vt[n>>8&255]+"-"+Vt[n>>16&255]+Vt[n>>24&255]+Vt[255&i]+Vt[i>>8&255]+Vt[i>>16&255]+Vt[i>>24&255]).toUpperCase()},clamp:function(e,t,n){return Math.max(t,Math.min(n,e))},euclideanModulo:function(e,t){return(e%t+t)%t},mapLinear:function(e,t,n,i,r){return i+(e-t)*(r-i)/(n-t)},lerp:function(e,t,n){return(1-n)*e+n*t},smoothstep:function(e,t,n){return e<=t?0:e>=n?1:(e=(e-t)/(n-t))*e*(3-2*e)},smootherstep:function(e,t,n){return e<=t?0:e>=n?1:(e=(e-t)/(n-t))*e*e*(e*(6*e-15)+10)},randInt:function(e,t){return e+Math.floor(Math.random()*(t-e+1))},randFloat:function(e,t){return e+Math.random()*(t-e)},randFloatSpread:function(e){return e*(.5-Math.random())},degToRad:function(e){return e*Wt.DEG2RAD},radToDeg:function(e){return e*Wt.RAD2DEG},isPowerOfTwo:function(e){return 0==(e&e-1)&&0!==e},ceilPowerOfTwo:function(e){return Math.pow(2,Math.ceil(Math.log(e)/Math.LN2))},floorPowerOfTwo:function(e){return Math.pow(2,Math.floor(Math.log(e)/Math.LN2))},setQuaternionFromProperEuler:function(e,t,n,i,r){var a=Math.cos,o=Math.sin,s=a(n/2),c=o(n/2),l=a((t+i)/2),h=o((t+i)/2),u=a((t-i)/2),p=o((t-i)/2),d=a((i-t)/2),f=o((i-t)/2);"XYX"===r?e.set(s*h,c*u,c*p,s*l):"YZY"===r?e.set(c*p,s*h,c*u,s*l):"ZXZ"===r?e.set(c*u,c*p,s*h,s*l):"XZX"===r?e.set(s*h,c*f,c*d,s*l):"YXY"===r?e.set(c*d,s*h,c*f,s*l):"ZYZ"===r?e.set(c*f,c*d,s*h,s*l):console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order.")}};function qt(e,t){this.x=e||0,this.y=t||0}function Xt(){this.elements=[1,0,0,0,1,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}Object.defineProperties(qt.prototype,{width:{get:function(){return this.x},set:function(e){this.x=e}},height:{get:function(){return this.y},set:function(e){this.y=e}}}),Object.assign(qt.prototype,{isVector2:!0,set:function(e,t){return this.x=e,this.y=t,this},setScalar:function(e){return this.x=e,this.y=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(e){return this.x=e.x,this.y=e.y,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this)},addScalar:function(e){return this.x+=e,this.y+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this)},subScalar:function(e){return this.x-=e,this.y-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this},multiply:function(e){return this.x*=e.x,this.y*=e.y,this},multiplyScalar:function(e){return this.x*=e,this.y*=e,this},divide:function(e){return this.x/=e.x,this.y/=e.y,this},divideScalar:function(e){return this.multiplyScalar(1/e)},applyMatrix3:function(e){var t=this.x,n=this.y,i=e.elements;return this.x=i[0]*t+i[3]*n+i[6],this.y=i[1]*t+i[4]*n+i[7],this},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this},negate:function(){return this.x=-this.x,this.y=-this.y,this},dot:function(e){return this.x*e.x+this.y*e.y},cross:function(e){return this.x*e.y-this.y*e.x},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){return Math.atan2(-this.y,-this.x)+Math.PI},distanceTo:function(e){return Math.sqrt(this.distanceToSquared(e))},distanceToSquared:function(e){var t=this.x-e.x,n=this.y-e.y;return t*t+n*n},manhattanDistanceTo:function(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},equals:function(e){return e.x===this.x&&e.y===this.y},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this},rotateAround:function(e,t){var n=Math.cos(t),i=Math.sin(t),r=this.x-e.x,a=this.y-e.y;return this.x=r*n-a*i+e.x,this.y=r*i+a*n+e.y,this}}),Object.assign(Xt.prototype,{isMatrix3:!0,set:function(e,t,n,i,r,a,o,s,c){var l=this.elements;return l[0]=e,l[1]=i,l[2]=o,l[3]=t,l[4]=r,l[5]=s,l[6]=n,l[7]=a,l[8]=c,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(e){var t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this},extractBasis:function(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this},setFromMatrix4:function(e){var t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this},multiply:function(e){return this.multiplyMatrices(this,e)},premultiply:function(e){return this.multiplyMatrices(e,this)},multiplyMatrices:function(e,t){var n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[3],s=n[6],c=n[1],l=n[4],h=n[7],u=n[2],p=n[5],d=n[8],f=i[0],m=i[3],g=i[6],v=i[1],y=i[4],x=i[7],b=i[2],_=i[5],w=i[8];return r[0]=a*f+o*v+s*b,r[3]=a*m+o*y+s*_,r[6]=a*g+o*x+s*w,r[1]=c*f+l*v+h*b,r[4]=c*m+l*y+h*_,r[7]=c*g+l*x+h*w,r[2]=u*f+p*v+d*b,r[5]=u*m+p*y+d*_,r[8]=u*g+p*x+d*w,this},multiplyScalar:function(e){var t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this},determinant:function(){var e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],a=e[4],o=e[5],s=e[6],c=e[7],l=e[8];return t*a*l-t*o*c-n*r*l+n*o*s+i*r*c-i*a*s},getInverse:function(e,t){e&&e.isMatrix4&&console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");var n=e.elements,i=this.elements,r=n[0],a=n[1],o=n[2],s=n[3],c=n[4],l=n[5],h=n[6],u=n[7],p=n[8],d=p*c-l*u,f=l*h-p*s,m=u*s-c*h,g=r*d+a*f+o*m;if(0===g){var v="THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";if(!0===t)throw new Error(v);return console.warn(v),this.identity()}var y=1/g;return i[0]=d*y,i[1]=(o*u-p*a)*y,i[2]=(l*a-o*c)*y,i[3]=f*y,i[4]=(p*r-o*h)*y,i[5]=(o*s-l*r)*y,i[6]=m*y,i[7]=(a*h-u*r)*y,i[8]=(c*r-a*s)*y,this},transpose:function(){var e,t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this},getNormalMatrix:function(e){return this.setFromMatrix4(e).getInverse(this).transpose()},transposeIntoArray:function(e){var t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this},setUvTransform:function(e,t,n,i,r,a,o){var s=Math.cos(r),c=Math.sin(r);this.set(n*s,n*c,-n*(s*a+c*o)+a+e,-i*c,i*s,-i*(-c*a+s*o)+o+t,0,0,1)},scale:function(e,t){var n=this.elements;return n[0]*=e,n[3]*=e,n[6]*=e,n[1]*=t,n[4]*=t,n[7]*=t,this},rotate:function(e){var t=Math.cos(e),n=Math.sin(e),i=this.elements,r=i[0],a=i[3],o=i[6],s=i[1],c=i[4],l=i[7];return i[0]=t*r+n*s,i[3]=t*a+n*c,i[6]=t*o+n*l,i[1]=-n*r+t*s,i[4]=-n*a+t*c,i[7]=-n*o+t*l,this},translate:function(e,t){var n=this.elements;return n[0]+=e*n[2],n[3]+=e*n[5],n[6]+=e*n[8],n[1]+=t*n[2],n[4]+=t*n[5],n[7]+=t*n[8],this},equals:function(e){for(var t=this.elements,n=e.elements,i=0;i<9;i++)if(t[i]!==n[i])return!1;return!0},fromArray:function(e,t){void 0===t&&(t=0);for(var n=0;n<9;n++)this.elements[n]=e[n+t];return this},toArray:function(e,t){void 0===e&&(e=[]),void 0===t&&(t=0);var n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}});var Yt={getDataURL:function(e){var t;if("undefined"==typeof HTMLCanvasElement)return e.src;if(e instanceof HTMLCanvasElement)t=e;else{void 0===jt&&(jt=document.createElementNS("http://www.w3.org/1999/xhtml","canvas")),jt.width=e.width,jt.height=e.height;var n=jt.getContext("2d");e instanceof ImageData?n.putImageData(e,0,0):n.drawImage(e,0,0,e.width,e.height),t=jt}return t.width>2048||t.height>2048?t.toDataURL("image/jpeg",.6):t.toDataURL("image/png")}},Zt=0;function Jt(e,t,n,i,r,a,o,s,c,l){Object.defineProperty(this,"id",{value:Zt++}),this.uuid=Wt.generateUUID(),this.name="",this.image=void 0!==e?e:Jt.DEFAULT_IMAGE,this.mipmaps=[],this.mapping=void 0!==t?t:Jt.DEFAULT_MAPPING,this.wrapS=void 0!==n?n:ie,this.wrapT=void 0!==i?i:ie,this.magFilter=void 0!==r?r:ce,this.minFilter=void 0!==a?a:he,this.anisotropy=void 0!==c?c:1,this.format=void 0!==o?o:Te,this.internalFormat=null,this.type=void 0!==s?s:ue,this.offset=new qt(0,0),this.repeat=new qt(1,1),this.center=new qt(0,0),this.rotation=0,this.matrixAutoUpdate=!0,this.matrix=new Xt,this.generateMipmaps=!0,this.premultiplyAlpha=!1,this.flipY=!0,this.unpackAlignment=4,this.encoding=void 0!==l?l:Tt,this.version=0,this.onUpdate=null}function Qt(e,t,n,i){this.x=e||0,this.y=t||0,this.z=n||0,this.w=void 0!==i?i:1}function Kt(e,t,n){this.width=e,this.height=t,this.scissor=new Qt(0,0,e,t),this.scissorTest=!1,this.viewport=new Qt(0,0,e,t),n=n||{},this.texture=new Jt(void 0,n.mapping,n.wrapS,n.wrapT,n.magFilter,n.minFilter,n.format,n.type,n.anisotropy,n.encoding),this.texture.image={},this.texture.image.width=e,this.texture.image.height=t,this.texture.generateMipmaps=void 0!==n.generateMipmaps&&n.generateMipmaps,this.texture.minFilter=void 0!==n.minFilter?n.minFilter:ce,this.depthBuffer=void 0===n.depthBuffer||n.depthBuffer,this.stencilBuffer=void 0===n.stencilBuffer||n.stencilBuffer,this.depthTexture=void 0!==n.depthTexture?n.depthTexture:null}function $t(e,t,n){Kt.call(this,e,t,n),this.samples=4}function en(e,t,n,i){this._x=e||0,this._y=t||0,this._z=n||0,this._w=void 0!==i?i:1}Jt.DEFAULT_IMAGE=void 0,Jt.DEFAULT_MAPPING=300,Jt.prototype=Object.assign(Object.create(Ht.prototype),{constructor:Jt,isTexture:!0,updateMatrix:function(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.name=e.name,this.image=e.image,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.encoding=e.encoding,this},toJSON:function(e){var t=void 0===e||"string"==typeof e;if(!t&&void 0!==e.textures[this.uuid])return e.textures[this.uuid];var n={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,type:this.type,encoding:this.encoding,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};if(void 0!==this.image){var i=this.image;if(void 0===i.uuid&&(i.uuid=Wt.generateUUID()),!t&&void 0===e.images[i.uuid]){var r;if(Array.isArray(i)){r=[];for(var a=0,o=i.length;a1)switch(this.wrapS){case ne:e.x=e.x-Math.floor(e.x);break;case ie:e.x=e.x<0?0:1;break;case re:1===Math.abs(Math.floor(e.x)%2)?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x)}if(e.y<0||e.y>1)switch(this.wrapT){case ne:e.y=e.y-Math.floor(e.y);break;case ie:e.y=e.y<0?0:1;break;case re:1===Math.abs(Math.floor(e.y)%2)?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y)}return this.flipY&&(e.y=1-e.y),e}}),Object.defineProperty(Jt.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.defineProperties(Qt.prototype,{width:{get:function(){return this.z},set:function(e){this.z=e}},height:{get:function(){return this.w},set:function(e){this.w=e}}}),Object.assign(Qt.prototype,{isVector4:!0,set:function(e,t,n,i){return this.x=e,this.y=t,this.z=n,this.w=i,this},setScalar:function(e){return this.x=e,this.y=e,this.z=e,this.w=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setZ:function(e){return this.z=e,this},setW:function(e){return this.w=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=void 0!==e.w?e.w:1,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this)},addScalar:function(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this)},subScalar:function(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this},multiplyScalar:function(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this},applyMatrix4:function(e){var t=this.x,n=this.y,i=this.z,r=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*i+a[12]*r,this.y=a[1]*t+a[5]*n+a[9]*i+a[13]*r,this.z=a[2]*t+a[6]*n+a[10]*i+a[14]*r,this.w=a[3]*t+a[7]*n+a[11]*i+a[15]*r,this},divideScalar:function(e){return this.multiplyScalar(1/e)},setAxisAngleFromQuaternion:function(e){this.w=2*Math.acos(e.w);var t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this},setAxisAngleFromRotationMatrix:function(e){var t,n,i,r,a=e.elements,o=a[0],s=a[4],c=a[8],l=a[1],h=a[5],u=a[9],p=a[2],d=a[6],f=a[10];if(Math.abs(s-l)<.01&&Math.abs(c-p)<.01&&Math.abs(u-d)<.01){if(Math.abs(s+l)<.1&&Math.abs(c+p)<.1&&Math.abs(u+d)<.1&&Math.abs(o+h+f-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;var m=(o+1)/2,g=(h+1)/2,v=(f+1)/2,y=(s+l)/4,x=(c+p)/4,b=(u+d)/4;return m>g&&m>v?m<.01?(n=0,i=.707106781,r=.707106781):(i=y/(n=Math.sqrt(m)),r=x/n):g>v?g<.01?(n=.707106781,i=0,r=.707106781):(n=y/(i=Math.sqrt(g)),r=b/i):v<.01?(n=.707106781,i=.707106781,r=0):(n=x/(r=Math.sqrt(v)),i=b/r),this.set(n,i,r,t),this}var _=Math.sqrt((d-u)*(d-u)+(c-p)*(c-p)+(l-s)*(l-s));return Math.abs(_)<.001&&(_=1),this.x=(d-u)/_,this.y=(c-p)/_,this.z=(l-s)/_,this.w=Math.acos((o+h+f-1)/2),this},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this.w=Math.max(e.w,Math.min(t.w,this.w)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this.w=Math.max(e,Math.min(t,this.w)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this.w=this.w<0?Math.ceil(this.w):Math.floor(this.w),this},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this},dot:function(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},equals:function(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}}),Kt.prototype=Object.assign(Object.create(Ht.prototype),{constructor:Kt,isWebGLRenderTarget:!0,setSize:function(e,t){this.width===e&&this.height===t||(this.width=e,this.height=t,this.texture.image.width=e,this.texture.image.height=t,this.dispose()),this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.width=e.width,this.height=e.height,this.viewport.copy(e.viewport),this.texture=e.texture.clone(),this.depthBuffer=e.depthBuffer,this.stencilBuffer=e.stencilBuffer,this.depthTexture=e.depthTexture,this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),$t.prototype=Object.assign(Object.create(Kt.prototype),{constructor:$t,isWebGLMultisampleRenderTarget:!0,copy:function(e){return Kt.prototype.copy.call(this,e),this.samples=e.samples,this}}),Object.assign(en,{slerp:function(e,t,n,i){return n.copy(e).slerp(t,i)},slerpFlat:function(e,t,n,i,r,a,o){var s=n[i+0],c=n[i+1],l=n[i+2],h=n[i+3],u=r[a+0],p=r[a+1],d=r[a+2],f=r[a+3];if(h!==f||s!==u||c!==p||l!==d){var m=1-o,g=s*u+c*p+l*d+h*f,v=g>=0?1:-1,y=1-g*g;if(y>Number.EPSILON){var x=Math.sqrt(y),b=Math.atan2(x,g*v);m=Math.sin(m*b)/x,o=Math.sin(o*b)/x}var _=o*v;if(s=s*m+u*_,c=c*m+p*_,l=l*m+d*_,h=h*m+f*_,m===1-o){var w=1/Math.sqrt(s*s+c*c+l*l+h*h);s*=w,c*=w,l*=w,h*=w}}e[t]=s,e[t+1]=c,e[t+2]=l,e[t+3]=h}}),Object.defineProperties(en.prototype,{x:{get:function(){return this._x},set:function(e){this._x=e,this._onChangeCallback()}},y:{get:function(){return this._y},set:function(e){this._y=e,this._onChangeCallback()}},z:{get:function(){return this._z},set:function(e){this._z=e,this._onChangeCallback()}},w:{get:function(){return this._w},set:function(e){this._w=e,this._onChangeCallback()}}}),Object.assign(en.prototype,{isQuaternion:!0,set:function(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._w=i,this._onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this},setFromEuler:function(e,t){if(!e||!e.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var n=e._x,i=e._y,r=e._z,a=e.order,o=Math.cos,s=Math.sin,c=o(n/2),l=o(i/2),h=o(r/2),u=s(n/2),p=s(i/2),d=s(r/2);return"XYZ"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h-u*p*d):"YXZ"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h+u*p*d):"ZXY"===a?(this._x=u*l*h-c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h-u*p*d):"ZYX"===a?(this._x=u*l*h-c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h+u*p*d):"YZX"===a?(this._x=u*l*h+c*p*d,this._y=c*p*h+u*l*d,this._z=c*l*d-u*p*h,this._w=c*l*h-u*p*d):"XZY"===a&&(this._x=u*l*h-c*p*d,this._y=c*p*h-u*l*d,this._z=c*l*d+u*p*h,this._w=c*l*h+u*p*d),!1!==t&&this._onChangeCallback(),this},setFromAxisAngle:function(e,t){var n=t/2,i=Math.sin(n);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(n),this._onChangeCallback(),this},setFromRotationMatrix:function(e){var t,n=e.elements,i=n[0],r=n[4],a=n[8],o=n[1],s=n[5],c=n[9],l=n[2],h=n[6],u=n[10],p=i+s+u;return p>0?(t=.5/Math.sqrt(p+1),this._w=.25/t,this._x=(h-c)*t,this._y=(a-l)*t,this._z=(o-r)*t):i>s&&i>u?(t=2*Math.sqrt(1+i-s-u),this._w=(h-c)/t,this._x=.25*t,this._y=(r+o)/t,this._z=(a+l)/t):s>u?(t=2*Math.sqrt(1+s-i-u),this._w=(a-l)/t,this._x=(r+o)/t,this._y=.25*t,this._z=(c+h)/t):(t=2*Math.sqrt(1+u-i-s),this._w=(o-r)/t,this._x=(a+l)/t,this._y=(c+h)/t,this._z=.25*t),this._onChangeCallback(),this},setFromUnitVectors:function(e,t){var n=e.dot(t)+1;return n<1e-6?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()},angleTo:function(e){return 2*Math.acos(Math.abs(Wt.clamp(this.dot(e),-1,1)))},rotateTowards:function(e,t){var n=this.angleTo(e);if(0===n)return this;var i=Math.min(1,t/n);return this.slerp(e,i),this},inverse:function(){return this.conjugate()},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this},dot:function(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var e=this.length();return 0===e?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(e,t)):this.multiplyQuaternions(this,e)},premultiply:function(e){return this.multiplyQuaternions(e,this)},multiplyQuaternions:function(e,t){var n=e._x,i=e._y,r=e._z,a=e._w,o=t._x,s=t._y,c=t._z,l=t._w;return this._x=n*l+a*o+i*c-r*s,this._y=i*l+a*s+r*o-n*c,this._z=r*l+a*c+n*s-i*o,this._w=a*l-n*o-i*s-r*c,this._onChangeCallback(),this},slerp:function(e,t){if(0===t)return this;if(1===t)return this.copy(e);var n=this._x,i=this._y,r=this._z,a=this._w,o=a*e._w+n*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=i,this._z=r,this;var s=1-o*o;if(s<=Number.EPSILON){var c=1-t;return this._w=c*a+t*this._w,this._x=c*n+t*this._x,this._y=c*i+t*this._y,this._z=c*r+t*this._z,this.normalize(),this._onChangeCallback(),this}var l=Math.sqrt(s),h=Math.atan2(l,o),u=Math.sin((1-t)*h)/l,p=Math.sin(t*h)/l;return this._w=a*u+this._w*p,this._x=n*u+this._x*p,this._y=i*u+this._y*p,this._z=r*u+this._z*p,this._onChangeCallback(),this},equals:function(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w},fromArray:function(e,t){return void 0===t&&(t=0),this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e},_onChange:function(e){return this._onChangeCallback=e,this},_onChangeCallback:function(){}});var tn=new rn,nn=new en;function rn(e,t,n){this.x=e||0,this.y=t||0,this.z=n||0}Object.assign(rn.prototype,{isVector3:!0,set:function(e,t,n){return this.x=e,this.y=t,this.z=n,this},setScalar:function(e){return this.x=e,this.y=e,this.z=e,this},setX:function(e){return this.x=e,this},setY:function(e){return this.y=e,this},setZ:function(e){return this.z=e,this},setComponent:function(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this},getComponent:function(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this},add:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(e,t)):(this.x+=e.x,this.y+=e.y,this.z+=e.z,this)},addScalar:function(e){return this.x+=e,this.y+=e,this.z+=e,this},addVectors:function(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this},addScaledVector:function(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this},sub:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(e,t)):(this.x-=e.x,this.y-=e.y,this.z-=e.z,this)},subScalar:function(e){return this.x-=e,this.y-=e,this.z-=e,this},subVectors:function(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(e,t)):(this.x*=e.x,this.y*=e.y,this.z*=e.z,this)},multiplyScalar:function(e){return this.x*=e,this.y*=e,this.z*=e,this},multiplyVectors:function(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this},applyEuler:function(e){return e&&e.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(nn.setFromEuler(e))},applyAxisAngle:function(e,t){return this.applyQuaternion(nn.setFromAxisAngle(e,t))},applyMatrix3:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*i,this.y=r[1]*t+r[4]*n+r[7]*i,this.z=r[2]*t+r[5]*n+r[8]*i,this},applyNormalMatrix:function(e){return this.applyMatrix3(e).normalize()},applyMatrix4:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements,a=1/(r[3]*t+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*i+r[12])*a,this.y=(r[1]*t+r[5]*n+r[9]*i+r[13])*a,this.z=(r[2]*t+r[6]*n+r[10]*i+r[14])*a,this},applyQuaternion:function(e){var t=this.x,n=this.y,i=this.z,r=e.x,a=e.y,o=e.z,s=e.w,c=s*t+a*i-o*n,l=s*n+o*t-r*i,h=s*i+r*n-a*t,u=-r*t-a*n-o*i;return this.x=c*s+u*-r+l*-o-h*-a,this.y=l*s+u*-a+h*-r-c*-o,this.z=h*s+u*-o+c*-a-l*-r,this},project:function(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)},unproject:function(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)},transformDirection:function(e){var t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*i,this.y=r[1]*t+r[5]*n+r[9]*i,this.z=r[2]*t+r[6]*n+r[10]*i,this.normalize()},divide:function(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this},divideScalar:function(e){return this.multiplyScalar(1/e)},min:function(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this},max:function(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this},clamp:function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this},clampScalar:function(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this},clampLength:function(e,t){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this},dot:function(e){return this.x*e.x+this.y*e.y+this.z*e.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(e){return this.normalize().multiplyScalar(e)},lerp:function(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this},lerpVectors:function(e,t,n){return this.subVectors(t,e).multiplyScalar(n).add(e)},cross:function(e,t){return void 0!==t?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(e,t)):this.crossVectors(this,e)},crossVectors:function(e,t){var n=e.x,i=e.y,r=e.z,a=t.x,o=t.y,s=t.z;return this.x=i*s-r*o,this.y=r*a-n*s,this.z=n*o-i*a,this},projectOnVector:function(e){var t=e.lengthSq();if(0===t)return this.set(0,0,0);var n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)},projectOnPlane:function(e){return tn.copy(this).projectOnVector(e),this.sub(tn)},reflect:function(e){return this.sub(tn.copy(e).multiplyScalar(2*this.dot(e)))},angleTo:function(e){var t=Math.sqrt(this.lengthSq()*e.lengthSq());if(0===t)return Math.PI/2;var n=this.dot(e)/t;return Math.acos(Wt.clamp(n,-1,1))},distanceTo:function(e){return Math.sqrt(this.distanceToSquared(e))},distanceToSquared:function(e){var t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i},manhattanDistanceTo:function(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)},setFromSpherical:function(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)},setFromSphericalCoords:function(e,t,n){var i=Math.sin(t)*e;return this.x=i*Math.sin(n),this.y=Math.cos(t)*e,this.z=i*Math.cos(n),this},setFromCylindrical:function(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)},setFromCylindricalCoords:function(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this},setFromMatrixPosition:function(e){var t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this},setFromMatrixScale:function(e){var t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=i,this},setFromMatrixColumn:function(e,t){return this.fromArray(e.elements,4*t)},setFromMatrix3Column:function(e,t){return this.fromArray(e.elements,3*t)},equals:function(e){return e.x===this.x&&e.y===this.y&&e.z===this.z},fromArray:function(e,t){return void 0===t&&(t=0),this.x=e[t],this.y=e[t+1],this.z=e[t+2],this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e},fromBufferAttribute:function(e,t,n){return void 0!==n&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}});var an=new rn,on=new pn,sn=new rn(0,0,0),cn=new rn(1,1,1),ln=new rn,hn=new rn,un=new rn;function pn(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}Object.assign(pn.prototype,{isMatrix4:!0,set:function(e,t,n,i,r,a,o,s,c,l,h,u,p,d,f,m){var g=this.elements;return g[0]=e,g[4]=t,g[8]=n,g[12]=i,g[1]=r,g[5]=a,g[9]=o,g[13]=s,g[2]=c,g[6]=l,g[10]=h,g[14]=u,g[3]=p,g[7]=d,g[11]=f,g[15]=m,this},identity:function(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this},clone:function(){return(new pn).fromArray(this.elements)},copy:function(e){var t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this},copyPosition:function(e){var t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this},extractBasis:function(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this},makeBasis:function(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this},extractRotation:function(e){var t=this.elements,n=e.elements,i=1/an.setFromMatrixColumn(e,0).length(),r=1/an.setFromMatrixColumn(e,1).length(),a=1/an.setFromMatrixColumn(e,2).length();return t[0]=n[0]*i,t[1]=n[1]*i,t[2]=n[2]*i,t[3]=0,t[4]=n[4]*r,t[5]=n[5]*r,t[6]=n[6]*r,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this},makeRotationFromEuler:function(e){e&&e.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var t=this.elements,n=e.x,i=e.y,r=e.z,a=Math.cos(n),o=Math.sin(n),s=Math.cos(i),c=Math.sin(i),l=Math.cos(r),h=Math.sin(r);if("XYZ"===e.order){var u=a*l,p=a*h,d=o*l,f=o*h;t[0]=s*l,t[4]=-s*h,t[8]=c,t[1]=p+d*c,t[5]=u-f*c,t[9]=-o*s,t[2]=f-u*c,t[6]=d+p*c,t[10]=a*s}else if("YXZ"===e.order){var m=s*l,g=s*h,v=c*l,y=c*h;t[0]=m+y*o,t[4]=v*o-g,t[8]=a*c,t[1]=a*h,t[5]=a*l,t[9]=-o,t[2]=g*o-v,t[6]=y+m*o,t[10]=a*s}else if("ZXY"===e.order){m=s*l,g=s*h,v=c*l,y=c*h;t[0]=m-y*o,t[4]=-a*h,t[8]=v+g*o,t[1]=g+v*o,t[5]=a*l,t[9]=y-m*o,t[2]=-a*c,t[6]=o,t[10]=a*s}else if("ZYX"===e.order){u=a*l,p=a*h,d=o*l,f=o*h;t[0]=s*l,t[4]=d*c-p,t[8]=u*c+f,t[1]=s*h,t[5]=f*c+u,t[9]=p*c-d,t[2]=-c,t[6]=o*s,t[10]=a*s}else if("YZX"===e.order){var x=a*s,b=a*c,_=o*s,w=o*c;t[0]=s*l,t[4]=w-x*h,t[8]=_*h+b,t[1]=h,t[5]=a*l,t[9]=-o*l,t[2]=-c*l,t[6]=b*h+_,t[10]=x-w*h}else if("XZY"===e.order){x=a*s,b=a*c,_=o*s,w=o*c;t[0]=s*l,t[4]=-h,t[8]=c*l,t[1]=x*h+w,t[5]=a*l,t[9]=b*h-_,t[2]=_*h-b,t[6]=o*l,t[10]=w*h+x}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this},makeRotationFromQuaternion:function(e){return this.compose(sn,e,cn)},lookAt:function(e,t,n){var i=this.elements;return un.subVectors(e,t),0===un.lengthSq()&&(un.z=1),un.normalize(),ln.crossVectors(n,un),0===ln.lengthSq()&&(1===Math.abs(n.z)?un.x+=1e-4:un.z+=1e-4,un.normalize(),ln.crossVectors(n,un)),ln.normalize(),hn.crossVectors(un,ln),i[0]=ln.x,i[4]=hn.x,i[8]=un.x,i[1]=ln.y,i[5]=hn.y,i[9]=un.y,i[2]=ln.z,i[6]=hn.z,i[10]=un.z,this},multiply:function(e,t){return void 0!==t?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(e,t)):this.multiplyMatrices(this,e)},premultiply:function(e){return this.multiplyMatrices(e,this)},multiplyMatrices:function(e,t){var n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[4],s=n[8],c=n[12],l=n[1],h=n[5],u=n[9],p=n[13],d=n[2],f=n[6],m=n[10],g=n[14],v=n[3],y=n[7],x=n[11],b=n[15],_=i[0],w=i[4],M=i[8],S=i[12],T=i[1],E=i[5],A=i[9],L=i[13],R=i[2],P=i[6],C=i[10],O=i[14],D=i[3],I=i[7],N=i[11],B=i[15];return r[0]=a*_+o*T+s*R+c*D,r[4]=a*w+o*E+s*P+c*I,r[8]=a*M+o*A+s*C+c*N,r[12]=a*S+o*L+s*O+c*B,r[1]=l*_+h*T+u*R+p*D,r[5]=l*w+h*E+u*P+p*I,r[9]=l*M+h*A+u*C+p*N,r[13]=l*S+h*L+u*O+p*B,r[2]=d*_+f*T+m*R+g*D,r[6]=d*w+f*E+m*P+g*I,r[10]=d*M+f*A+m*C+g*N,r[14]=d*S+f*L+m*O+g*B,r[3]=v*_+y*T+x*R+b*D,r[7]=v*w+y*E+x*P+b*I,r[11]=v*M+y*A+x*C+b*N,r[15]=v*S+y*L+x*O+b*B,this},multiplyScalar:function(e){var t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this},determinant:function(){var e=this.elements,t=e[0],n=e[4],i=e[8],r=e[12],a=e[1],o=e[5],s=e[9],c=e[13],l=e[2],h=e[6],u=e[10],p=e[14];return e[3]*(+r*s*h-i*c*h-r*o*u+n*c*u+i*o*p-n*s*p)+e[7]*(+t*s*p-t*c*u+r*a*u-i*a*p+i*c*l-r*s*l)+e[11]*(+t*c*h-t*o*p-r*a*h+n*a*p+r*o*l-n*c*l)+e[15]*(-i*o*l-t*s*h+t*o*u+i*a*h-n*a*u+n*s*l)},transpose:function(){var e,t=this.elements;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this},setPosition:function(e,t,n){var i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=n),this},getInverse:function(e,t){var n=this.elements,i=e.elements,r=i[0],a=i[1],o=i[2],s=i[3],c=i[4],l=i[5],h=i[6],u=i[7],p=i[8],d=i[9],f=i[10],m=i[11],g=i[12],v=i[13],y=i[14],x=i[15],b=d*y*u-v*f*u+v*h*m-l*y*m-d*h*x+l*f*x,_=g*f*u-p*y*u-g*h*m+c*y*m+p*h*x-c*f*x,w=p*v*u-g*d*u+g*l*m-c*v*m-p*l*x+c*d*x,M=g*d*h-p*v*h-g*l*f+c*v*f+p*l*y-c*d*y,S=r*b+a*_+o*w+s*M;if(0===S){var T="THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";if(!0===t)throw new Error(T);return console.warn(T),this.identity()}var E=1/S;return n[0]=b*E,n[1]=(v*f*s-d*y*s-v*o*m+a*y*m+d*o*x-a*f*x)*E,n[2]=(l*y*s-v*h*s+v*o*u-a*y*u-l*o*x+a*h*x)*E,n[3]=(d*h*s-l*f*s-d*o*u+a*f*u+l*o*m-a*h*m)*E,n[4]=_*E,n[5]=(p*y*s-g*f*s+g*o*m-r*y*m-p*o*x+r*f*x)*E,n[6]=(g*h*s-c*y*s-g*o*u+r*y*u+c*o*x-r*h*x)*E,n[7]=(c*f*s-p*h*s+p*o*u-r*f*u-c*o*m+r*h*m)*E,n[8]=w*E,n[9]=(g*d*s-p*v*s-g*a*m+r*v*m+p*a*x-r*d*x)*E,n[10]=(c*v*s-g*l*s+g*a*u-r*v*u-c*a*x+r*l*x)*E,n[11]=(p*l*s-c*d*s-p*a*u+r*d*u+c*a*m-r*l*m)*E,n[12]=M*E,n[13]=(p*v*o-g*d*o+g*a*f-r*v*f-p*a*y+r*d*y)*E,n[14]=(g*l*o-c*v*o-g*a*h+r*v*h+c*a*y-r*l*y)*E,n[15]=(c*d*o-p*l*o+p*a*h-r*d*h-c*a*f+r*l*f)*E,this},scale:function(e){var t=this.elements,n=e.x,i=e.y,r=e.z;return t[0]*=n,t[4]*=i,t[8]*=r,t[1]*=n,t[5]*=i,t[9]*=r,t[2]*=n,t[6]*=i,t[10]*=r,t[3]*=n,t[7]*=i,t[11]*=r,this},getMaxScaleOnAxis:function(){var e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,i))},makeTranslation:function(e,t,n){return this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this},makeRotationX:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this},makeRotationY:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this},makeRotationZ:function(e){var t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this},makeRotationAxis:function(e,t){var n=Math.cos(t),i=Math.sin(t),r=1-n,a=e.x,o=e.y,s=e.z,c=r*a,l=r*o;return this.set(c*a+n,c*o-i*s,c*s+i*o,0,c*o+i*s,l*o+n,l*s-i*a,0,c*s-i*o,l*s+i*a,r*s*s+n,0,0,0,0,1),this},makeScale:function(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this},makeShear:function(e,t,n){return this.set(1,t,n,0,e,1,n,0,e,t,1,0,0,0,0,1),this},compose:function(e,t,n){var i=this.elements,r=t._x,a=t._y,o=t._z,s=t._w,c=r+r,l=a+a,h=o+o,u=r*c,p=r*l,d=r*h,f=a*l,m=a*h,g=o*h,v=s*c,y=s*l,x=s*h,b=n.x,_=n.y,w=n.z;return i[0]=(1-(f+g))*b,i[1]=(p+x)*b,i[2]=(d-y)*b,i[3]=0,i[4]=(p-x)*_,i[5]=(1-(u+g))*_,i[6]=(m+v)*_,i[7]=0,i[8]=(d+y)*w,i[9]=(m-v)*w,i[10]=(1-(u+f))*w,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this},decompose:function(e,t,n){var i=this.elements,r=an.set(i[0],i[1],i[2]).length(),a=an.set(i[4],i[5],i[6]).length(),o=an.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],on.copy(this);var s=1/r,c=1/a,l=1/o;return on.elements[0]*=s,on.elements[1]*=s,on.elements[2]*=s,on.elements[4]*=c,on.elements[5]*=c,on.elements[6]*=c,on.elements[8]*=l,on.elements[9]*=l,on.elements[10]*=l,t.setFromRotationMatrix(on),n.x=r,n.y=a,n.z=o,this},makePerspective:function(e,t,n,i,r,a){void 0===a&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");var o=this.elements,s=2*r/(t-e),c=2*r/(n-i),l=(t+e)/(t-e),h=(n+i)/(n-i),u=-(a+r)/(a-r),p=-2*a*r/(a-r);return o[0]=s,o[4]=0,o[8]=l,o[12]=0,o[1]=0,o[5]=c,o[9]=h,o[13]=0,o[2]=0,o[6]=0,o[10]=u,o[14]=p,o[3]=0,o[7]=0,o[11]=-1,o[15]=0,this},makeOrthographic:function(e,t,n,i,r,a){var o=this.elements,s=1/(t-e),c=1/(n-i),l=1/(a-r),h=(t+e)*s,u=(n+i)*c,p=(a+r)*l;return o[0]=2*s,o[4]=0,o[8]=0,o[12]=-h,o[1]=0,o[5]=2*c,o[9]=0,o[13]=-u,o[2]=0,o[6]=0,o[10]=-2*l,o[14]=-p,o[3]=0,o[7]=0,o[11]=0,o[15]=1,this},equals:function(e){for(var t=this.elements,n=e.elements,i=0;i<16;i++)if(t[i]!==n[i])return!1;return!0},fromArray:function(e,t){void 0===t&&(t=0);for(var n=0;n<16;n++)this.elements[n]=e[n+t];return this},toArray:function(e,t){void 0===e&&(e=[]),void 0===t&&(t=0);var n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}});var dn=new pn,fn=new en;function mn(e,t,n,i){this._x=e||0,this._y=t||0,this._z=n||0,this._order=i||mn.DefaultOrder}function gn(){this.mask=1}mn.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"],mn.DefaultOrder="XYZ",Object.defineProperties(mn.prototype,{x:{get:function(){return this._x},set:function(e){this._x=e,this._onChangeCallback()}},y:{get:function(){return this._y},set:function(e){this._y=e,this._onChangeCallback()}},z:{get:function(){return this._z},set:function(e){this._z=e,this._onChangeCallback()}},order:{get:function(){return this._order},set:function(e){this._order=e,this._onChangeCallback()}}}),Object.assign(mn.prototype,{isEuler:!0,set:function(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._order=i||this._order,this._onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this},setFromRotationMatrix:function(e,t,n){var i=Wt.clamp,r=e.elements,a=r[0],o=r[4],s=r[8],c=r[1],l=r[5],h=r[9],u=r[2],p=r[6],d=r[10];return"XYZ"===(t=t||this._order)?(this._y=Math.asin(i(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(-h,d),this._z=Math.atan2(-o,a)):(this._x=Math.atan2(p,l),this._z=0)):"YXZ"===t?(this._x=Math.asin(-i(h,-1,1)),Math.abs(h)<.9999999?(this._y=Math.atan2(s,d),this._z=Math.atan2(c,l)):(this._y=Math.atan2(-u,a),this._z=0)):"ZXY"===t?(this._x=Math.asin(i(p,-1,1)),Math.abs(p)<.9999999?(this._y=Math.atan2(-u,d),this._z=Math.atan2(-o,l)):(this._y=0,this._z=Math.atan2(c,a))):"ZYX"===t?(this._y=Math.asin(-i(u,-1,1)),Math.abs(u)<.9999999?(this._x=Math.atan2(p,d),this._z=Math.atan2(c,a)):(this._x=0,this._z=Math.atan2(-o,l))):"YZX"===t?(this._z=Math.asin(i(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(-h,l),this._y=Math.atan2(-u,a)):(this._x=0,this._y=Math.atan2(s,d))):"XZY"===t?(this._z=Math.asin(-i(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(p,l),this._y=Math.atan2(s,a)):(this._x=Math.atan2(-h,d),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+t),this._order=t,!1!==n&&this._onChangeCallback(),this},setFromQuaternion:function(e,t,n){return dn.makeRotationFromQuaternion(e),this.setFromRotationMatrix(dn,t,n)},setFromVector3:function(e,t){return this.set(e.x,e.y,e.z,t||this._order)},reorder:function(e){return fn.setFromEuler(this),this.setFromQuaternion(fn,e)},equals:function(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order},fromArray:function(e){return this._x=e[0],this._y=e[1],this._z=e[2],void 0!==e[3]&&(this._order=e[3]),this._onChangeCallback(),this},toArray:function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=0),e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e},toVector3:function(e){return e?e.set(this._x,this._y,this._z):new rn(this._x,this._y,this._z)},_onChange:function(e){return this._onChangeCallback=e,this},_onChangeCallback:function(){}}),Object.assign(gn.prototype,{set:function(e){this.mask=1<1){for(var t=0;t1){for(var t=0;t0){i.children=[];for(s=0;s0&&(n.geometries=u),p.length>0&&(n.materials=p),d.length>0&&(n.textures=d),f.length>0&&(n.images=f),o.length>0&&(n.shapes=o)}return n.object=i,n;function m(e){var t=[];for(var n in e){var i=e[n];delete i.metadata,t.push(i)}return t}},clone:function(e){return(new this.constructor).copy(this,e)},copy:function(e,t){if(void 0===t&&(t=!0),this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.userData=JSON.parse(JSON.stringify(e.userData)),!0===t)for(var n=0;ns)return!1}return!0}Object.assign(Wn.prototype,{isBox3:!0,set:function(e,t){return this.min.copy(e),this.max.copy(t),this},setFromArray:function(e){for(var t=1/0,n=1/0,i=1/0,r=-1/0,a=-1/0,o=-1/0,s=0,c=e.length;sr&&(r=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(t,n,i),this.max.set(r,a,o),this},setFromBufferAttribute:function(e){for(var t=1/0,n=1/0,i=1/0,r=-1/0,a=-1/0,o=-1/0,s=0,c=e.count;sr&&(r=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(t,n,i),this.max.set(r,a,o),this},setFromPoints:function(e){this.makeEmpty();for(var t=0,n=e.length;tthis.max.x||e.ythis.max.y||e.zthis.max.z)},containsBox:function(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z},getParameter:function(e,t){return void 0===t&&(console.warn("THREE.Box3: .getParameter() target is now required"),t=new rn),t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(e){return!(e.max.xthis.max.x||e.max.ythis.max.y||e.max.zthis.max.z)},intersectsSphere:function(e){return this.clampPoint(e.center,Dn),Dn.distanceToSquared(e.center)<=e.radius*e.radius},intersectsPlane:function(e){var t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant},intersectsTriangle:function(e){if(this.isEmpty())return!1;this.getCenter(Hn),Vn.subVectors(this.max,Hn),Nn.subVectors(e.a,Hn),Bn.subVectors(e.b,Hn),zn.subVectors(e.c,Hn),Fn.subVectors(Bn,Nn),Un.subVectors(zn,Bn),Gn.subVectors(Nn,zn);var t=[0,-Fn.z,Fn.y,0,-Un.z,Un.y,0,-Gn.z,Gn.y,Fn.z,0,-Fn.x,Un.z,0,-Un.x,Gn.z,0,-Gn.x,-Fn.y,Fn.x,0,-Un.y,Un.x,0,-Gn.y,Gn.x,0];return!!qn(t,Nn,Bn,zn,Vn)&&(!!qn(t=[1,0,0,0,1,0,0,0,1],Nn,Bn,zn,Vn)&&(kn.crossVectors(Fn,Un),qn(t=[kn.x,kn.y,kn.z],Nn,Bn,zn,Vn)))},clampPoint:function(e,t){return void 0===t&&(console.warn("THREE.Box3: .clampPoint() target is now required"),t=new rn),t.copy(e).clamp(this.min,this.max)},distanceToPoint:function(e){return Dn.copy(e).clamp(this.min,this.max).sub(e).length()},getBoundingSphere:function(e){return void 0===e&&console.error("THREE.Box3: .getBoundingSphere() target is now required"),this.getCenter(e.center),e.radius=.5*this.getSize(Dn).length(),e},intersect:function(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this},union:function(e){return this.min.min(e.min),this.max.max(e.max),this},applyMatrix4:function(e){return this.isEmpty()?this:(On[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),On[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),On[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),On[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),On[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),On[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),On[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),On[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(On),this)},translate:function(e){return this.min.add(e),this.max.add(e),this},equals:function(e){return e.min.equals(this.min)&&e.max.equals(this.max)}});var Xn=new Wn;function Yn(e,t){this.center=void 0!==e?e:new rn,this.radius=void 0!==t?t:0}Object.assign(Yn.prototype,{set:function(e,t){return this.center.copy(e),this.radius=t,this},setFromPoints:function(e,t){var n=this.center;void 0!==t?n.copy(t):Xn.setFromPoints(e).getCenter(n);for(var i=0,r=0,a=e.length;rthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t},getBoundingBox:function(e){return void 0===e&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),e=new Wn),e.set(this.center,this.center),e.expandByScalar(this.radius),e},applyMatrix4:function(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this},translate:function(e){return this.center.add(e),this},equals:function(e){return e.center.equals(this.center)&&e.radius===this.radius}});var Zn=new rn,Jn=new rn,Qn=new rn,Kn=new rn,$n=new rn,ei=new rn,ti=new rn;function ni(e,t){this.origin=void 0!==e?e:new rn,this.direction=void 0!==t?t:new rn(0,0,-1)}Object.assign(ni.prototype,{set:function(e,t){return this.origin.copy(e),this.direction.copy(t),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this},at:function(e,t){return void 0===t&&(console.warn("THREE.Ray: .at() target is now required"),t=new rn),t.copy(this.direction).multiplyScalar(e).add(this.origin)},lookAt:function(e){return this.direction.copy(e).sub(this.origin).normalize(),this},recast:function(e){return this.origin.copy(this.at(e,Zn)),this},closestPointToPoint:function(e,t){void 0===t&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"),t=new rn),t.subVectors(e,this.origin);var n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.direction).multiplyScalar(n).add(this.origin)},distanceToPoint:function(e){return Math.sqrt(this.distanceSqToPoint(e))},distanceSqToPoint:function(e){var t=Zn.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Zn.copy(this.direction).multiplyScalar(t).add(this.origin),Zn.distanceToSquared(e))},distanceSqToSegment:function(e,t,n,i){Jn.copy(e).add(t).multiplyScalar(.5),Qn.copy(t).sub(e).normalize(),Kn.copy(this.origin).sub(Jn);var r,a,o,s,c=.5*e.distanceTo(t),l=-this.direction.dot(Qn),h=Kn.dot(this.direction),u=-Kn.dot(Qn),p=Kn.lengthSq(),d=Math.abs(1-l*l);if(d>0)if(a=l*h-u,s=c*d,(r=l*u-h)>=0)if(a>=-s)if(a<=s){var f=1/d;o=(r*=f)*(r+l*(a*=f)+2*h)+a*(l*r+a+2*u)+p}else a=c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;else a=-c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;else a<=-s?o=-(r=Math.max(0,-(-l*c+h)))*r+(a=r>0?-c:Math.min(Math.max(-c,-u),c))*(a+2*u)+p:a<=s?(r=0,o=(a=Math.min(Math.max(-c,-u),c))*(a+2*u)+p):o=-(r=Math.max(0,-(l*c+h)))*r+(a=r>0?c:Math.min(Math.max(-c,-u),c))*(a+2*u)+p;else a=l>0?-c:c,o=-(r=Math.max(0,-(l*a+h)))*r+a*(a+2*u)+p;return n&&n.copy(this.direction).multiplyScalar(r).add(this.origin),i&&i.copy(Qn).multiplyScalar(a).add(Jn),o},intersectSphere:function(e,t){Zn.subVectors(e.center,this.origin);var n=Zn.dot(this.direction),i=Zn.dot(Zn)-n*n,r=e.radius*e.radius;if(i>r)return null;var a=Math.sqrt(r-i),o=n-a,s=n+a;return o<0&&s<0?null:o<0?this.at(s,t):this.at(o,t)},intersectsSphere:function(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius},distanceToPlane:function(e){var t=e.normal.dot(this.direction);if(0===t)return 0===e.distanceToPoint(this.origin)?0:null;var n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null},intersectPlane:function(e,t){var n=this.distanceToPlane(e);return null===n?null:this.at(n,t)},intersectsPlane:function(e){var t=e.distanceToPoint(this.origin);return 0===t||e.normal.dot(this.direction)*t<0},intersectBox:function(e,t){var n,i,r,a,o,s,c=1/this.direction.x,l=1/this.direction.y,h=1/this.direction.z,u=this.origin;return c>=0?(n=(e.min.x-u.x)*c,i=(e.max.x-u.x)*c):(n=(e.max.x-u.x)*c,i=(e.min.x-u.x)*c),l>=0?(r=(e.min.y-u.y)*l,a=(e.max.y-u.y)*l):(r=(e.max.y-u.y)*l,a=(e.min.y-u.y)*l),n>a||r>i?null:((r>n||n!=n)&&(n=r),(a=0?(o=(e.min.z-u.z)*h,s=(e.max.z-u.z)*h):(o=(e.max.z-u.z)*h,s=(e.min.z-u.z)*h),n>s||o>i?null:((o>n||n!=n)&&(n=o),(s=0?n:i,t)))},intersectsBox:function(e){return null!==this.intersectBox(e,Zn)},intersectTriangle:function(e,t,n,i,r){$n.subVectors(t,e),ei.subVectors(n,e),ti.crossVectors($n,ei);var a,o=this.direction.dot(ti);if(o>0){if(i)return null;a=1}else{if(!(o<0))return null;a=-1,o=-o}Kn.subVectors(this.origin,e);var s=a*this.direction.dot(ei.crossVectors(Kn,ei));if(s<0)return null;var c=a*this.direction.dot($n.cross(Kn));if(c<0)return null;if(s+c>o)return null;var l=-a*Kn.dot(ti);return l<0?null:this.at(l/o,r)},applyMatrix4:function(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this},equals:function(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}});var ii=new rn,ri=new rn,ai=new Xt;function oi(e,t){this.normal=void 0!==e?e:new rn(1,0,0),this.constant=void 0!==t?t:0}Object.assign(oi.prototype,{isPlane:!0,set:function(e,t){return this.normal.copy(e),this.constant=t,this},setComponents:function(e,t,n,i){return this.normal.set(e,t,n),this.constant=i,this},setFromNormalAndCoplanarPoint:function(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this},setFromCoplanarPoints:function(e,t,n){var i=ii.subVectors(n,t).cross(ri.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(i,e),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.normal.copy(e.normal),this.constant=e.constant,this},normalize:function(){var e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this},negate:function(){return this.constant*=-1,this.normal.negate(),this},distanceToPoint:function(e){return this.normal.dot(e)+this.constant},distanceToSphere:function(e){return this.distanceToPoint(e.center)-e.radius},projectPoint:function(e,t){return void 0===t&&(console.warn("THREE.Plane: .projectPoint() target is now required"),t=new rn),t.copy(this.normal).multiplyScalar(-this.distanceToPoint(e)).add(e)},intersectLine:function(e,t){void 0===t&&(console.warn("THREE.Plane: .intersectLine() target is now required"),t=new rn);var n=e.delta(ii),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(e.start)?t.copy(e.start):void 0;var r=-(e.start.dot(this.normal)+this.constant)/i;return r<0||r>1?void 0:t.copy(n).multiplyScalar(r).add(e.start)},intersectsLine:function(e){var t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0},intersectsBox:function(e){return e.intersectsPlane(this)},intersectsSphere:function(e){return e.intersectsPlane(this)},coplanarPoint:function(e){return void 0===e&&(console.warn("THREE.Plane: .coplanarPoint() target is now required"),e=new rn),e.copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(e,t){var n=t||ai.getNormalMatrix(e),i=this.coplanarPoint(ii).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this},translate:function(e){return this.constant-=e.dot(this.normal),this},equals:function(e){return e.normal.equals(this.normal)&&e.constant===this.constant}});var si=new rn,ci=new rn,li=new rn,hi=new rn,ui=new rn,pi=new rn,di=new rn,fi=new rn,mi=new rn,gi=new rn;function vi(e,t,n){this.a=void 0!==e?e:new rn,this.b=void 0!==t?t:new rn,this.c=void 0!==n?n:new rn}Object.assign(vi,{getNormal:function(e,t,n,i){void 0===i&&(console.warn("THREE.Triangle: .getNormal() target is now required"),i=new rn),i.subVectors(n,t),si.subVectors(e,t),i.cross(si);var r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)},getBarycoord:function(e,t,n,i,r){si.subVectors(i,t),ci.subVectors(n,t),li.subVectors(e,t);var a=si.dot(si),o=si.dot(ci),s=si.dot(li),c=ci.dot(ci),l=ci.dot(li),h=a*c-o*o;if(void 0===r&&(console.warn("THREE.Triangle: .getBarycoord() target is now required"),r=new rn),0===h)return r.set(-2,-1,-1);var u=1/h,p=(c*s-o*l)*u,d=(a*l-o*s)*u;return r.set(1-p-d,d,p)},containsPoint:function(e,t,n,i){return vi.getBarycoord(e,t,n,i,hi),hi.x>=0&&hi.y>=0&&hi.x+hi.y<=1},getUV:function(e,t,n,i,r,a,o,s){return this.getBarycoord(e,t,n,i,hi),s.set(0,0),s.addScaledVector(r,hi.x),s.addScaledVector(a,hi.y),s.addScaledVector(o,hi.z),s},isFrontFacing:function(e,t,n,i){return si.subVectors(n,t),ci.subVectors(e,t),si.cross(ci).dot(i)<0}}),Object.assign(vi.prototype,{set:function(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this},setFromPointsAndIndices:function(e,t,n,i){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[i]),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this},getArea:function(){return si.subVectors(this.c,this.b),ci.subVectors(this.a,this.b),.5*si.cross(ci).length()},getMidpoint:function(e){return void 0===e&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),e=new rn),e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},getNormal:function(e){return vi.getNormal(this.a,this.b,this.c,e)},getPlane:function(e){return void 0===e&&(console.warn("THREE.Triangle: .getPlane() target is now required"),e=new oi),e.setFromCoplanarPoints(this.a,this.b,this.c)},getBarycoord:function(e,t){return vi.getBarycoord(e,this.a,this.b,this.c,t)},getUV:function(e,t,n,i,r){return vi.getUV(e,this.a,this.b,this.c,t,n,i,r)},containsPoint:function(e){return vi.containsPoint(e,this.a,this.b,this.c)},isFrontFacing:function(e){return vi.isFrontFacing(this.a,this.b,this.c,e)},intersectsBox:function(e){return e.intersectsTriangle(this)},closestPointToPoint:function(e,t){void 0===t&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),t=new rn);var n,i,r=this.a,a=this.b,o=this.c;ui.subVectors(a,r),pi.subVectors(o,r),fi.subVectors(e,r);var s=ui.dot(fi),c=pi.dot(fi);if(s<=0&&c<=0)return t.copy(r);mi.subVectors(e,a);var l=ui.dot(mi),h=pi.dot(mi);if(l>=0&&h<=l)return t.copy(a);var u=s*h-l*c;if(u<=0&&s>=0&&l<=0)return n=s/(s-l),t.copy(r).addScaledVector(ui,n);gi.subVectors(e,o);var p=ui.dot(gi),d=pi.dot(gi);if(d>=0&&p<=d)return t.copy(o);var f=p*c-s*d;if(f<=0&&c>=0&&d<=0)return i=c/(c-d),t.copy(r).addScaledVector(pi,i);var m=l*d-p*h;if(m<=0&&h-l>=0&&p-d>=0)return di.subVectors(o,a),i=(h-l)/(h-l+(p-d)),t.copy(a).addScaledVector(di,i);var g=1/(m+f+u);return n=f*g,i=u*g,t.copy(r).addScaledVector(ui,n).addScaledVector(pi,i)},equals:function(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}});var yi={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},xi={h:0,s:0,l:0},bi={h:0,s:0,l:0};function _i(e,t,n){return void 0===t&&void 0===n?this.set(e):this.setRGB(e,t,n)}function wi(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+6*(t-e)*(2/3-n):e}function Mi(e){return e<.04045?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function Si(e){return e<.0031308?12.92*e:1.055*Math.pow(e,.41666)-.055}function Ti(e,t,n,i,r,a){this.a=e,this.b=t,this.c=n,this.normal=i&&i.isVector3?i:new rn,this.vertexNormals=Array.isArray(i)?i:[],this.color=r&&r.isColor?r:new _i,this.vertexColors=Array.isArray(r)?r:[],this.materialIndex=void 0!==a?a:0}Object.assign(_i.prototype,{isColor:!0,r:1,g:1,b:1,set:function(e){return e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e),this},setScalar:function(e){return this.r=e,this.g=e,this.b=e,this},setHex:function(e){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(255&e)/255,this},setRGB:function(e,t,n){return this.r=e,this.g=t,this.b=n,this},setHSL:function(e,t,n){if(e=Wt.euclideanModulo(e,1),t=Wt.clamp(t,0,1),n=Wt.clamp(n,0,1),0===t)this.r=this.g=this.b=n;else{var i=n<=.5?n*(1+t):n+t-n*t,r=2*n-i;this.r=wi(r,i,e+1/3),this.g=wi(r,i,e),this.b=wi(r,i,e-1/3)}return this},setStyle:function(e){function t(t){void 0!==t&&parseFloat(t)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}var n;if(n=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(e)){var i,r=n[1],a=n[2];switch(r){case"rgb":case"rgba":if(i=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(255,parseInt(i[1],10))/255,this.g=Math.min(255,parseInt(i[2],10))/255,this.b=Math.min(255,parseInt(i[3],10))/255,t(i[5]),this;if(i=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(100,parseInt(i[1],10))/100,this.g=Math.min(100,parseInt(i[2],10))/100,this.b=Math.min(100,parseInt(i[3],10))/100,t(i[5]),this;break;case"hsl":case"hsla":if(i=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a)){var o=parseFloat(i[1])/360,s=parseInt(i[2],10)/100,c=parseInt(i[3],10)/100;return t(i[5]),this.setHSL(o,s,c)}}}else if(n=/^\#([A-Fa-f0-9]+)$/.exec(e)){var l=n[1],h=l.length;if(3===h)return this.r=parseInt(l.charAt(0)+l.charAt(0),16)/255,this.g=parseInt(l.charAt(1)+l.charAt(1),16)/255,this.b=parseInt(l.charAt(2)+l.charAt(2),16)/255,this;if(6===h)return this.r=parseInt(l.charAt(0)+l.charAt(1),16)/255,this.g=parseInt(l.charAt(2)+l.charAt(3),16)/255,this.b=parseInt(l.charAt(4)+l.charAt(5),16)/255,this}return e&&e.length>0?this.setColorName(e):this},setColorName:function(e){var t=yi[e];return void 0!==t?this.setHex(t):console.warn("THREE.Color: Unknown color "+e),this},clone:function(){return new this.constructor(this.r,this.g,this.b)},copy:function(e){return this.r=e.r,this.g=e.g,this.b=e.b,this},copyGammaToLinear:function(e,t){return void 0===t&&(t=2),this.r=Math.pow(e.r,t),this.g=Math.pow(e.g,t),this.b=Math.pow(e.b,t),this},copyLinearToGamma:function(e,t){void 0===t&&(t=2);var n=t>0?1/t:1;return this.r=Math.pow(e.r,n),this.g=Math.pow(e.g,n),this.b=Math.pow(e.b,n),this},convertGammaToLinear:function(e){return this.copyGammaToLinear(this,e),this},convertLinearToGamma:function(e){return this.copyLinearToGamma(this,e),this},copySRGBToLinear:function(e){return this.r=Mi(e.r),this.g=Mi(e.g),this.b=Mi(e.b),this},copyLinearToSRGB:function(e){return this.r=Si(e.r),this.g=Si(e.g),this.b=Si(e.b),this},convertSRGBToLinear:function(){return this.copySRGBToLinear(this),this},convertLinearToSRGB:function(){return this.copyLinearToSRGB(this),this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(e){void 0===e&&(console.warn("THREE.Color: .getHSL() target is now required"),e={h:0,s:0,l:0});var t,n,i=this.r,r=this.g,a=this.b,o=Math.max(i,r,a),s=Math.min(i,r,a),c=(s+o)/2;if(s===o)t=0,n=0;else{var l=o-s;switch(n=c<=.5?l/(o+s):l/(2-o-s),o){case i:t=(r-a)/l+(r0&&(n.alphaTest=this.alphaTest),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=this.premultipliedAlpha),!0===this.wireframe&&(n.wireframe=this.wireframe),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.morphTargets&&(n.morphTargets=!0),!0===this.morphNormals&&(n.morphNormals=!0),!0===this.skinning&&(n.skinning=!0),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),"{}"!==JSON.stringify(this.userData)&&(n.userData=this.userData),t){var r=i(e.textures),a=i(e.images);r.length>0&&(n.textures=r),a.length>0&&(n.images=a)}return n},clone:function(){return(new this.constructor).copy(this)},copy:function(e){this.name=e.name,this.fog=e.fog,this.blending=e.blending,this.side=e.side,this.flatShading=e.flatShading,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;var t=e.clippingPlanes,n=null;if(null!==t){var i=t.length;n=new Array(i);for(var r=0;r!==i;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.premultipliedAlpha=e.premultipliedAlpha,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),Object.defineProperty(Ai.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Li.prototype=Object.create(Ai.prototype),Li.prototype.constructor=Li,Li.prototype.isMeshBasicMaterial=!0,Li.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this};var Ri=new rn;function Pi(e,t,n){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.name="",this.array=e,this.itemSize=t,this.count=void 0!==e?e.length/t:0,this.normalized=!0===n,this.usage=Ut,this.updateRange={offset:0,count:-1},this.version=0}function Ci(e,t,n){Pi.call(this,new Int8Array(e),t,n)}function Oi(e,t,n){Pi.call(this,new Uint8Array(e),t,n)}function Di(e,t,n){Pi.call(this,new Uint8ClampedArray(e),t,n)}function Ii(e,t,n){Pi.call(this,new Int16Array(e),t,n)}function Ni(e,t,n){Pi.call(this,new Uint16Array(e),t,n)}function Bi(e,t,n){Pi.call(this,new Int32Array(e),t,n)}function zi(e,t,n){Pi.call(this,new Uint32Array(e),t,n)}function Fi(e,t,n){Pi.call(this,new Float32Array(e),t,n)}function Ui(e,t,n){Pi.call(this,new Float64Array(e),t,n)}function Gi(){this.vertices=[],this.normals=[],this.colors=[],this.uvs=[],this.uvs2=[],this.groups=[],this.morphTargets={},this.skinWeights=[],this.skinIndices=[],this.boundingBox=null,this.boundingSphere=null,this.verticesNeedUpdate=!1,this.normalsNeedUpdate=!1,this.colorsNeedUpdate=!1,this.uvsNeedUpdate=!1,this.groupsNeedUpdate=!1}function Hi(e){if(0===e.length)return-1/0;for(var t=e[0],n=1,i=e.length;nt&&(t=e[n]);return t}Object.defineProperty(Pi.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.assign(Pi.prototype,{isBufferAttribute:!0,onUploadCallback:function(){},setUsage:function(e){return this.usage=e,this},copy:function(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this},copyAt:function(e,t,n){e*=this.itemSize,n*=t.itemSize;for(var i=0,r=this.itemSize;i0,o=r[1]&&r[1].length>0,s=e.morphTargets,c=s.length;if(c>0){t=[];for(var l=0;l0){h=[];for(l=0;l0&&0===n.length&&console.error("THREE.DirectGeometry: Faceless geometries are not supported.");for(l=0;l65535?zi:Ni)(e,1):this.index=e},getAttribute:function(e){return this.attributes[e]},setAttribute:function(e,t){return this.attributes[e]=t,this},deleteAttribute:function(e){return delete this.attributes[e],this},addGroup:function(e,t,n){this.groups.push({start:e,count:t,materialIndex:void 0!==n?n:0})},clearGroups:function(){this.groups=[]},setDrawRange:function(e,t){this.drawRange.start=e,this.drawRange.count=t},applyMatrix4:function(e){var t=this.attributes.position;void 0!==t&&(t.applyMatrix4(e),t.needsUpdate=!0);var n=this.attributes.normal;if(void 0!==n){var i=(new Xt).getNormalMatrix(e);n.applyNormalMatrix(i),n.needsUpdate=!0}var r=this.attributes.tangent;return void 0!==r&&(r.transformDirection(e),r.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},rotateX:function(e){return ki.makeRotationX(e),this.applyMatrix4(ki),this},rotateY:function(e){return ki.makeRotationY(e),this.applyMatrix4(ki),this},rotateZ:function(e){return ki.makeRotationZ(e),this.applyMatrix4(ki),this},translate:function(e,t,n){return ki.makeTranslation(e,t,n),this.applyMatrix4(ki),this},scale:function(e,t,n){return ki.makeScale(e,t,n),this.applyMatrix4(ki),this},lookAt:function(e){return ji.lookAt(e),ji.updateMatrix(),this.applyMatrix4(ji.matrix),this},center:function(){return this.computeBoundingBox(),this.boundingBox.getCenter(Wi).negate(),this.translate(Wi.x,Wi.y,Wi.z),this},setFromObject:function(e){var t=e.geometry;if(e.isPoints||e.isLine){var n=new Fi(3*t.vertices.length,3),i=new Fi(3*t.colors.length,3);if(this.setAttribute("position",n.copyVector3sArray(t.vertices)),this.setAttribute("color",i.copyColorsArray(t.colors)),t.lineDistances&&t.lineDistances.length===t.vertices.length){var r=new Fi(t.lineDistances.length,1);this.setAttribute("lineDistance",r.copyArray(t.lineDistances))}null!==t.boundingSphere&&(this.boundingSphere=t.boundingSphere.clone()),null!==t.boundingBox&&(this.boundingBox=t.boundingBox.clone())}else e.isMesh&&t&&t.isGeometry&&this.fromGeometry(t);return this},setFromPoints:function(e){for(var t=[],n=0,i=e.length;n0){var n=new Float32Array(3*e.normals.length);this.setAttribute("normal",new Pi(n,3).copyVector3sArray(e.normals))}if(e.colors.length>0){var i=new Float32Array(3*e.colors.length);this.setAttribute("color",new Pi(i,3).copyColorsArray(e.colors))}if(e.uvs.length>0){var r=new Float32Array(2*e.uvs.length);this.setAttribute("uv",new Pi(r,2).copyVector2sArray(e.uvs))}if(e.uvs2.length>0){var a=new Float32Array(2*e.uvs2.length);this.setAttribute("uv2",new Pi(a,2).copyVector2sArray(e.uvs2))}for(var o in this.groups=e.groups,e.morphTargets){for(var s=[],c=e.morphTargets[o],l=0,h=c.length;l0){var d=new Fi(4*e.skinIndices.length,4);this.setAttribute("skinIndex",d.copyVector4sArray(e.skinIndices))}if(e.skinWeights.length>0){var f=new Fi(4*e.skinWeights.length,4);this.setAttribute("skinWeight",f.copyVector4sArray(e.skinWeights))}return null!==e.boundingSphere&&(this.boundingSphere=e.boundingSphere.clone()),null!==e.boundingBox&&(this.boundingBox=e.boundingBox.clone()),this},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new Wn);var e=this.attributes.position,t=this.morphAttributes.position;if(void 0!==e){if(this.boundingBox.setFromBufferAttribute(e),t)for(var n=0,i=t.length;n0&&(e.userData=this.userData),void 0!==this.parameters){var t=this.parameters;for(var n in t)void 0!==t[n]&&(e[n]=t[n]);return e}e.data={attributes:{}};var i=this.index;null!==i&&(e.data.index={type:i.array.constructor.name,array:Array.prototype.slice.call(i.array)});var r=this.attributes;for(var n in r){var a=(p=r[n]).toJSON();""!==p.name&&(a.name=p.name),e.data.attributes[n]=a}var o={},s=!1;for(var n in this.morphAttributes){for(var c=this.morphAttributes[n],l=[],h=0,u=c.length;h0&&(o[n]=l,s=!0)}s&&(e.data.morphAttributes=o,e.data.morphTargetsRelative=this.morphTargetsRelative);var d=this.groups;d.length>0&&(e.data.groups=JSON.parse(JSON.stringify(d)));var f=this.boundingSphere;return null!==f&&(e.data.boundingSphere={center:f.center.toArray(),radius:f.radius}),e},clone:function(){return(new Zi).copy(this)},copy:function(e){var t,n,i;this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.name=e.name;var r=e.index;null!==r&&this.setIndex(r.clone());var a=e.attributes;for(t in a){var o=a[t];this.setAttribute(t,o.clone())}var s=e.morphAttributes;for(t in s){var c=[],l=s[t];for(n=0,i=l.length;nn.far?null:{distance:h,point:pr.clone(),object:e}}function mr(e,t,n,i,r,a,o,s,c,l,h,u){$i.fromBufferAttribute(r,l),er.fromBufferAttribute(r,h),tr.fromBufferAttribute(r,u);var p=e.morphTargetInfluences;if(t.morphTargets&&a&&p){ar.set(0,0,0),or.set(0,0,0),sr.set(0,0,0);for(var d=0,f=a.length;d0){var o=r[a[0]];if(void 0!==o)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},e=0,t=o.length;e0&&console.error("THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}},raycast:function(e,t){var n,i=this.geometry,r=this.material,a=this.matrixWorld;if(void 0!==r&&(null===i.boundingSphere&&i.computeBoundingSphere(),Ki.copy(i.boundingSphere),Ki.applyMatrix4(a),!1!==e.ray.intersectsSphere(Ki)&&(Ji.getInverse(a),Qi.copy(e.ray).applyMatrix4(Ji),null===i.boundingBox||!1!==Qi.intersectsBox(i.boundingBox))))if(i.isBufferGeometry){var o,s,c,l,h,u,p,d,f,m=i.index,g=i.attributes.position,v=i.morphAttributes.position,y=i.morphTargetsRelative,x=i.attributes.uv,b=i.attributes.uv2,_=i.groups,w=i.drawRange;if(null!==m)if(Array.isArray(r))for(l=0,u=_.length;l0&&(E=P);for(var C=0,O=R.length;C0)for(l=0;l0&&(this.normalsNeedUpdate=!0)},computeFlatVertexNormals:function(){var e,t,n;for(this.computeFaceNormals(),e=0,t=this.faces.length;e0&&(this.normalsNeedUpdate=!0)},computeMorphNormals:function(){var e,t,n,i,r;for(n=0,i=this.faces.length;n=0;n--){var f=p[n];for(this.faces.splice(f,1),o=0,s=this.faceVertexUvs.length;o0,g=d.vertexNormals.length>0,v=1!==d.color.r||1!==d.color.g||1!==d.color.b,y=d.vertexColors.length>0,x=0;if(x=M(x,0,0),x=M(x,1,!0),x=M(x,2,!1),x=M(x,3,f),x=M(x,4,m),x=M(x,5,g),x=M(x,6,v),x=M(x,7,y),o.push(x),o.push(d.a,d.b,d.c),o.push(d.materialIndex),f){var b=this.faceVertexUvs[0][r];o.push(E(b[0]),E(b[1]),E(b[2]))}if(m&&o.push(S(d.normal)),g){var _=d.vertexNormals;o.push(S(_[0]),S(_[1]),S(_[2]))}if(v&&o.push(T(d.color)),y){var w=d.vertexColors;o.push(T(w[0]),T(w[1]),T(w[2]))}}function M(e,t,n){return n?e|1<0&&(e.data.colors=l),u.length>0&&(e.data.uvs=[u]),e.data.faces=o,e},clone:function(){return(new br).copy(this)},copy:function(e){var t,n,i,r,a,o;this.vertices=[],this.colors=[],this.faces=[],this.faceVertexUvs=[[]],this.morphTargets=[],this.morphNormals=[],this.skinWeights=[],this.skinIndices=[],this.lineDistances=[],this.boundingBox=null,this.boundingSphere=null,this.name=e.name;var s=e.vertices;for(t=0,n=s.length;t0?1:-1,h.push(R.x,R.y,R.z),u.push(y/m),u.push(1-x/g),A+=1}}for(x=0;x0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader;var r={};for(var a in this.extensions)!0===this.extensions[a]&&(r[a]=!0);return Object.keys(r).length>0&&(t.extensions=r),t},Rr.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Rr,isCamera:!0,copy:function(e,t){return Pn.prototype.copy.call(this,e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this},getWorldDirection:function(e){void 0===e&&(console.warn("THREE.Camera: .getWorldDirection() target is now required"),e=new rn),this.updateMatrixWorld(!0);var t=this.matrixWorld.elements;return e.set(-t[8],-t[9],-t[10]).normalize()},updateMatrixWorld:function(e){Pn.prototype.updateMatrixWorld.call(this,e),this.matrixWorldInverse.getInverse(this.matrixWorld)},updateWorldMatrix:function(e,t){Pn.prototype.updateWorldMatrix.call(this,e,t),this.matrixWorldInverse.getInverse(this.matrixWorld)},clone:function(){return(new this.constructor).copy(this)}}),Pr.prototype=Object.assign(Object.create(Rr.prototype),{constructor:Pr,isPerspectiveCamera:!0,copy:function(e,t){return Rr.prototype.copy.call(this,e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=null===e.view?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this},setFocalLength:function(e){var t=.5*this.getFilmHeight()/e;this.fov=2*Wt.RAD2DEG*Math.atan(t),this.updateProjectionMatrix()},getFocalLength:function(){var e=Math.tan(.5*Wt.DEG2RAD*this.fov);return.5*this.getFilmHeight()/e},getEffectiveFOV:function(){return 2*Wt.RAD2DEG*Math.atan(Math.tan(.5*Wt.DEG2RAD*this.fov)/this.zoom)},getFilmWidth:function(){return this.filmGauge*Math.min(this.aspect,1)},getFilmHeight:function(){return this.filmGauge/Math.max(this.aspect,1)},setViewOffset:function(e,t,n,i,r,a){this.aspect=e/t,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()},clearViewOffset:function(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()},updateProjectionMatrix:function(){var e=this.near,t=e*Math.tan(.5*Wt.DEG2RAD*this.fov)/this.zoom,n=2*t,i=this.aspect*n,r=-.5*i,a=this.view;if(null!==this.view&&this.view.enabled){var o=a.fullWidth,s=a.fullHeight;r+=a.offsetX*i/o,t-=a.offsetY*n/s,i*=a.width/o,n*=a.height/s}var c=this.filmOffset;0!==c&&(r+=e*c/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-n,e,this.far),this.projectionMatrixInverse.getInverse(this.projectionMatrix)},toJSON:function(e){var t=Pn.prototype.toJSON.call(this,e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,null!==this.view&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}});var Cr=90,Or=1;function Dr(e,t,n,i){Pn.call(this),this.type="CubeCamera";var r=new Pr(Cr,Or,e,t);r.up.set(0,-1,0),r.lookAt(new rn(1,0,0)),this.add(r);var a=new Pr(Cr,Or,e,t);a.up.set(0,-1,0),a.lookAt(new rn(-1,0,0)),this.add(a);var o=new Pr(Cr,Or,e,t);o.up.set(0,0,1),o.lookAt(new rn(0,1,0)),this.add(o);var s=new Pr(Cr,Or,e,t);s.up.set(0,0,-1),s.lookAt(new rn(0,-1,0)),this.add(s);var c=new Pr(Cr,Or,e,t);c.up.set(0,-1,0),c.lookAt(new rn(0,0,1)),this.add(c);var l=new Pr(Cr,Or,e,t);l.up.set(0,-1,0),l.lookAt(new rn(0,0,-1)),this.add(l),i=i||{format:Se,magFilter:ce,minFilter:ce},this.renderTarget=new Ir(n,i),this.renderTarget.texture.name="CubeCamera",this.update=function(e,t){null===this.parent&&this.updateMatrixWorld();var n=e.getRenderTarget(),i=this.renderTarget,h=i.texture.generateMipmaps;i.texture.generateMipmaps=!1,e.setRenderTarget(i,0),e.render(t,r),e.setRenderTarget(i,1),e.render(t,a),e.setRenderTarget(i,2),e.render(t,o),e.setRenderTarget(i,3),e.render(t,s),e.setRenderTarget(i,4),e.render(t,c),i.texture.generateMipmaps=h,e.setRenderTarget(i,5),e.render(t,l),e.setRenderTarget(n)},this.clear=function(e,t,n,i){for(var r=e.getRenderTarget(),a=this.renderTarget,o=0;o<6;o++)e.setRenderTarget(a,o),e.clear(t,n,i);e.setRenderTarget(r)}}function Ir(e,t,n){Number.isInteger(t)&&(console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"),t=n),Kt.call(this,e,e,t)}function Nr(e,t,n,i,r,a,o,s,c,l,h,u){Jt.call(this,null,a,o,s,c,l,i,r,h,u),this.image={data:e||null,width:t||1,height:n||1},this.magFilter=void 0!==c?c:ae,this.minFilter=void 0!==l?l:ae,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1,this.needsUpdate=!0}Dr.prototype=Object.create(Pn.prototype),Dr.prototype.constructor=Dr,Ir.prototype=Object.create(Kt.prototype),Ir.prototype.constructor=Ir,Ir.prototype.isWebGLCubeRenderTarget=!0,Ir.prototype.fromEquirectangularTexture=function(e,t){this.texture.type=t.type,this.texture.format=t.format,this.texture.encoding=t.encoding;var n=new Cn,i={uniforms:{tEquirect:{value:null}},vertexShader:["varying vec3 vWorldDirection;","vec3 transformDirection( in vec3 dir, in mat4 matrix ) {","\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );","}","void main() {","\tvWorldDirection = transformDirection( position, modelMatrix );","\t#include ","\t#include ","}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;","varying vec3 vWorldDirection;","#define RECIPROCAL_PI 0.31830988618","#define RECIPROCAL_PI2 0.15915494","void main() {","\tvec3 direction = normalize( vWorldDirection );","\tvec2 sampleUV;","\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;","\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;","\tgl_FragColor = texture2D( tEquirect, sampleUV );","}"].join("\n")},r=new Lr({type:"CubemapFromEquirect",uniforms:Mr(i.uniforms),vertexShader:i.vertexShader,fragmentShader:i.fragmentShader,side:c,blending:h});r.uniforms.tEquirect.value=t;var a=new dr(new wr(5,5,5),r);n.add(a);var o=new Dr(1,10,1);return o.renderTarget=this,o.renderTarget.texture.name="CubeCameraTexture",o.update(e,n),a.geometry.dispose(),a.material.dispose(),this},Nr.prototype=Object.create(Jt.prototype),Nr.prototype.constructor=Nr,Nr.prototype.isDataTexture=!0;var Br=new Yn,zr=new rn;function Fr(e,t,n,i,r,a){this.planes=[void 0!==e?e:new oi,void 0!==t?t:new oi,void 0!==n?n:new oi,void 0!==i?i:new oi,void 0!==r?r:new oi,void 0!==a?a:new oi]}Object.assign(Fr.prototype,{set:function(e,t,n,i,r,a){var o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(i),o[4].copy(r),o[5].copy(a),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){for(var t=this.planes,n=0;n<6;n++)t[n].copy(e.planes[n]);return this},setFromProjectionMatrix:function(e){var t=this.planes,n=e.elements,i=n[0],r=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],h=n[7],u=n[8],p=n[9],d=n[10],f=n[11],m=n[12],g=n[13],v=n[14],y=n[15];return t[0].setComponents(o-i,h-s,f-u,y-m).normalize(),t[1].setComponents(o+i,h+s,f+u,y+m).normalize(),t[2].setComponents(o+r,h+c,f+p,y+g).normalize(),t[3].setComponents(o-r,h-c,f-p,y-g).normalize(),t[4].setComponents(o-a,h-l,f-d,y-v).normalize(),t[5].setComponents(o+a,h+l,f+d,y+v).normalize(),this},intersectsObject:function(e){var t=e.geometry;return null===t.boundingSphere&&t.computeBoundingSphere(),Br.copy(t.boundingSphere).applyMatrix4(e.matrixWorld),this.intersectsSphere(Br)},intersectsSprite:function(e){return Br.center.set(0,0,0),Br.radius=.7071067811865476,Br.applyMatrix4(e.matrixWorld),this.intersectsSphere(Br)},intersectsSphere:function(e){for(var t=this.planes,n=e.center,i=-e.radius,r=0;r<6;r++){if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,zr.y=i.normal.y>0?e.max.y:e.min.y,zr.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(zr)<0)return!1}return!0},containsPoint:function(e){for(var t=this.planes,n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}});var Ur={common:{diffuse:{value:new _i(15658734)},opacity:{value:1},map:{value:null},uvTransform:{value:new Xt},uv2Transform:{value:new Xt},alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new qt(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new _i(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new _i(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},uvTransform:{value:new Xt}},sprite:{diffuse:{value:new _i(15658734)},opacity:{value:1},center:{value:new qt(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null},uvTransform:{value:new Xt}}};function Gr(){var e=null,t=!1,n=null;function i(r,a){!1!==t&&(n(r,a),e.requestAnimationFrame(i))}return{start:function(){!0!==t&&null!==n&&(e.requestAnimationFrame(i),t=!0)},stop:function(){t=!1},setAnimationLoop:function(e){n=e},setContext:function(t){e=t}}}function Hr(e,t){var n=t.isWebGL2,i=new WeakMap;return{get:function(e){return e.isInterleavedBufferAttribute&&(e=e.data),i.get(e)},remove:function(t){t.isInterleavedBufferAttribute&&(t=t.data);var n=i.get(t);n&&(e.deleteBuffer(n.buffer),i.delete(t))},update:function(t,r){t.isInterleavedBufferAttribute&&(t=t.data);var a=i.get(t);void 0===a?i.set(t,function(t,n){var i=t.array,r=t.usage,a=e.createBuffer();e.bindBuffer(n,a),e.bufferData(n,i,r),t.onUploadCallback();var o=5126;return i instanceof Float32Array?o=5126:i instanceof Float64Array?console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array."):i instanceof Uint16Array?o=5123:i instanceof Int16Array?o=5122:i instanceof Uint32Array?o=5125:i instanceof Int32Array?o=5124:i instanceof Int8Array?o=5120:i instanceof Uint8Array&&(o=5121),{buffer:a,type:o,bytesPerElement:i.BYTES_PER_ELEMENT,version:t.version}}(t,r)):a.version 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\tvarying vec3 vViewPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP ) && ! defined( TOON )\n\tvViewPosition = - mvPosition.xyz;\n#endif",color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == - 1.0;\n}",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_maxMipLevel 8.0\n#define cubeUV_minMipLevel 4.0\n#define cubeUV_maxTileSize 256.0\n#define cubeUV_minTileSize 16.0\nfloat getFace(vec3 direction) {\n vec3 absDirection = abs(direction);\n float face = -1.0;\n if (absDirection.x > absDirection.z) {\n if (absDirection.x > absDirection.y)\n face = direction.x > 0.0 ? 0.0 : 3.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n } else {\n if (absDirection.z > absDirection.y)\n face = direction.z > 0.0 ? 2.0 : 5.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n }\n return face;\n}\nvec2 getUV(vec3 direction, float face) {\n vec2 uv;\n if (face == 0.0) {\n uv = vec2(-direction.z, direction.y) / abs(direction.x);\n } else if (face == 1.0) {\n uv = vec2(direction.x, -direction.z) / abs(direction.y);\n } else if (face == 2.0) {\n uv = direction.xy / abs(direction.z);\n } else if (face == 3.0) {\n uv = vec2(direction.z, direction.y) / abs(direction.x);\n } else if (face == 4.0) {\n uv = direction.xz / abs(direction.y);\n } else {\n uv = vec2(-direction.x, direction.y) / abs(direction.z);\n }\n return 0.5 * (uv + 1.0);\n}\nvec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {\n float face = getFace(direction);\n float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);\n mipInt = max(mipInt, cubeUV_minMipLevel);\n float faceSize = exp2(mipInt);\n float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);\n vec2 uv = getUV(direction, face) * (faceSize - 1.0);\n vec2 f = fract(uv);\n uv += 0.5 - f;\n if (face > 2.0) {\n uv.y += faceSize;\n face -= 3.0;\n }\n uv.x += face * faceSize;\n if(mipInt < cubeUV_maxMipLevel){\n uv.y += 2.0 * cubeUV_maxTileSize;\n }\n uv.y += filterInt * 2.0 * cubeUV_minTileSize;\n uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);\n uv *= texelSize;\n vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x += texelSize;\n vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.y += texelSize;\n vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x -= texelSize;\n vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n vec3 tm = mix(tl, tr, f.x);\n vec3 bm = mix(bl, br, f.x);\n return mix(tm, bm, f.y);\n}\n#define r0 1.0\n#define v0 0.339\n#define m0 -2.0\n#define r1 0.8\n#define v1 0.276\n#define m1 -1.0\n#define r4 0.4\n#define v4 0.046\n#define m4 2.0\n#define r5 0.305\n#define v5 0.016\n#define m5 3.0\n#define r6 0.21\n#define v6 0.0038\n#define m6 4.0\nfloat roughnessToMip(float roughness) {\n float mip = 0.0;\n if (roughness >= r1) {\n mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;\n } else if (roughness >= r4) {\n mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;\n } else if (roughness >= r5) {\n mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;\n } else if (roughness >= r6) {\n mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;\n } else {\n mip = -2.0 * log2(1.16 * roughness); }\n return mip;\n}\nvec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) {\n float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel);\n float mipF = fract(mip);\n float mipInt = floor(mip);\n vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt);\n if (mipF == 0.0) {\n return vec4(color0, 1.0);\n } else {\n vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0);\n return vec4(mix(color0, color1, mipF), 1.0);\n }\n}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\t\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t vec3 reflectVec = reflect( -viewDir, normal );\n\t\t reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t vec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) { \n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = saturate( clearcoat );\tmaterial.clearcoatRoughness = max( clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif",normal_fragment_begin:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;",normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif",clearcoat_normalmap_pars_fragment:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );\n}",uv_pars_fragment:"#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSPARENCY\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSPARENCY\n\tuniform float transparency;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSPARENCY\n\t\tdiffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}",normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"},Wr={basic:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.fog]),vertexShader:jr.meshbasic_vert,fragmentShader:jr.meshbasic_frag},lambert:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)}}]),vertexShader:jr.meshlambert_vert,fragmentShader:jr.meshlambert_frag},phong:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},specular:{value:new _i(1118481)},shininess:{value:30}}]),vertexShader:jr.meshphong_vert,fragmentShader:jr.meshphong_frag},standard:{uniforms:Sr([Ur.common,Ur.envmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.roughnessmap,Ur.metalnessmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:jr.meshphysical_vert,fragmentShader:jr.meshphysical_frag},toon:{uniforms:Sr([Ur.common,Ur.specularmap,Ur.aomap,Ur.lightmap,Ur.emissivemap,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.gradientmap,Ur.fog,Ur.lights,{emissive:{value:new _i(0)},specular:{value:new _i(1118481)},shininess:{value:30}}]),vertexShader:jr.meshtoon_vert,fragmentShader:jr.meshtoon_frag},matcap:{uniforms:Sr([Ur.common,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,Ur.fog,{matcap:{value:null}}]),vertexShader:jr.meshmatcap_vert,fragmentShader:jr.meshmatcap_frag},points:{uniforms:Sr([Ur.points,Ur.fog]),vertexShader:jr.points_vert,fragmentShader:jr.points_frag},dashed:{uniforms:Sr([Ur.common,Ur.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:jr.linedashed_vert,fragmentShader:jr.linedashed_frag},depth:{uniforms:Sr([Ur.common,Ur.displacementmap]),vertexShader:jr.depth_vert,fragmentShader:jr.depth_frag},normal:{uniforms:Sr([Ur.common,Ur.bumpmap,Ur.normalmap,Ur.displacementmap,{opacity:{value:1}}]),vertexShader:jr.normal_vert,fragmentShader:jr.normal_frag},sprite:{uniforms:Sr([Ur.sprite,Ur.fog]),vertexShader:jr.sprite_vert,fragmentShader:jr.sprite_frag},background:{uniforms:{uvTransform:{value:new Xt},t2D:{value:null}},vertexShader:jr.background_vert,fragmentShader:jr.background_frag},cube:{uniforms:Sr([Ur.envmap,{opacity:{value:1}}]),vertexShader:jr.cube_vert,fragmentShader:jr.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:jr.equirect_vert,fragmentShader:jr.equirect_frag},distanceRGBA:{uniforms:Sr([Ur.common,Ur.displacementmap,{referencePosition:{value:new rn},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:jr.distanceRGBA_vert,fragmentShader:jr.distanceRGBA_frag},shadow:{uniforms:Sr([Ur.lights,Ur.fog,{color:{value:new _i(0)},opacity:{value:1}}]),vertexShader:jr.shadow_vert,fragmentShader:jr.shadow_frag}};function qr(e,t,n,i){var r,a,o=new _i(0),l=0,h=null,u=0,p=null;function d(e,n){t.buffers.color.setClear(e.r,e.g,e.b,n,i)}return{getClearColor:function(){return o},setClearColor:function(e,t){o.set(e),d(o,l=void 0!==t?t:1)},getClearAlpha:function(){return l},setClearAlpha:function(e){d(o,l=e)},render:function(t,i,f,m){var g=i.background,v=e.xr,y=v.getSession&&v.getSession();if(y&&"additive"===y.environmentBlendMode&&(g=null),null===g?d(o,l):g&&g.isColor&&(d(g,1),m=!0),(e.autoClear||m)&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),g&&(g.isCubeTexture||g.isWebGLCubeRenderTarget||g.mapping===ee)){void 0===a&&((a=new dr(new wr(1,1,1),new Lr({type:"BackgroundCubeMaterial",uniforms:Mr(Wr.cube.uniforms),vertexShader:Wr.cube.vertexShader,fragmentShader:Wr.cube.fragmentShader,side:c,depthTest:!1,depthWrite:!1,fog:!1}))).geometry.deleteAttribute("normal"),a.geometry.deleteAttribute("uv"),a.onBeforeRender=function(e,t,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(a.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),n.update(a));var x=g.isWebGLCubeRenderTarget?g.texture:g;a.material.uniforms.envMap.value=x,a.material.uniforms.flipEnvMap.value=x.isCubeTexture?-1:1,h===g&&u===x.version&&p===e.toneMapping||(a.material.needsUpdate=!0,h=g,u=x.version,p=e.toneMapping),t.unshift(a,a.geometry,a.material,0,0,null)}else g&&g.isTexture&&(void 0===r&&((r=new dr(new kr(2,2),new Lr({type:"BackgroundMaterial",uniforms:Mr(Wr.background.uniforms),vertexShader:Wr.background.vertexShader,fragmentShader:Wr.background.fragmentShader,side:s,depthTest:!1,depthWrite:!1,fog:!1}))).geometry.deleteAttribute("normal"),Object.defineProperty(r.material,"map",{get:function(){return this.uniforms.t2D.value}}),n.update(r)),r.material.uniforms.t2D.value=g,!0===g.matrixAutoUpdate&&g.updateMatrix(),r.material.uniforms.uvTransform.value.copy(g.matrix),h===g&&u===g.version&&p===e.toneMapping||(r.material.needsUpdate=!0,h=g,u=g.version,p=e.toneMapping),t.unshift(r,r.geometry,r.material,0,0,null))}}}function Xr(e,t,n,i){var r,a=i.isWebGL2;this.setMode=function(e){r=e},this.render=function(t,i){e.drawArrays(r,t,i),n.update(i,r)},this.renderInstances=function(i,o,s,c){if(0!==c){var l,h;if(a)l=e,h="drawArraysInstanced";else if(h="drawArraysInstancedANGLE",null===(l=t.get("ANGLE_instanced_arrays")))return void console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");l[h](r,o,s,c),n.update(s,r,c)}}}function Yr(e,t,n){var i;function r(t){if("highp"===t){if(e.getShaderPrecisionFormat(35633,36338).precision>0&&e.getShaderPrecisionFormat(35632,36338).precision>0)return"highp";t="mediump"}return"mediump"===t&&e.getShaderPrecisionFormat(35633,36337).precision>0&&e.getShaderPrecisionFormat(35632,36337).precision>0?"mediump":"lowp"}var a="undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext||"undefined"!=typeof WebGL2ComputeRenderingContext&&e instanceof WebGL2ComputeRenderingContext,o=void 0!==n.precision?n.precision:"highp",s=r(o);s!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",s,"instead."),o=s);var c=!0===n.logarithmicDepthBuffer,l=e.getParameter(34930),h=e.getParameter(35660),u=e.getParameter(3379),p=e.getParameter(34076),d=e.getParameter(34921),f=e.getParameter(36347),m=e.getParameter(36348),g=e.getParameter(36349),v=h>0,y=a||!!t.get("OES_texture_float");return{isWebGL2:a,getMaxAnisotropy:function(){if(void 0!==i)return i;var n=t.get("EXT_texture_filter_anisotropic");return i=null!==n?e.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0},getMaxPrecision:r,precision:o,logarithmicDepthBuffer:c,maxTextures:l,maxVertexTextures:h,maxTextureSize:u,maxCubemapSize:p,maxAttributes:d,maxVertexUniforms:f,maxVaryings:m,maxFragmentUniforms:g,vertexTextures:v,floatFragmentTextures:y,floatVertexTextures:v&&y,maxSamples:a?e.getParameter(36183):0}}function Zr(){var e=this,t=null,n=0,i=!1,r=!1,a=new oi,o=new Xt,s={value:null,needsUpdate:!1};function c(){s.value!==t&&(s.value=t,s.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function l(t,n,i,r){var c=null!==t?t.length:0,l=null;if(0!==c){if(l=s.value,!0!==r||null===l){var h=i+4*c,u=n.matrixWorldInverse;o.getNormalMatrix(u),(null===l||l.length65535?zi:Ni)(n,1);d.version=o,t.update(d,34963);var f=r.get(e);f&&t.remove(f),r.set(e,d)}return{get:function(e,t){var r=i.get(t);return r||(t.addEventListener("dispose",a),t.isBufferGeometry?r=t:t.isGeometry&&(void 0===t._bufferGeometry&&(t._bufferGeometry=(new Zi).setFromObject(e)),r=t._bufferGeometry),i.set(t,r),n.memory.geometries++,r)},update:function(e){var n=e.index,i=e.attributes;for(var r in null!==n&&t.update(n,34963),i)t.update(i[r],34962);var a=e.morphAttributes;for(var r in a)for(var o=a[r],s=0,c=o.length;s0)return e;var r=t*n,a=ha[r];if(void 0===a&&(a=new Float32Array(r),ha[r]=a),0!==t){i.toArray(a,0);for(var o=1,s=0;o!==t;++o)s+=n,e[o].toArray(a,s)}return a}function ga(e,t){if(e.length!==t.length)return!1;for(var n=0,i=e.length;n/gm;function uo(e){return e.replace(ho,po)}function po(e,t){var n=jr[t];if(void 0===n)throw new Error("Can not resolve #include <"+t+">");return uo(n)}var fo=/#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;function mo(e){return e.replace(fo,go)}function go(e,t,n,i){for(var r="",a=parseInt(t);a0?e.gammaFactor:1,b=n.isWebGL2?"":function(e){return[e.extensionDerivatives||e.envMapCubeUV||e.bumpMap||e.tangentSpaceNormalMap||e.clearcoatNormalMap||e.flatShading||"physical"===e.shaderID?"#extension GL_OES_standard_derivatives : enable":"",(e.extensionFragDepth||e.logarithmicDepthBuffer)&&e.rendererExtensionFragDepth?"#extension GL_EXT_frag_depth : enable":"",e.extensionDrawBuffers&&e.rendererExtensionDrawBuffers?"#extension GL_EXT_draw_buffers : require":"",(e.extensionShaderTextureLOD||e.envMap)&&e.rendererExtensionShaderTextureLod?"#extension GL_EXT_shader_texture_lod : enable":""].filter(so).join("\n")}(n),_=function(e){var t=[];for(var n in e){var i=e[n];!1!==i&&t.push("#define "+n+" "+i)}return t.join("\n")}(p),w=u.createProgram();if(n.isRawShaderMaterial?((i=[_].filter(so).join("\n")).length>0&&(i+="\n"),(s=[b,_].filter(so).join("\n")).length>0&&(s+="\n")):(i=[vo(n),"#define SHADER_NAME "+n.shaderName,_,n.instancing?"#define USE_INSTANCING":"",n.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+x,"#define MAX_BONES "+n.maxBones,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+v:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.displacementMap&&n.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.useVertexTexture?"#define BONE_TEXTURE":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+m:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(so).join("\n"),s=[b,vo(n),"#define SHADER_NAME "+n.shaderName,_,n.alphaTest?"#define ALPHATEST "+n.alphaTest+(n.alphaTest%1?"":".0"):"","#define GAMMA_FACTOR "+x,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+g:"",n.envMap?"#define "+v:"",n.envMap?"#define "+y:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.sheen?"#define USE_SHEEN":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+m:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"",(n.extensionShaderTextureLOD||n.envMap)&&n.rendererExtensionShaderTextureLod?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==k?"#define TONE_MAPPING":"",n.toneMapping!==k?jr.tonemapping_pars_fragment:"",n.toneMapping!==k?oo("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.outputEncoding||n.mapEncoding||n.matcapEncoding||n.envMapEncoding||n.emissiveMapEncoding||n.lightMapEncoding?jr.encodings_pars_fragment:"",n.mapEncoding?ao("mapTexelToLinear",n.mapEncoding):"",n.matcapEncoding?ao("matcapTexelToLinear",n.matcapEncoding):"",n.envMapEncoding?ao("envMapTexelToLinear",n.envMapEncoding):"",n.emissiveMapEncoding?ao("emissiveMapTexelToLinear",n.emissiveMapEncoding):"",n.lightMapEncoding?ao("lightMapTexelToLinear",n.lightMapEncoding):"",n.outputEncoding?(c="linearToOutputTexel",l=n.outputEncoding,h=io(l),"vec4 "+c+"( vec4 value ) { return LinearTo"+h[0]+h[1]+"; }"):"",n.depthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(so).join("\n")),d=lo(d=co(d=uo(d),n),n),f=lo(f=co(f=uo(f),n),n),d=mo(d),f=mo(f),n.isWebGL2&&!n.isRawShaderMaterial){var M=!1,S=/^\s*#version\s+300\s+es\s*\n/;n.isShaderMaterial&&null!==d.match(S)&&null!==f.match(S)&&(M=!0,d=d.replace(S,""),f=f.replace(S,"")),i=["#version 300 es\n","#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+i,s=["#version 300 es\n","#define varying in",M?"":"out highp vec4 pc_fragColor;",M?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+s}var T,E,A=s+f,L=to(u,35633,i+d),R=to(u,35632,A);if(u.attachShader(w,L),u.attachShader(w,R),void 0!==n.index0AttributeName?u.bindAttribLocation(w,0,n.index0AttributeName):!0===n.morphTargets&&u.bindAttribLocation(w,0,"position"),u.linkProgram(w),e.debug.checkShaderErrors){var P=u.getProgramInfoLog(w).trim(),C=u.getShaderInfoLog(L).trim(),O=u.getShaderInfoLog(R).trim(),D=!0,I=!0;if(!1===u.getProgramParameter(w,35714)){D=!1;var N=ro(u,L,"vertex"),B=ro(u,R,"fragment");console.error("THREE.WebGLProgram: shader error: ",u.getError(),"35715",u.getProgramParameter(w,35715),"gl.getProgramInfoLog",P,N,B)}else""!==P?console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",P):""!==C&&""!==O||(I=!1);I&&(this.diagnostics={runnable:D,programLog:P,vertexShader:{log:C,prefix:i},fragmentShader:{log:O,prefix:s}})}return u.detachShader(w,L),u.detachShader(w,R),u.deleteShader(L),u.deleteShader(R),this.getUniforms=function(){return void 0===T&&(T=new eo(u,w)),T},this.getAttributes=function(){return void 0===E&&(E=function(e,t){for(var n={},i=e.getProgramParameter(t,35721),r=0;r0,maxBones:S,useVertexTexture:o,morphTargets:i.morphTargets,morphNormals:i.morphNormals,maxMorphTargets:e.maxMorphTargets,maxMorphNormals:e.maxMorphNormals,numDirLights:d.directional.length,numPointLights:d.point.length,numSpotLights:d.spot.length,numRectAreaLights:d.rectArea.length,numHemiLights:d.hemi.length,numDirLightShadows:d.directionalShadowMap.length,numPointLightShadows:d.pointShadowMap.length,numSpotLightShadows:d.spotShadowMap.length,numClippingPlanes:v,numClipIntersection:y,dithering:i.dithering,shadowMapEnabled:e.shadowMap.enabled&&m.length>0,shadowMapType:e.shadowMap.type,toneMapping:i.toneMapped?e.toneMapping:k,physicallyCorrectLights:e.physicallyCorrectLights,premultipliedAlpha:i.premultipliedAlpha,alphaTest:i.alphaTest,doubleSided:i.side===l,flipSided:i.side===c,depthPacking:void 0!==i.depthPacking&&i.depthPacking,index0AttributeName:i.index0AttributeName,extensionDerivatives:i.extensions&&i.extensions.derivatives,extensionFragDepth:i.extensions&&i.extensions.fragDepth,extensionDrawbuffers:i.extensions&&i.extensions.drawBuffers,extensionShaderTextureLOD:i.extensions&&i.extensions.shaderTextureLOD,rendererExtensionFragDepth:r||null!==t.get("EXT_frag_depth"),rendererExtensionDrawBuffers:r||null!==t.get("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:r||null!==t.get("EXT_shader_texture_lod"),onBeforeCompile:i.onBeforeCompile}},this.getProgramCacheKey=function(t){var n=[];if(t.shaderID?n.push(t.shaderID):(n.push(t.fragmentShader),n.push(t.vertexShader)),void 0!==t.defines)for(var i in t.defines)n.push(i),n.push(t.defines[i]);if(void 0===t.isRawShaderMaterial){for(var r=0;r1&&n.sort(e||_o),i.length>1&&i.sort(t||wo)}}}function So(){var e=new WeakMap;function t(n){var i=n.target;i.removeEventListener("dispose",t),e.delete(i)}return{get:function(n,i){var r,a=e.get(n);return void 0===a?(r=new Mo,e.set(n,new WeakMap),e.get(n).set(i,r),n.addEventListener("dispose",t)):void 0===(r=a.get(i))&&(r=new Mo,a.set(i,r)),r},dispose:function(){e=new WeakMap}}}function To(){var e={};return{get:function(t){if(void 0!==e[t.id])return e[t.id];var n;switch(t.type){case"DirectionalLight":n={direction:new rn,color:new _i};break;case"SpotLight":n={position:new rn,direction:new rn,color:new _i,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new rn,color:new _i,distance:0,decay:0};break;case"HemisphereLight":n={direction:new rn,skyColor:new _i,groundColor:new _i};break;case"RectAreaLight":n={color:new _i,position:new rn,halfWidth:new rn,halfHeight:new rn}}return e[t.id]=n,n}}}var Eo=0;function Ao(e,t){return(t.castShadow?1:0)-(e.castShadow?1:0)}function Lo(){for(var e,t=new To,n=(e={},{get:function(t){if(void 0!==e[t.id])return e[t.id];var n;switch(t.type){case"DirectionalLight":case"SpotLight":n={shadowBias:0,shadowRadius:1,shadowMapSize:new qt};break;case"PointLight":n={shadowBias:0,shadowRadius:1,shadowMapSize:new qt,shadowCameraNear:1,shadowCameraFar:1e3}}return e[t.id]=n,n}}),i={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadow:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[],point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[]},r=0;r<9;r++)i.probe.push(new rn);var a=new rn,o=new pn,s=new pn;return{setup:function(e,r,c){for(var l=0,h=0,u=0,p=0;p<9;p++)i.probe[p].set(0,0,0);var d=0,f=0,m=0,g=0,v=0,y=0,x=0,b=0,_=c.matrixWorldInverse;e.sort(Ao),p=0;for(var w=e.length;p0:!0===c.isGeometry&&(p=c.morphTargets&&c.morphTargets.length>0));var d=!1;!0===t.isSkinnedMesh&&(!0===n.skinning?d=!0:console.warn("THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:",t)),l=h(p,d,!0===t.isInstancedMesh)}else l=u;if(e.localClippingEnabled&&!0===n.clipShadows&&0!==n.clippingPlanes.length){var f=l.uuid,v=n.uuid,y=m[f];void 0===y&&(y={},m[f]=y);var x=y[v];void 0===x&&(x=l.clone(),y[v]=x),l=x}return l.visible=n.visible,l.wireframe=n.wireframe,l.side=s===o?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:g[n.side],l.clipShadows=n.clipShadows,l.clippingPlanes=n.clippingPlanes,l.clipIntersection=n.clipIntersection,l.wireframeLinewidth=n.wireframeLinewidth,l.linewidth=n.linewidth,!0===i.isPointLight&&!0===l.isMeshDistanceMaterial&&(l.referencePosition.setFromMatrixPosition(i.matrixWorld),l.nearDistance=r,l.farDistance=a),l}function E(n,r,a,s,c){if(!1!==n.visible){if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&c===o)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(a.matrixWorldInverse,n.matrixWorld);var l=t.update(n),h=n.material;if(Array.isArray(h))for(var u=l.groups,p=0,d=u.length;pn||a.y>n)&&(console.warn("THREE.WebGLShadowMap:",v,"has shadow exceeding max texture size, reducing"),a.x>n&&(u.x=Math.floor(n/x.x),a.x=u.x*x.x,y.mapSize.x=u.x),a.y>n&&(u.y=Math.floor(n/x.y),a.y=u.y*x.y,y.mapSize.y=u.y)),null===y.map&&!y.isPointLightShadow&&this.type===o){var b={minFilter:ce,magFilter:ce,format:Te};y.map=new Kt(a.x,a.y,b),y.map.texture.name=v.name+".shadowMap",y.mapPass=new Kt(a.x,a.y,b),y.camera.updateProjectionMatrix()}if(null===y.map){b={minFilter:ae,magFilter:ae,format:Te};y.map=new Kt(a.x,a.y,b),y.map.texture.name=v.name+".shadowMap",y.camera.updateProjectionMatrix()}e.setRenderTarget(y.map),e.clear();for(var M=y.getViewportCount(),S=0;S=1):-1!==ue.indexOf("OpenGL ES")&&(he=parseFloat(/^OpenGL\ ES\ ([0-9])/.exec(ue)[1]),le=he>=2);var pe=null,de={},fe=new Qt,me=new Qt;function ge(t,n,i){var r=new Uint8Array(4),a=e.createTexture();e.bindTexture(t,a),e.texParameteri(t,10241,9728),e.texParameteri(t,10240,9728);for(var o=0;oi||e.height>i)&&(r=i/Math.max(e.width,e.height)),r<1||!0===t){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap){var a=t?Wt.floorPowerOfTwo:Math.floor,o=a(r*e.width),c=a(r*e.height);void 0===s&&(s=m(o,c));var l=n?m(o,c):s;return l.width=o,l.height=c,l.getContext("2d").drawImage(e,0,0,o,c),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+e.width+"x"+e.height+") to ("+o+"x"+c+")."),l}return"data"in e&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+e.width+"x"+e.height+")."),e}return e}function v(e){return Wt.isPowerOfTwo(e.width)&&Wt.isPowerOfTwo(e.height)}function y(e,t){return e.generateMipmaps&&t&&e.minFilter!==ae&&e.minFilter!==ce}function x(t,n,r,a){e.generateMipmap(t),i.get(n).__maxMipLevel=Math.log(Math.max(r,a))*Math.LOG2E}function b(n,i,r){if(!1===c)return i;if(null!==n){if(void 0!==e[n])return e[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}var a=i;return 6403===i&&(5126===r&&(a=33326),5131===r&&(a=33325),5121===r&&(a=33321)),6407===i&&(5126===r&&(a=34837),5131===r&&(a=34843),5121===r&&(a=32849)),6408===i&&(5126===r&&(a=34836),5131===r&&(a=34842),5121===r&&(a=32856)),33325===a||33326===a||34842===a||34836===a?t.get("EXT_color_buffer_float"):34843!==a&&34837!==a||console.warn("THREE.WebGLRenderer: Floating point textures with RGB format not supported. Please use RGBA instead."),a}function _(e){return e===ae||e===oe||e===se?9728:9729}function w(t){var n=t.target;n.removeEventListener("dispose",w),function(t){var n=i.get(t);if(void 0===n.__webglInit)return;e.deleteTexture(n.__webglTexture),i.remove(t)}(n),n.isVideoTexture&&d.delete(n),o.memory.textures--}function M(t){var n=t.target;n.removeEventListener("dispose",M),function(t){var n=i.get(t),r=i.get(t.texture);if(!t)return;void 0!==r.__webglTexture&&e.deleteTexture(r.__webglTexture);t.depthTexture&&t.depthTexture.dispose();if(t.isWebGLCubeRenderTarget)for(var a=0;a<6;a++)e.deleteFramebuffer(n.__webglFramebuffer[a]),n.__webglDepthbuffer&&e.deleteRenderbuffer(n.__webglDepthbuffer[a]);else e.deleteFramebuffer(n.__webglFramebuffer),n.__webglDepthbuffer&&e.deleteRenderbuffer(n.__webglDepthbuffer);i.remove(t.texture),i.remove(t)}(n),o.memory.textures--}var S=0;function T(e,t){var r=i.get(e);if(e.isVideoTexture&&function(e){var t=o.render.frame;d.get(e)!==t&&(d.set(e,t),e.update())}(e),e.version>0&&r.__version!==e.version){var a=e.image;if(void 0===a)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined");else{if(!1!==a.complete)return void O(r,e,t);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.activeTexture(33984+t),n.bindTexture(3553,r.__webglTexture)}function E(t,r){if(6===t.image.length){var o=i.get(t);if(t.version>0&&o.__version!==t.version){C(o,t),n.activeTexture(33984+r),n.bindTexture(34067,o.__webglTexture),e.pixelStorei(37440,t.flipY);for(var s=t&&(t.isCompressedTexture||t.image[0].isCompressedTexture),l=t.image[0]&&t.image[0].isDataTexture,u=[],p=0;p<6;p++)u[p]=s||l?l?t.image[p].image:t.image[p]:g(t.image[p],!1,!0,h);var d,f=u[0],m=v(f)||c,_=a.convert(t.format),w=a.convert(t.type),M=b(t.internalFormat,_,w);if(P(34067,t,m),s){for(p=0;p<6;p++){d=u[p].mipmaps;for(var S=0;S1||i.get(a).__currentAnisotropy)&&(e.texParameterf(n,s.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(a.anisotropy,r.getMaxAnisotropy())),i.get(a).__currentAnisotropy=a.anisotropy)}}function C(t,n){void 0===t.__webglInit&&(t.__webglInit=!0,n.addEventListener("dispose",w),t.__webglTexture=e.createTexture(),o.memory.textures++)}function O(t,i,r){var o=3553;i.isDataTexture2DArray&&(o=35866),i.isDataTexture3D&&(o=32879),C(t,i),n.activeTexture(33984+r),n.bindTexture(o,t.__webglTexture),e.pixelStorei(37440,i.flipY),e.pixelStorei(37441,i.premultiplyAlpha),e.pixelStorei(3317,i.unpackAlignment);var s=function(e){return!c&&(e.wrapS!==ie||e.wrapT!==ie||e.minFilter!==ae&&e.minFilter!==ce)}(i)&&!1===v(i.image),l=g(i.image,s,!1,u),h=v(l)||c,p=a.convert(i.format),d=a.convert(i.type),f=b(i.internalFormat,p,d);P(o,i,h);var m,_=i.mipmaps;if(i.isDepthTexture){if(f=6402,i.type===ve){if(!1===c)throw new Error("Float Depth Texture only supported in WebGL2.0");f=36012}else c&&(f=33189);i.format===Re&&6402===f&&i.type!==fe&&i.type!==ge&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),i.type=fe,d=a.convert(i.type)),i.format===Pe&&(f=34041,i.type!==we&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),i.type=we,d=a.convert(i.type))),n.texImage2D(3553,0,f,l.width,l.height,0,p,d,null)}else if(i.isDataTexture)if(_.length>0&&h){for(var w=0,M=_.length;w0&&h){for(w=0,M=_.length;w=l&&console.warn("THREE.WebGLTextures: Trying to use "+e+" texture units while this GPU supports only "+l),S+=1,e},this.resetTextureUnits=function(){S=0},this.setTexture2D=T,this.setTexture2DArray=function(e,t){var r=i.get(e);e.version>0&&r.__version!==e.version?O(r,e,t):(n.activeTexture(33984+t),n.bindTexture(35866,r.__webglTexture))},this.setTexture3D=function(e,t){var r=i.get(e);e.version>0&&r.__version!==e.version?O(r,e,t):(n.activeTexture(33984+t),n.bindTexture(32879,r.__webglTexture))},this.setTextureCube=E,this.setTextureCubeDynamic=A,this.setupRenderTarget=function(t){var r=i.get(t),s=i.get(t.texture);t.addEventListener("dispose",M),s.__webglTexture=e.createTexture(),o.memory.textures++;var l=!0===t.isWebGLCubeRenderTarget,h=!0===t.isWebGLMultisampleRenderTarget,u=v(t)||c;if(l){r.__webglFramebuffer=[];for(var p=0;p<6;p++)r.__webglFramebuffer[p]=e.createFramebuffer()}else if(r.__webglFramebuffer=e.createFramebuffer(),h)if(c){r.__webglMultisampledFramebuffer=e.createFramebuffer(),r.__webglColorRenderbuffer=e.createRenderbuffer(),e.bindRenderbuffer(36161,r.__webglColorRenderbuffer);var d=a.convert(t.texture.format),f=a.convert(t.texture.type),m=b(t.texture.internalFormat,d,f),g=B(t);e.renderbufferStorageMultisample(36161,g,m,t.width,t.height),e.bindFramebuffer(36160,r.__webglMultisampledFramebuffer),e.framebufferRenderbuffer(36160,36064,36161,r.__webglColorRenderbuffer),e.bindRenderbuffer(36161,null),t.depthBuffer&&(r.__webglDepthRenderbuffer=e.createRenderbuffer(),I(r.__webglDepthRenderbuffer,t,!0)),e.bindFramebuffer(36160,null)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.");if(l){for(n.bindTexture(34067,s.__webglTexture),P(34067,t.texture,u),p=0;p<6;p++)D(r.__webglFramebuffer[p],t,36064,34069+p);y(t.texture,u)&&x(34067,t.texture,t.width,t.height),n.bindTexture(34067,null)}else n.bindTexture(3553,s.__webglTexture),P(3553,t.texture,u),D(r.__webglFramebuffer,t,36064,3553),y(t.texture,u)&&x(3553,t.texture,t.width,t.height),n.bindTexture(3553,null);t.depthBuffer&&N(t)},this.updateRenderTargetMipmap=function(e){var t=e.texture;if(y(t,v(e)||c)){var r=e.isWebGLCubeRenderTarget?34067:3553,a=i.get(t).__webglTexture;n.bindTexture(r,a),x(r,t,e.width,e.height),n.bindTexture(r,null)}},this.updateMultisampleRenderTarget=function(t){if(t.isWebGLMultisampleRenderTarget)if(c){var n=i.get(t);e.bindFramebuffer(36008,n.__webglMultisampledFramebuffer),e.bindFramebuffer(36009,n.__webglFramebuffer);var r=t.width,a=t.height,o=16384;t.depthBuffer&&(o|=256),t.stencilBuffer&&(o|=1024),e.blitFramebuffer(0,0,r,a,0,0,r,a,o,9728)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.")},this.safeSetTexture2D=function(e,t){e&&e.isWebGLRenderTarget&&(!1===z&&(console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."),z=!0),e=e.texture),T(e,t)},this.safeSetTextureCube=function(e,t){e&&e.isWebGLCubeRenderTarget&&(!1===F&&(console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."),F=!0),e=e.texture),e&&e.isCubeTexture||Array.isArray(e.image)&&6===e.image.length?E(e,t):A(e,t)}}function Fo(e,t,n){var i=n.isWebGL2;return{convert:function(e){var n;if(e===ue)return 5121;if(e===xe)return 32819;if(e===be)return 32820;if(e===_e)return 33635;if(e===pe)return 5120;if(e===de)return 5122;if(e===fe)return 5123;if(e===me)return 5124;if(e===ge)return 5125;if(e===ve)return 5126;if(e===ye)return i?5131:null!==(n=t.get("OES_texture_half_float"))?n.HALF_FLOAT_OES:null;if(e===Me)return 6406;if(e===Se)return 6407;if(e===Te)return 6408;if(e===Ee)return 6409;if(e===Ae)return 6410;if(e===Re)return 6402;if(e===Pe)return 34041;if(e===Ce)return 6403;if(e===Oe)return 36244;if(e===De)return 33319;if(e===Ie)return 33320;if(e===Ne)return 36248;if(e===Be)return 36249;if(e===ze||e===Fe||e===Ue||e===Ge){if(null===(n=t.get("WEBGL_compressed_texture_s3tc")))return null;if(e===ze)return n.COMPRESSED_RGB_S3TC_DXT1_EXT;if(e===Fe)return n.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(e===Ue)return n.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(e===Ge)return n.COMPRESSED_RGBA_S3TC_DXT5_EXT}if(e===He)return null!==(n=t.get("EXT_texture_compression_bptc"))?n.COMPRESSED_RGBA_BPTC_UNORM_EXT:null;if(e===Ve||e===ke||e===je||e===We){if(null===(n=t.get("WEBGL_compressed_texture_pvrtc")))return null;if(e===Ve)return n.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(e===ke)return n.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(e===je)return n.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(e===We)return n.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}if(e===qe)return null!==(n=t.get("WEBGL_compressed_texture_etc1"))?n.COMPRESSED_RGB_ETC1_WEBGL:null;if((e===Xe||e===Ye)&&null!==(n=t.get("WEBGL_compressed_texture_etc"))){if(e===Xe)return n.COMPRESSED_RGB8_ETC2;if(e===Ye)return n.COMPRESSED_RGBA8_ETC2_EAC}return e===Ze||e===Je||e===Qe||e===Ke||e===$e||e===et||e===tt||e===nt||e===it||e===rt||e===at||e===ot||e===st||e===ct||e===lt||e===ht||e===ut||e===pt||e===dt||e===ft||e===mt||e===gt||e===vt||e===yt||e===xt||e===bt||e===_t||e===wt?null!==(n=t.get("WEBGL_compressed_texture_astc"))?e:null:e===we?i?34042:null!==(n=t.get("WEBGL_depth_texture"))?n.UNSIGNED_INT_24_8_WEBGL:null:void 0}}}function Uo(e){Pr.call(this),this.cameras=e||[]}function Go(){Pn.call(this),this.type="Group"}function Ho(e,t){var n=this,i=null,r=1,a=null,o="local-floor",s=null,c=[],l=new Map,h=new Pr;h.layers.enable(1),h.viewport=new Qt;var u=new Pr;u.layers.enable(2),u.viewport=new Qt;var p=new Uo([h,u]);p.layers.enable(1),p.layers.enable(2);var d=null,f=null;function m(e){var t=l.get(e.inputSource);t&&(t.targetRay&&t.targetRay.dispatchEvent({type:e.type}),t.grip&&t.grip.dispatchEvent({type:e.type}))}function g(){l.forEach(function(e,t){e.targetRay&&(e.targetRay.dispatchEvent({type:"disconnected",data:t}),e.targetRay.visible=!1),e.grip&&(e.grip.dispatchEvent({type:"disconnected",data:t}),e.grip.visible=!1)}),l.clear(),e.setFramebuffer(null),e.setRenderTarget(e.getRenderTarget()),M.stop(),n.isPresenting=!1,n.dispatchEvent({type:"sessionend"})}function v(e){a=e,M.setContext(i),M.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}function y(e){for(var t=i.inputSources,n=0;n=0){var l=r[s];if(void 0!==l){var h=l.normalized,u=l.itemSize,p=_.get(l);if(void 0===p)continue;var d=p.buffer,y=p.type,x=p.bytesPerElement;if(l.isInterleavedBufferAttribute){var b=l.data,w=b.stride,M=l.offset;b&&b.isInstancedInterleavedBuffer?(v.enableAttributeAndDivisor(c,b.meshPerAttribute),void 0===t.maxInstancedCount&&(t.maxInstancedCount=b.meshPerAttribute*b.count)):v.enableAttribute(c),f.bindBuffer(34962,d),f.vertexAttribPointer(c,u,y,h,w*x,M*x)}else l.isInstancedBufferAttribute?(v.enableAttributeAndDivisor(c,l.meshPerAttribute),void 0===t.maxInstancedCount&&(t.maxInstancedCount=l.meshPerAttribute*l.count)):v.enableAttribute(c),f.bindBuffer(34962,d),f.vertexAttribPointer(c,u,y,h,0,0)}else if("instanceMatrix"===s){var p=_.get(e.instanceMatrix);if(void 0===p)continue;var d=p.buffer,y=p.type;v.enableAttributeAndDivisor(c+0,1),v.enableAttributeAndDivisor(c+1,1),v.enableAttributeAndDivisor(c+2,1),v.enableAttributeAndDivisor(c+3,1),f.bindBuffer(34962,d),f.vertexAttribPointer(c+0,4,y,!1,64,0),f.vertexAttribPointer(c+1,4,y,!1,64,16),f.vertexAttribPointer(c+2,4,y,!1,64,32),f.vertexAttribPointer(c+3,4,y,!1,64,48)}else if(void 0!==o){var S=o[s];if(void 0!==S)switch(S.length){case 2:f.vertexAttrib2fv(c,S);break;case 3:f.vertexAttrib3fv(c,S);break;case 4:f.vertexAttrib4fv(c,S);break;default:f.vertexAttrib1fv(c,S)}}}}v.disableUnusedAttributes()}(r,n,i,s),null!==l&&f.bindBuffer(34963,u.buffer));var y=null!==l?l.count:h.count,x=n.drawRange.start*p,b=n.drawRange.count*p,M=null!==a?a.start*p:0,S=null!==a?a.count*p:1/0,T=Math.max(x,M),E=Math.min(y,x+b,M+S)-1,A=Math.max(0,E-T+1);if(0!==A){if(r.isMesh)!0===i.wireframe?(v.setLineWidth(i.wireframeLinewidth*se()),d.setMode(1)):d.setMode(4);else if(r.isLine){var C=i.linewidth;void 0===C&&(C=1),v.setLineWidth(C*se()),r.isLineSegments?d.setMode(1):r.isLineLoop?d.setMode(2):d.setMode(3)}else r.isPoints?d.setMode(0):r.isSprite&&d.setMode(4);r.isInstancedMesh?d.renderInstances(n,T,A,r.count):n.isInstancedBufferGeometry?d.renderInstances(n,T,A,n.maxInstancedCount):d.render(T,A)}},this.compile=function(e,t){(d=E.get(e,t)).init(),e.traverse(function(e){e.isLight&&(d.pushLight(e),e.castShadow&&d.pushShadow(e))}),d.setupLights(t);var n={};e.traverse(function(t){if(t.material)if(Array.isArray(t.material))for(var i=0;i=0&&e.numSupportedMorphTargets++}if(e.morphNormals){e.numSupportedMorphNormals=0;for(p=0;p=0&&e.numSupportedMorphNormals++}var f=i.uniforms;(e.isShaderMaterial||e.isRawShaderMaterial)&&!0!==e.clipping||(i.numClippingPlanes=ne.numPlanes,i.numIntersection=ne.numIntersection,f.clippingPlanes=ne.uniform),i.fog=t.fog,i.needsLights=function(e){return e.isMeshLambertMaterial||e.isMeshToonMaterial||e.isMeshPhongMaterial||e.isMeshStandardMaterial||e.isShadowMaterial||e.isShaderMaterial&&!0===e.lights}(e),i.lightsStateVersion=o,i.needsLights&&(f.ambientLightColor.value=r.state.ambient,f.lightProbe.value=r.state.probe,f.directionalLights.value=r.state.directional,f.directionalLightShadows.value=r.state.directionalShadow,f.spotLights.value=r.state.spot,f.spotLightShadows.value=r.state.spotShadow,f.rectAreaLights.value=r.state.rectArea,f.pointLights.value=r.state.point,f.pointLightShadows.value=r.state.pointShadow,f.hemisphereLights.value=r.state.hemi,f.directionalShadowMap.value=r.state.directionalShadowMap,f.directionalShadowMatrix.value=r.state.directionalShadowMatrix,f.spotShadowMap.value=r.state.spotShadowMap,f.spotShadowMatrix.value=r.state.spotShadowMatrix,f.pointShadowMap.value=r.state.pointShadowMap,f.pointShadowMatrix.value=r.state.pointShadowMatrix);var m=i.program.getUniforms(),g=eo.seqWithValue(m.seq,f);i.uniformsList=g}function Ee(e,t,n,i){b.resetTextureUnits();var r=t.fog,a=n.isMeshStandardMaterial?t.environment:null,o=x.get(n),s=d.state.lights;if(ie&&(re||e!==H)){var l=e===H&&n.id===U;ne.setState(n.clippingPlanes,n.clipIntersection,n.clipShadows,e,o,l)}n.version===o.__version?void 0===o.program?Se(n,t,i):n.fog&&o.fog!==r?Se(n,t,i):o.environment!==a?Se(n,t,i):o.needsLights&&o.lightsStateVersion!==s.state.version?Se(n,t,i):void 0===o.numClippingPlanes||o.numClippingPlanes===ne.numPlanes&&o.numIntersection===ne.numIntersection?o.outputEncoding!==O.outputEncoding&&Se(n,t,i):Se(n,t,i):(Se(n,t,i),o.__version=n.version);var h,u,p=!1,m=!1,y=!1,_=o.program,w=_.getUniforms(),M=o.uniforms;if(v.useProgram(_.program)&&(p=!0,m=!0,y=!0),n.id!==U&&(U=n.id,m=!0),p||H!==e){if(w.setValue(f,"projectionMatrix",e.projectionMatrix),g.logarithmicDepthBuffer&&w.setValue(f,"logDepthBufFC",2/(Math.log(e.far+1)/Math.LN2)),H!==e&&(H=e,m=!0,y=!0),n.isShaderMaterial||n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshStandardMaterial||n.envMap){var S=w.map.cameraPosition;void 0!==S&&S.setValue(f,oe.setFromMatrixPosition(e.matrixWorld))}(n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshLambertMaterial||n.isMeshBasicMaterial||n.isMeshStandardMaterial||n.isShaderMaterial)&&w.setValue(f,"isOrthographic",!0===e.isOrthographicCamera),(n.isMeshPhongMaterial||n.isMeshToonMaterial||n.isMeshLambertMaterial||n.isMeshBasicMaterial||n.isMeshStandardMaterial||n.isShaderMaterial||n.skinning)&&w.setValue(f,"viewMatrix",e.matrixWorldInverse)}if(n.skinning){w.setOptional(f,i,"bindMatrix"),w.setOptional(f,i,"bindMatrixInverse");var T=i.skeleton;if(T){var E=T.bones;if(g.floatVertexTextures){if(void 0===T.boneTexture){var A=Math.sqrt(4*E.length);A=Wt.ceilPowerOfTwo(A),A=Math.max(A,4);var L=new Float32Array(A*A*4);L.set(T.boneMatrices);var R=new Nr(L,A,A,Te,ve);T.boneMatrices=L,T.boneTexture=R,T.boneTextureSize=A}w.setValue(f,"boneTexture",T.boneTexture,b),w.setValue(f,"boneTextureSize",T.boneTextureSize)}else w.setOptional(f,T,"boneMatrices")}}return(m||o.receiveShadow!==i.receiveShadow)&&(o.receiveShadow=i.receiveShadow,w.setValue(f,"receiveShadow",i.receiveShadow)),m&&(w.setValue(f,"toneMappingExposure",O.toneMappingExposure),w.setValue(f,"toneMappingWhitePoint",O.toneMappingWhitePoint),o.needsLights&&(u=y,(h=M).ambientLightColor.needsUpdate=u,h.lightProbe.needsUpdate=u,h.directionalLights.needsUpdate=u,h.directionalLightShadows.needsUpdate=u,h.pointLights.needsUpdate=u,h.pointLightShadows.needsUpdate=u,h.spotLights.needsUpdate=u,h.spotLightShadows.needsUpdate=u,h.rectAreaLights.needsUpdate=u,h.hemisphereLights.needsUpdate=u),r&&n.fog&&function(e,t){e.fogColor.value.copy(t.color),t.isFog?(e.fogNear.value=t.near,e.fogFar.value=t.far):t.isFogExp2&&(e.fogDensity.value=t.density)}(M,r),n.isMeshBasicMaterial?Ae(M,n):n.isMeshLambertMaterial?(Ae(M,n),function(e,t){t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap)}(M,n)):n.isMeshToonMaterial?(Ae(M,n),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4),t.gradientMap&&(e.gradientMap.value=t.gradientMap);t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshPhongMaterial?(Ae(M,n),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4),t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshStandardMaterial?(Ae(M,n,a),n.isMeshPhysicalMaterial?function(e,t,n){Le(e,t,n),e.reflectivity.value=t.reflectivity,e.clearcoat.value=t.clearcoat,e.clearcoatRoughness.value=t.clearcoatRoughness,t.sheen&&e.sheen.value.copy(t.sheen);t.clearcoatNormalMap&&(e.clearcoatNormalScale.value.copy(t.clearcoatNormalScale),e.clearcoatNormalMap.value=t.clearcoatNormalMap,t.side===c&&e.clearcoatNormalScale.value.negate());e.transparency.value=t.transparency}(M,n,a):Le(M,n,a)):n.isMeshMatcapMaterial?(Ae(M,n),function(e,t){t.matcap&&(e.matcap.value=t.matcap);t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshDepthMaterial?(Ae(M,n),function(e,t){t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isMeshDistanceMaterial?(Ae(M,n),function(e,t){t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias);e.referencePosition.value.copy(t.referencePosition),e.nearDistance.value=t.nearDistance,e.farDistance.value=t.farDistance}(M,n)):n.isMeshNormalMaterial?(Ae(M,n),function(e,t){t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1));t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate());t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias)}(M,n)):n.isLineBasicMaterial?(function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity}(M,n),n.isLineDashedMaterial&&function(e,t){e.dashSize.value=t.dashSize,e.totalSize.value=t.dashSize+t.gapSize,e.scale.value=t.scale}(M,n)):n.isPointsMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.size.value=t.size*Z,e.scale.value=.5*Y,t.map&&(e.map.value=t.map);t.alphaMap&&(e.alphaMap.value=t.alphaMap);var n;t.map?n=t.map:t.alphaMap&&(n=t.alphaMap);void 0!==n&&(!0===n.matrixAutoUpdate&&n.updateMatrix(),e.uvTransform.value.copy(n.matrix))}(M,n):n.isSpriteMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.rotation.value=t.rotation,t.map&&(e.map.value=t.map);t.alphaMap&&(e.alphaMap.value=t.alphaMap);var n;t.map?n=t.map:t.alphaMap&&(n=t.alphaMap);void 0!==n&&(!0===n.matrixAutoUpdate&&n.updateMatrix(),e.uvTransform.value.copy(n.matrix))}(M,n):n.isShadowMaterial&&(M.color.value.copy(n.color),M.opacity.value=n.opacity),void 0!==M.ltc_1&&(M.ltc_1.value=Ur.LTC_1),void 0!==M.ltc_2&&(M.ltc_2.value=Ur.LTC_2),eo.upload(f,o.uniformsList,M,b),n.isShaderMaterial&&(n.uniformsNeedUpdate=!1)),n.isShaderMaterial&&!0===n.uniformsNeedUpdate&&(eo.upload(f,o.uniformsList,M,b),n.uniformsNeedUpdate=!1),n.isSpriteMaterial&&w.setValue(f,"center",i.center),w.setValue(f,"modelViewMatrix",i.modelViewMatrix),w.setValue(f,"normalMatrix",i.normalMatrix),w.setValue(f,"modelMatrix",i.matrixWorld),_}function Ae(e,t,n){e.opacity.value=t.opacity,t.color&&e.diffuse.value.copy(t.color),t.emissive&&e.emissive.value.copy(t.emissive).multiplyScalar(t.emissiveIntensity),t.map&&(e.map.value=t.map),t.alphaMap&&(e.alphaMap.value=t.alphaMap),t.specularMap&&(e.specularMap.value=t.specularMap);var i,r,a=t.envMap||n;a&&(e.envMap.value=a,e.flipEnvMap.value=a.isCubeTexture?-1:1,e.reflectivity.value=t.reflectivity,e.refractionRatio.value=t.refractionRatio,e.maxMipLevel.value=x.get(a).__maxMipLevel),t.lightMap&&(e.lightMap.value=t.lightMap,e.lightMapIntensity.value=t.lightMapIntensity),t.aoMap&&(e.aoMap.value=t.aoMap,e.aoMapIntensity.value=t.aoMapIntensity),t.map?i=t.map:t.specularMap?i=t.specularMap:t.displacementMap?i=t.displacementMap:t.normalMap?i=t.normalMap:t.bumpMap?i=t.bumpMap:t.roughnessMap?i=t.roughnessMap:t.metalnessMap?i=t.metalnessMap:t.alphaMap?i=t.alphaMap:t.emissiveMap&&(i=t.emissiveMap),void 0!==i&&(i.isWebGLRenderTarget&&(i=i.texture),!0===i.matrixAutoUpdate&&i.updateMatrix(),e.uvTransform.value.copy(i.matrix)),t.aoMap?r=t.aoMap:t.lightMap&&(r=t.lightMap),void 0!==r&&(r.isWebGLRenderTarget&&(r=r.texture),!0===r.matrixAutoUpdate&&r.updateMatrix(),e.uv2Transform.value.copy(r.matrix))}function Le(e,t,n){e.roughness.value=t.roughness,e.metalness.value=t.metalness,t.roughnessMap&&(e.roughnessMap.value=t.roughnessMap),t.metalnessMap&&(e.metalnessMap.value=t.metalnessMap),t.emissiveMap&&(e.emissiveMap.value=t.emissiveMap),t.bumpMap&&(e.bumpMap.value=t.bumpMap,e.bumpScale.value=t.bumpScale,t.side===c&&(e.bumpScale.value*=-1)),t.normalMap&&(e.normalMap.value=t.normalMap,e.normalScale.value.copy(t.normalScale),t.side===c&&e.normalScale.value.negate()),t.displacementMap&&(e.displacementMap.value=t.displacementMap,e.displacementScale.value=t.displacementScale,e.displacementBias.value=t.displacementBias),(t.envMap||n)&&(e.envMapIntensity.value=t.envMapIntensity)}_e.setAnimationLoop(function(e){he.isPresenting||be&&be(e)}),"undefined"!=typeof window&&_e.setContext(window),this.setAnimationLoop=function(e){be=e,he.setAnimationLoop(e),_e.start()},this.render=function(e,t){var n,i;if(void 0!==arguments[2]&&(console.warn("THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead."),n=arguments[2]),void 0!==arguments[3]&&(console.warn("THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead."),i=arguments[3]),t&&t.isCamera){if(!D){G.geometry=null,G.program=null,G.wireframe=!1,U=-1,H=null,!0===e.autoUpdate&&e.updateMatrixWorld(),null===t.parent&&t.updateMatrixWorld(),he.enabled&&he.isPresenting&&(t=he.getCamera(t)),(d=E.get(e,t)).init(),e.onBeforeRender(O,e,t,n||z),ae.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),te.setFromProjectionMatrix(ae),re=this.localClippingEnabled,ie=ne.init(this.clippingPlanes,re,t),(p=T.get(e,t)).init(),function e(t,n,i,r){if(!1===t.visible)return;var a=t.layers.test(n.layers);if(a)if(t.isGroup)i=t.renderOrder;else if(t.isLOD)!0===t.autoUpdate&&t.update(n);else if(t.isLight)d.pushLight(t),t.castShadow&&d.pushShadow(t);else if(t.isSprite){if(!t.frustumCulled||te.intersectsSprite(t)){r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae);var o=M.update(t),s=t.material;s.visible&&p.push(t,o,s,i,oe.z,null)}}else if(t.isImmediateRenderObject)r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae),p.push(t,null,t.material,i,oe.z,null);else if((t.isMesh||t.isLine||t.isPoints)&&(t.isSkinnedMesh&&t.skeleton.frame!==y.render.frame&&(t.skeleton.update(),t.skeleton.frame=y.render.frame),!t.frustumCulled||te.intersectsObject(t))){r&&oe.setFromMatrixPosition(t.matrixWorld).applyMatrix4(ae);var o=M.update(t),s=t.material;if(Array.isArray(s))for(var c=o.groups,l=0,h=c.length;l=0&&t<=e.width-i&&n>=0&&n<=e.height-r&&f.readPixels(t,n,i,r,C.convert(h),C.convert(u),a):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.")}finally{c&&f.bindFramebuffer(36160,F)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")},this.copyFramebufferToTexture=function(e,t,n){void 0===n&&(n=0);var i=Math.pow(2,-n),r=Math.floor(t.image.width*i),a=Math.floor(t.image.height*i),o=C.convert(t.format);b.setTexture2D(t,0),f.copyTexImage2D(3553,n,o,e.x,e.y,r,a,0),v.unbindTexture()},this.copyTextureToTexture=function(e,t,n,i){var r=t.image.width,a=t.image.height,o=C.convert(n.format),s=C.convert(n.type);b.setTexture2D(n,0),t.isDataTexture?f.texSubImage2D(3553,i||0,e.x,e.y,r,a,o,s,t.image.data):f.texSubImage2D(3553,i||0,e.x,e.y,o,s,t.image),v.unbindTexture()},this.initTexture=function(e){b.setTexture2D(e,0),v.unbindTexture()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}function ko(e,t){this.name="",this.color=new _i(e),this.density=void 0!==t?t:25e-5}function jo(e,t,n){this.name="",this.color=new _i(e),this.near=void 0!==t?t:1,this.far=void 0!==n?n:1e3}function Wo(e,t){this.array=e,this.stride=t,this.count=void 0!==e?e.length/t:0,this.usage=Ut,this.updateRange={offset:0,count:-1},this.version=0}Uo.prototype=Object.assign(Object.create(Pr.prototype),{constructor:Uo,isArrayCamera:!0}),Go.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Go,isGroup:!0}),Object.assign(Ho.prototype,Ht.prototype),Object.assign(ko.prototype,{isFogExp2:!0,clone:function(){return new ko(this.color,this.density)},toJSON:function(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}}),Object.assign(jo.prototype,{isFog:!0,clone:function(){return new jo(this.color,this.near,this.far)},toJSON:function(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}}),Object.defineProperty(Wo.prototype,"needsUpdate",{set:function(e){!0===e&&this.version++}}),Object.assign(Wo.prototype,{isInterleavedBuffer:!0,onUploadCallback:function(){},setUsage:function(e){return this.usage=e,this},copy:function(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this},copyAt:function(e,t,n){e*=this.stride,n*=t.stride;for(var i=0,r=this.stride;ie.far||t.push({distance:s,point:Jo.clone(),uv:vi.getUV(Jo,ns,is,rs,as,os,ss,new qt),face:null,object:this})}},clone:function(){return new this.constructor(this.material).copy(this)},copy:function(e){return Pn.prototype.copy.call(this,e),void 0!==e.center&&this.center.copy(e.center),this}});var hs=new rn,us=new rn;function ps(){Pn.call(this),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]}}),this.autoUpdate=!0}function ds(e,t){e&&e.isGeometry&&console.error("THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."),dr.call(this,e,t),this.type="SkinnedMesh",this.bindMode="attached",this.bindMatrix=new pn,this.bindMatrixInverse=new pn}ps.prototype=Object.assign(Object.create(Pn.prototype),{constructor:ps,isLOD:!0,copy:function(e){Pn.prototype.copy.call(this,e,!1);for(var t=e.levels,n=0,i=t.length;n0){for(var n=1,i=t.length;n0){hs.setFromMatrixPosition(this.matrixWorld);var n=e.ray.origin.distanceTo(hs);this.getObjectForDistance(n).raycast(e,t)}},update:function(e){var t=this.levels;if(t.length>1){hs.setFromMatrixPosition(e.matrixWorld),us.setFromMatrixPosition(this.matrixWorld);var n=hs.distanceTo(us)/e.zoom;t[0].object.visible=!0;for(var i=1,r=t.length;i=t[i].distance;i++)t[i-1].object.visible=!1,t[i].object.visible=!0;for(this._currentLevel=i-1;i0&&(bs[0].instanceId=r,bs[0].object=this,t.push(bs[0]),bs.length=0)},setMatrixAt:function(e,t){t.toArray(this.instanceMatrix.array,16*e)},updateMorphTargets:function(){}}),Ms.prototype=Object.create(Ai.prototype),Ms.prototype.constructor=Ms,Ms.prototype.isLineBasicMaterial=!0,Ms.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this};var Ss=new rn,Ts=new rn,Es=new pn,As=new ni,Ls=new Yn;function Rs(e,t,n){1===n&&console.error("THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead."),Pn.call(this),this.type="Line",this.geometry=void 0!==e?e:new Zi,this.material=void 0!==t?t:new Ms}Rs.prototype=Object.assign(Object.create(Pn.prototype),{constructor:Rs,isLine:!0,computeLineDistances:function(){var e=this.geometry;if(e.isBufferGeometry)if(null===e.index){for(var t=e.attributes.position,n=[0],i=1,r=t.count;io))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}else for(m=0,g=d.length/3-1;mo))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}}else if(n.isGeometry){var x=n.vertices,b=x.length;for(m=0;mo))h.applyMatrix4(this.matrixWorld),(_=e.ray.origin.distanceTo(h))e.far||t.push({distance:_,point:l.clone().applyMatrix4(this.matrixWorld),index:m,face:null,faceIndex:null,object:this})}}}},clone:function(){return new this.constructor(this.geometry,this.material).copy(this)}});var Ps=new rn,Cs=new rn;function Os(e,t){Rs.call(this,e,t),this.type="LineSegments"}function Ds(e,t){Rs.call(this,e,t),this.type="LineLoop"}function Is(e){Ai.call(this),this.type="PointsMaterial",this.color=new _i(16777215),this.map=null,this.alphaMap=null,this.size=1,this.sizeAttenuation=!0,this.morphTargets=!1,this.setValues(e)}Os.prototype=Object.assign(Object.create(Rs.prototype),{constructor:Os,isLineSegments:!0,computeLineDistances:function(){var e=this.geometry;if(e.isBufferGeometry)if(null===e.index){for(var t=e.attributes.position,n=[],i=0,r=t.count;ir.far)return;a.push({distance:l,distanceToRay:Math.sqrt(s),point:c,index:t,face:null,object:o})}}function Hs(e,t,n,i,r,a,o,s,c){Jt.call(this,e,t,n,i,r,a,o,s,c),this.format=void 0!==o?o:Se,this.minFilter=void 0!==a?a:ce,this.magFilter=void 0!==r?r:ce,this.generateMipmaps=!1}function Vs(e,t,n,i,r,a,o,s,c,l,h,u){Jt.call(this,null,a,o,s,c,l,i,r,h,u),this.image={width:t,height:n},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}function ks(e,t,n,i,r,a,o,s,c){Jt.call(this,e,t,n,i,r,a,o,s,c),this.needsUpdate=!0}function js(e,t,n,i,r,a,o,s,c,l){if((l=void 0!==l?l:Re)!==Re&&l!==Pe)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===n&&l===Re&&(n=fe),void 0===n&&l===Pe&&(n=we),Jt.call(this,null,i,r,a,o,s,l,n,c),this.image={width:e,height:t},this.magFilter=void 0!==o?o:ae,this.minFilter=void 0!==s?s:ae,this.flipY=!1,this.generateMipmaps=!1}function Ws(e){Zi.call(this),this.type="WireframeGeometry";var t,n,i,r,a,o,s,c,l,h,u=[],p=[0,0],d={},f=["a","b","c"];if(e&&e.isGeometry){var m=e.faces;for(t=0,i=m.length;t=0?(e(g-1e-5,m,u),p.subVectors(h,u)):(e(g+1e-5,m,u),p.subVectors(u,h)),m-1e-5>=0?(e(g,m-1e-5,u),d.subVectors(h,u)):(e(g,m+1e-5,u),d.subVectors(u,h)),l.crossVectors(p,d).normalize(),s.push(l.x,l.y,l.z),c.push(g,m)}}for(i=0;i.9&&o<.1&&(t<.2&&(a[e+0]+=1),n<.2&&(a[e+2]+=1),i<.2&&(a[e+4]+=1))}}()}(),this.setAttribute("position",new Fi(r,3)),this.setAttribute("normal",new Fi(r.slice(),3)),this.setAttribute("uv",new Fi(a,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}function Js(e,t){br.call(this),this.type="TetrahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new Qs(e,t)),this.mergeVertices()}function Qs(e,t){Zs.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],e,t),this.type="TetrahedronBufferGeometry",this.parameters={radius:e,detail:t}}function Ks(e,t){br.call(this),this.type="OctahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new $s(e,t)),this.mergeVertices()}function $s(e,t){Zs.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],e,t),this.type="OctahedronBufferGeometry",this.parameters={radius:e,detail:t}}function ec(e,t){br.call(this),this.type="IcosahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new tc(e,t)),this.mergeVertices()}function tc(e,t){var n=(1+Math.sqrt(5))/2,i=[-1,n,0,1,n,0,-1,-n,0,1,-n,0,0,-1,n,0,1,n,0,-1,-n,0,1,-n,n,0,-1,n,0,1,-n,0,-1,-n,0,1];Zs.call(this,i,[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],e,t),this.type="IcosahedronBufferGeometry",this.parameters={radius:e,detail:t}}function nc(e,t){br.call(this),this.type="DodecahedronGeometry",this.parameters={radius:e,detail:t},this.fromBufferGeometry(new ic(e,t)),this.mergeVertices()}function ic(e,t){var n=(1+Math.sqrt(5))/2,i=1/n,r=[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i];Zs.call(this,r,[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,t),this.type="DodecahedronBufferGeometry",this.parameters={radius:e,detail:t}}function rc(e,t,n,i,r,a){br.call(this),this.type="TubeGeometry",this.parameters={path:e,tubularSegments:t,radius:n,radialSegments:i,closed:r},void 0!==a&&console.warn("THREE.TubeGeometry: taper has been removed.");var o=new ac(e,t,n,i,r);this.tangents=o.tangents,this.normals=o.normals,this.binormals=o.binormals,this.fromBufferGeometry(o),this.mergeVertices()}function ac(e,t,n,i,r){Zi.call(this),this.type="TubeBufferGeometry",this.parameters={path:e,tubularSegments:t,radius:n,radialSegments:i,closed:r},t=t||64,n=n||1,i=i||8,r=r||!1;var a=e.computeFrenetFrames(t,r);this.tangents=a.tangents,this.normals=a.normals,this.binormals=a.binormals;var o,s,c=new rn,l=new rn,h=new qt,u=new rn,p=[],d=[],f=[],m=[];function g(r){u=e.getPointAt(r/t,u);var o=a.normals[r],h=a.binormals[r];for(s=0;s<=i;s++){var f=s/i*Math.PI*2,m=Math.sin(f),g=-Math.cos(f);l.x=g*o.x+m*h.x,l.y=g*o.y+m*h.y,l.z=g*o.z+m*h.z,l.normalize(),d.push(l.x,l.y,l.z),c.x=u.x+n*l.x,c.y=u.y+n*l.y,c.z=u.z+n*l.z,p.push(c.x,c.y,c.z)}}!function(){for(o=0;o0){var o=r[a[0]];if(void 0!==o)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},e=0,t=o.length;e0&&console.error("THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}},clone:function(){return new this.constructor(this.geometry,this.material).copy(this)}}),Hs.prototype=Object.assign(Object.create(Jt.prototype),{constructor:Hs,isVideoTexture:!0,update:function(){var e=this.image;e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}),Vs.prototype=Object.create(Jt.prototype),Vs.prototype.constructor=Vs,Vs.prototype.isCompressedTexture=!0,ks.prototype=Object.create(Jt.prototype),ks.prototype.constructor=ks,ks.prototype.isCanvasTexture=!0,js.prototype=Object.create(Jt.prototype),js.prototype.constructor=js,js.prototype.isDepthTexture=!0,Ws.prototype=Object.create(Zi.prototype),Ws.prototype.constructor=Ws,qs.prototype=Object.create(br.prototype),qs.prototype.constructor=qs,Xs.prototype=Object.create(Zi.prototype),Xs.prototype.constructor=Xs,Ys.prototype=Object.create(br.prototype),Ys.prototype.constructor=Ys,Zs.prototype=Object.create(Zi.prototype),Zs.prototype.constructor=Zs,Js.prototype=Object.create(br.prototype),Js.prototype.constructor=Js,Qs.prototype=Object.create(Zs.prototype),Qs.prototype.constructor=Qs,Ks.prototype=Object.create(br.prototype),Ks.prototype.constructor=Ks,$s.prototype=Object.create(Zs.prototype),$s.prototype.constructor=$s,ec.prototype=Object.create(br.prototype),ec.prototype.constructor=ec,tc.prototype=Object.create(Zs.prototype),tc.prototype.constructor=tc,nc.prototype=Object.create(br.prototype),nc.prototype.constructor=nc,ic.prototype=Object.create(Zs.prototype),ic.prototype.constructor=ic,rc.prototype=Object.create(br.prototype),rc.prototype.constructor=rc,ac.prototype=Object.create(Zi.prototype),ac.prototype.constructor=ac,ac.prototype.toJSON=function(){var e=Zi.prototype.toJSON.call(this);return e.path=this.parameters.path.toJSON(),e},oc.prototype=Object.create(br.prototype),oc.prototype.constructor=oc,sc.prototype=Object.create(Zi.prototype),sc.prototype.constructor=sc,cc.prototype=Object.create(br.prototype),cc.prototype.constructor=cc,lc.prototype=Object.create(Zi.prototype),lc.prototype.constructor=lc;var hc=function(e,t,n){n=n||2;var i,r,a,o,s,c,l,h=t&&t.length,u=h?t[0]*n:e.length,p=uc(e,0,u,n,!0),d=[];if(!p||p.next===p.prev)return d;if(h&&(p=function(e,t,n,i){var r,a,o,s,c,l=[];for(r=0,a=t.length;r80*n){i=a=e[0],r=o=e[1];for(var f=n;fa&&(a=s),c>o&&(o=c);l=0!==(l=Math.max(a-i,o-r))?1/l:0}return dc(p,d,n,i,r,l),d};function uc(e,t,n,i,r){var a,o;if(r===function(e,t,n,i){for(var r=0,a=t,o=n-i;a0)for(a=t;a=t;a-=i)o=Rc(a,e[a],e[a+1],o);return o&&Tc(o,o.next)&&(Pc(o),o=o.next),o}function pc(e,t){if(!e)return e;t||(t=e);var n,i=e;do{if(n=!1,i.steiner||!Tc(i,i.next)&&0!==Sc(i.prev,i,i.next))i=i.next;else{if(Pc(i),(i=t=i.prev)===i.next)break;n=!0}}while(n||i!==t);return t}function dc(e,t,n,i,r,a,o){if(e){!o&&a&&function(e,t,n,i){var r=e;do{null===r.z&&(r.z=bc(r.x,r.y,t,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==e);r.prevZ.nextZ=null,r.prevZ=null,function(e){var t,n,i,r,a,o,s,c,l=1;do{for(n=e,e=null,a=null,o=0;n;){for(o++,i=n,s=0,t=0;t0||c>0&&i;)0!==s&&(0===c||!i||n.z<=i.z)?(r=n,n=n.nextZ,s--):(r=i,i=i.nextZ,c--),a?a.nextZ=r:e=r,r.prevZ=a,a=r;n=i}a.nextZ=null,l*=2}while(o>1)}(r)}(e,i,r,a);for(var s,c,l=e;e.prev!==e.next;)if(s=e.prev,c=e.next,a?mc(e,i,r,a):fc(e))t.push(s.i/n),t.push(e.i/n),t.push(c.i/n),Pc(e),e=c.next,l=c.next;else if((e=c)===l){o?1===o?dc(e=gc(e,t,n),t,n,i,r,a,2):2===o&&vc(e,t,n,i,r,a):dc(pc(e),t,n,i,r,a,1);break}}}function fc(e){var t=e.prev,n=e,i=e.next;if(Sc(t,n,i)>=0)return!1;for(var r=e.next.next;r!==e.prev;){if(wc(t.x,t.y,n.x,n.y,i.x,i.y,r.x,r.y)&&Sc(r.prev,r,r.next)>=0)return!1;r=r.next}return!0}function mc(e,t,n,i){var r=e.prev,a=e,o=e.next;if(Sc(r,a,o)>=0)return!1;for(var s=r.xa.x?r.x>o.x?r.x:o.x:a.x>o.x?a.x:o.x,h=r.y>a.y?r.y>o.y?r.y:o.y:a.y>o.y?a.y:o.y,u=bc(s,c,t,n,i),p=bc(l,h,t,n,i),d=e.prevZ,f=e.nextZ;d&&d.z>=u&&f&&f.z<=p;){if(d!==e.prev&&d!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,d.x,d.y)&&Sc(d.prev,d,d.next)>=0)return!1;if(d=d.prevZ,f!==e.prev&&f!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,f.x,f.y)&&Sc(f.prev,f,f.next)>=0)return!1;f=f.nextZ}for(;d&&d.z>=u;){if(d!==e.prev&&d!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,d.x,d.y)&&Sc(d.prev,d,d.next)>=0)return!1;d=d.prevZ}for(;f&&f.z<=p;){if(f!==e.prev&&f!==e.next&&wc(r.x,r.y,a.x,a.y,o.x,o.y,f.x,f.y)&&Sc(f.prev,f,f.next)>=0)return!1;f=f.nextZ}return!0}function gc(e,t,n){var i=e;do{var r=i.prev,a=i.next.next;!Tc(r,a)&&Ec(r,i,i.next,a)&&Ac(r,a)&&Ac(a,r)&&(t.push(r.i/n),t.push(i.i/n),t.push(a.i/n),Pc(i),Pc(i.next),i=e=a),i=i.next}while(i!==e);return i}function vc(e,t,n,i,r,a){var o=e;do{for(var s=o.next.next;s!==o.prev;){if(o.i!==s.i&&Mc(o,s)){var c=Lc(o,s);return o=pc(o,o.next),c=pc(c,c.next),dc(o,t,n,i,r,a),void dc(c,t,n,i,r,a)}s=s.next}o=o.next}while(o!==e)}function yc(e,t){return e.x-t.x}function xc(e,t){if(t=function(e,t){var n,i=t,r=e.x,a=e.y,o=-1/0;do{if(a<=i.y&&a>=i.next.y&&i.next.y!==i.y){var s=i.x+(a-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(s<=r&&s>o){if(o=s,s===r){if(a===i.y)return i;if(a===i.next.y)return i.next}n=i.x=i.x&&i.x>=h&&r!==i.x&&wc(an.x)&&Ac(i,e)&&(n=i,p=c),i=i.next;return n}(e,t)){var n=Lc(t,e);pc(n,n.next)}}function bc(e,t,n,i,r){return(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=32767*(e-n)*r)|e<<8))|e<<4))|e<<2))|e<<1))|(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=32767*(t-i)*r)|t<<8))|t<<4))|t<<2))|t<<1))<<1}function _c(e){var t=e,n=e;do{(t.x=0&&(e-o)*(i-s)-(n-o)*(t-s)>=0&&(n-o)*(a-s)-(r-o)*(i-s)>=0}function Mc(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!function(e,t){var n=e;do{if(n.i!==e.i&&n.next.i!==e.i&&n.i!==t.i&&n.next.i!==t.i&&Ec(n,n.next,e,t))return!0;n=n.next}while(n!==e);return!1}(e,t)&&Ac(e,t)&&Ac(t,e)&&function(e,t){var n=e,i=!1,r=(e.x+t.x)/2,a=(e.y+t.y)/2;do{n.y>a!=n.next.y>a&&n.next.y!==n.y&&r<(n.next.x-n.x)*(a-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==e);return i}(e,t)}function Sc(e,t,n){return(t.y-e.y)*(n.x-t.x)-(t.x-e.x)*(n.y-t.y)}function Tc(e,t){return e.x===t.x&&e.y===t.y}function Ec(e,t,n,i){return!!(Tc(e,n)&&Tc(t,i)||Tc(e,i)&&Tc(n,t))||Sc(e,t,n)>0!=Sc(e,t,i)>0&&Sc(n,i,e)>0!=Sc(n,i,t)>0}function Ac(e,t){return Sc(e.prev,e,e.next)<0?Sc(e,t,e.next)>=0&&Sc(e,e.prev,t)>=0:Sc(e,t,e.prev)<0||Sc(e,e.next,t)<0}function Lc(e,t){var n=new Cc(e.i,e.x,e.y),i=new Cc(t.i,t.x,t.y),r=e.next,a=t.prev;return e.next=t,t.prev=e,n.next=r,r.prev=n,i.next=n,n.prev=i,a.next=i,i.prev=a,i}function Rc(e,t,n,i){var r=new Cc(e,t,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function Pc(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function Cc(e,t,n){this.i=e,this.x=t,this.y=n,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}var Oc={area:function(e){for(var t=e.length,n=0,i=t-1,r=0;r2&&e[t-1].equals(e[0])&&e.pop()}function Ic(e,t){for(var n=0;nNumber.EPSILON){var p=Math.sqrt(h),d=Math.sqrt(c*c+l*l),f=t.x-s/p,m=t.y+o/p,g=((n.x-l/d-f)*l-(n.y+c/d-m)*c)/(o*l-s*c),v=(i=f+o*g-e.x)*i+(r=m+s*g-e.y)*r;if(v<=2)return new qt(i,r);a=Math.sqrt(v/2)}else{var y=!1;o>Number.EPSILON?c>Number.EPSILON&&(y=!0):o<-Number.EPSILON?c<-Number.EPSILON&&(y=!0):Math.sign(s)===Math.sign(l)&&(y=!0),y?(i=-s,r=o,a=Math.sqrt(h)):(i=o,r=s,a=Math.sqrt(h/2))}return new qt(i/a,r/a)}for(var G=[],H=0,V=R.length,k=V-1,j=H+1;H=0;C--){for(D=C/d,I=h*Math.cos(D*Math.PI/2),O=u*Math.sin(D*Math.PI/2)+p,H=0,V=R.length;H=0;){n=H,(i=H-1)<0&&(i=e.length-1);var r=0,a=s+2*d;for(r=0;r0)&&f.push(w,M,T),(c!==n-1||l0&&v(!0),t>0&&v(!1)),this.setIndex(l),this.setAttribute("position",new Fi(h,3)),this.setAttribute("normal",new Fi(u,3)),this.setAttribute("uv",new Fi(p,2))}function $c(e,t,n,i,r,a,o){Qc.call(this,0,e,t,n,i,r,a,o),this.type="ConeGeometry",this.parameters={radius:e,height:t,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:a,thetaLength:o}}function el(e,t,n,i,r,a,o){Kc.call(this,0,e,t,n,i,r,a,o),this.type="ConeBufferGeometry",this.parameters={radius:e,height:t,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:a,thetaLength:o}}function tl(e,t,n,i){br.call(this),this.type="CircleGeometry",this.parameters={radius:e,segments:t,thetaStart:n,thetaLength:i},this.fromBufferGeometry(new nl(e,t,n,i)),this.mergeVertices()}function nl(e,t,n,i){Zi.call(this),this.type="CircleBufferGeometry",this.parameters={radius:e,segments:t,thetaStart:n,thetaLength:i},e=e||1,t=void 0!==t?Math.max(3,t):8,n=void 0!==n?n:0,i=void 0!==i?i:2*Math.PI;var r,a,o=[],s=[],c=[],l=[],h=new rn,u=new qt;for(s.push(0,0,0),c.push(0,0,1),l.push(.5,.5),a=0,r=3;a<=t;a++,r+=3){var p=n+a/t*i;h.x=e*Math.cos(p),h.y=e*Math.sin(p),s.push(h.x,h.y,h.z),c.push(0,0,1),u.x=(s[r]/e+1)/2,u.y=(s[r+1]/e+1)/2,l.push(u.x,u.y)}for(r=1;r<=t;r++)o.push(r,r+1,0);this.setIndex(o),this.setAttribute("position",new Fi(s,3)),this.setAttribute("normal",new Fi(c,3)),this.setAttribute("uv",new Fi(l,2))}Uc.prototype=Object.create(br.prototype),Uc.prototype.constructor=Uc,Gc.prototype=Object.create(Bc.prototype),Gc.prototype.constructor=Gc,Hc.prototype=Object.create(br.prototype),Hc.prototype.constructor=Hc,Vc.prototype=Object.create(Zi.prototype),Vc.prototype.constructor=Vc,kc.prototype=Object.create(br.prototype),kc.prototype.constructor=kc,jc.prototype=Object.create(Zi.prototype),jc.prototype.constructor=jc,Wc.prototype=Object.create(br.prototype),Wc.prototype.constructor=Wc,qc.prototype=Object.create(Zi.prototype),qc.prototype.constructor=qc,Xc.prototype=Object.create(br.prototype),Xc.prototype.constructor=Xc,Xc.prototype.toJSON=function(){var e=br.prototype.toJSON.call(this);return Zc(this.parameters.shapes,e)},Yc.prototype=Object.create(Zi.prototype),Yc.prototype.constructor=Yc,Yc.prototype.toJSON=function(){var e=Zi.prototype.toJSON.call(this);return Zc(this.parameters.shapes,e)},Jc.prototype=Object.create(Zi.prototype),Jc.prototype.constructor=Jc,Qc.prototype=Object.create(br.prototype),Qc.prototype.constructor=Qc,Kc.prototype=Object.create(Zi.prototype),Kc.prototype.constructor=Kc,$c.prototype=Object.create(Qc.prototype),$c.prototype.constructor=$c,el.prototype=Object.create(Kc.prototype),el.prototype.constructor=el,tl.prototype=Object.create(br.prototype),tl.prototype.constructor=tl,nl.prototype=Object.create(Zi.prototype),nl.prototype.constructor=nl;var il=Object.freeze({__proto__:null,WireframeGeometry:Ws,ParametricGeometry:qs,ParametricBufferGeometry:Xs,TetrahedronGeometry:Js,TetrahedronBufferGeometry:Qs,OctahedronGeometry:Ks,OctahedronBufferGeometry:$s,IcosahedronGeometry:ec,IcosahedronBufferGeometry:tc,DodecahedronGeometry:nc,DodecahedronBufferGeometry:ic,PolyhedronGeometry:Ys,PolyhedronBufferGeometry:Zs,TubeGeometry:rc,TubeBufferGeometry:ac,TorusKnotGeometry:oc,TorusKnotBufferGeometry:sc,TorusGeometry:cc,TorusBufferGeometry:lc,TextGeometry:Uc,TextBufferGeometry:Gc,SphereGeometry:Hc,SphereBufferGeometry:Vc,RingGeometry:kc,RingBufferGeometry:jc,PlaneGeometry:Vr,PlaneBufferGeometry:kr,LatheGeometry:Wc,LatheBufferGeometry:qc,ShapeGeometry:Xc,ShapeBufferGeometry:Yc,ExtrudeGeometry:Nc,ExtrudeBufferGeometry:Bc,EdgesGeometry:Jc,ConeGeometry:$c,ConeBufferGeometry:el,CylinderGeometry:Qc,CylinderBufferGeometry:Kc,CircleGeometry:tl,CircleBufferGeometry:nl,BoxGeometry:_r,BoxBufferGeometry:wr});function rl(e){Ai.call(this),this.type="ShadowMaterial",this.color=new _i(0),this.transparent=!0,this.setValues(e)}function al(e){Lr.call(this,e),this.type="RawShaderMaterial"}function ol(e){Ai.call(this),this.defines={STANDARD:""},this.type="MeshStandardMaterial",this.color=new _i(16777215),this.roughness=1,this.metalness=0,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.roughnessMap=null,this.metalnessMap=null,this.alphaMap=null,this.envMap=null,this.envMapIntensity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.vertexTangents=!1,this.setValues(e)}function sl(e){ol.call(this),this.defines={STANDARD:"",PHYSICAL:""},this.type="MeshPhysicalMaterial",this.reflectivity=.5,this.clearcoat=0,this.clearcoatRoughness=0,this.sheen=null,this.clearcoatNormalScale=new qt(1,1),this.clearcoatNormalMap=null,this.transparency=0,this.setValues(e)}function cl(e){Ai.call(this),this.type="MeshPhongMaterial",this.color=new _i(16777215),this.specular=new _i(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=G,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function ll(e){Ai.call(this),this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new _i(16777215),this.specular=new _i(1118481),this.shininess=30,this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function hl(e){Ai.call(this),this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function ul(e){Ai.call(this),this.type="MeshLambertMaterial",this.color=new _i(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new _i(0),this.emissiveIntensity=1,this.emissiveMap=null,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=G,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function pl(e){Ai.call(this),this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new _i(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Nt,this.normalScale=new qt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(e)}function dl(e){Ms.call(this),this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}rl.prototype=Object.create(Ai.prototype),rl.prototype.constructor=rl,rl.prototype.isShadowMaterial=!0,rl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this},al.prototype=Object.create(Lr.prototype),al.prototype.constructor=al,al.prototype.isRawShaderMaterial=!0,ol.prototype=Object.create(Ai.prototype),ol.prototype.constructor=ol,ol.prototype.isMeshStandardMaterial=!0,ol.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.defines={STANDARD:""},this.color.copy(e.color),this.roughness=e.roughness,this.metalness=e.metalness,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.roughnessMap=e.roughnessMap,this.metalnessMap=e.metalnessMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapIntensity=e.envMapIntensity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this.vertexTangents=e.vertexTangents,this},sl.prototype=Object.create(ol.prototype),sl.prototype.constructor=sl,sl.prototype.isMeshPhysicalMaterial=!0,sl.prototype.copy=function(e){return ol.prototype.copy.call(this,e),this.defines={STANDARD:"",PHYSICAL:""},this.reflectivity=e.reflectivity,this.clearcoat=e.clearcoat,this.clearcoatRoughness=e.clearcoatRoughness,e.sheen?this.sheen=(this.sheen||new _i).copy(e.sheen):this.sheen=null,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.transparency=e.transparency,this},cl.prototype=Object.create(Ai.prototype),cl.prototype.constructor=cl,cl.prototype.isMeshPhongMaterial=!0,cl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},ll.prototype=Object.create(Ai.prototype),ll.prototype.constructor=ll,ll.prototype.isMeshToonMaterial=!0,ll.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},hl.prototype=Object.create(Ai.prototype),hl.prototype.constructor=hl,hl.prototype.isMeshNormalMaterial=!0,hl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},ul.prototype=Object.create(Ai.prototype),ul.prototype.constructor=ul,ul.prototype.isMeshLambertMaterial=!0,ul.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},pl.prototype=Object.create(Ai.prototype),pl.prototype.constructor=pl,pl.prototype.isMeshMatcapMaterial=!0,pl.prototype.copy=function(e){return Ai.prototype.copy.call(this,e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.skinning=e.skinning,this.morphTargets=e.morphTargets,this.morphNormals=e.morphNormals,this},dl.prototype=Object.create(Ms.prototype),dl.prototype.constructor=dl,dl.prototype.isLineDashedMaterial=!0,dl.prototype.copy=function(e){return Ms.prototype.copy.call(this,e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this};var fl=Object.freeze({__proto__:null,ShadowMaterial:rl,SpriteMaterial:Zo,RawShaderMaterial:al,ShaderMaterial:Lr,PointsMaterial:Is,MeshPhysicalMaterial:sl,MeshStandardMaterial:ol,MeshPhongMaterial:cl,MeshToonMaterial:ll,MeshNormalMaterial:hl,MeshLambertMaterial:ul,MeshDepthMaterial:Co,MeshDistanceMaterial:Oo,MeshBasicMaterial:Li,MeshMatcapMaterial:pl,LineDashedMaterial:dl,LineBasicMaterial:Ms,Material:Ai}),ml={arraySlice:function(e,t,n){return ml.isTypedArray(e)?new e.constructor(e.subarray(t,void 0!==n?n:e.length)):e.slice(t,n)},convertArray:function(e,t,n){return!e||!n&&e.constructor===t?e:"number"==typeof t.BYTES_PER_ELEMENT?new t(e):Array.prototype.slice.call(e)},isTypedArray:function(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)},getKeyframeOrder:function(e){for(var t=e.length,n=new Array(t),i=0;i!==t;++i)n[i]=i;return n.sort(function(t,n){return e[t]-e[n]}),n},sortedArray:function(e,t,n){for(var i=e.length,r=new e.constructor(i),a=0,o=0;o!==i;++a)for(var s=n[a]*t,c=0;c!==t;++c)r[o++]=e[s+c];return r},flattenJSON:function(e,t,n,i){for(var r=1,a=e[0];void 0!==a&&void 0===a[i];)a=e[r++];if(void 0!==a){var o=a[i];if(void 0!==o)if(Array.isArray(o))do{void 0!==(o=a[i])&&(t.push(a.time),n.push.apply(n,o)),a=e[r++]}while(void 0!==a);else if(void 0!==o.toArray)do{void 0!==(o=a[i])&&(t.push(a.time),o.toArray(n,n.length)),a=e[r++]}while(void 0!==a);else do{void 0!==(o=a[i])&&(t.push(a.time),n.push(o)),a=e[r++]}while(void 0!==a)}},subclip:function(e,t,n,i,r){r=r||30;var a=e.clone();a.name=t;for(var o=[],s=0;s=i)){h.push(c.times[p]);for(var f=0;fa.tracks[s].times[0]&&(m=a.tracks[s].times[0]);for(s=0;s=r)break e;var s=t[1];e=(r=t[--n-1]))break t}a=n,n=0}for(;n>>1;et;)--a;if(++a,0!==r||a!==i){r>=a&&(r=(a=Math.max(a,1))-1);var o=this.getValueSize();this.times=ml.arraySlice(n,r,a),this.values=ml.arraySlice(this.values,r*o,a*o)}return this},validate:function(){var e=!0,t=this.getValueSize();t-Math.floor(t)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);var n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);for(var a=null,o=0;o!==r;o++){var s=n[o];if("number"==typeof s&&isNaN(s)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,o,s),e=!1;break}if(null!==a&&a>s){console.error("THREE.KeyframeTrack: Out of order keys.",this,o,s,a),e=!1;break}a=s}if(void 0!==i&&ml.isTypedArray(i)){o=0;for(var c=i.length;o!==c;++o){var l=i[o];if(isNaN(l)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,o,l),e=!1;break}}}return e},optimize:function(){for(var e=ml.arraySlice(this.times),t=ml.arraySlice(this.values),n=this.getValueSize(),i=2302===this.getInterpolation(),r=1,a=e.length-1,o=1;o0){e[r]=e[a];for(f=a*n,m=r*n,p=0;p!==n;++p)t[m+p]=t[f+p];++r}return r!==e.length?(this.times=ml.arraySlice(e,0,r),this.values=ml.arraySlice(t,0,r*n)):(this.times=e,this.values=t),this},clone:function(){var e=ml.arraySlice(this.times,0),t=ml.arraySlice(this.values,0),n=new(0,this.constructor)(this.name,e,t);return n.createInterpolant=this.createInterpolant,n}}),_l.prototype=Object.assign(Object.create(bl.prototype),{constructor:_l,ValueTypeName:"bool",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),wl.prototype=Object.assign(Object.create(bl.prototype),{constructor:wl,ValueTypeName:"color"}),Ml.prototype=Object.assign(Object.create(bl.prototype),{constructor:Ml,ValueTypeName:"number"}),Sl.prototype=Object.assign(Object.create(gl.prototype),{constructor:Sl,interpolate_:function(e,t,n,i){for(var r=this.resultBuffer,a=this.sampleValues,o=this.valueSize,s=e*o,c=(n-t)/(i-t),l=s+o;s!==l;s+=4)en.slerpFlat(r,0,a,s-o,a,s,c);return r}}),Tl.prototype=Object.assign(Object.create(bl.prototype),{constructor:Tl,ValueTypeName:"quaternion",DefaultInterpolation:2301,InterpolantFactoryMethodLinear:function(e){return new Sl(this.times,this.values,this.getValueSize(),e)},InterpolantFactoryMethodSmooth:void 0}),El.prototype=Object.assign(Object.create(bl.prototype),{constructor:El,ValueTypeName:"string",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),Al.prototype=Object.assign(Object.create(bl.prototype),{constructor:Al,ValueTypeName:"vector"}),Object.assign(Ll,{parse:function(e){for(var t=[],n=e.tracks,i=1/(e.fps||1),r=0,a=n.length;r!==a;++r)t.push(Rl(n[r]).scale(i));return new Ll(e.name,e.duration,t)},toJSON:function(e){for(var t=[],n=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid},r=0,a=n.length;r!==a;++r)t.push(bl.toJSON(n[r]));return i},CreateFromMorphTargetSequence:function(e,t,n,i){for(var r=t.length,a=[],o=0;o1){var l=i[u=c[1]];l||(i[u]=l=[]),l.push(s)}}var h=[];for(var u in i)h.push(Ll.CreateFromMorphTargetSequence(u,i[u],t,n));return h},parseAnimation:function(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;for(var n=function(e,t,n,i,r){if(0!==n.length){var a=[],o=[];ml.flattenJSON(n,a,o,i),0!==a.length&&r.push(new e(t,a,o))}},i=[],r=e.name||"default",a=e.length||-1,o=e.fps||30,s=e.hierarchy||[],c=0;c0||0===e.search(/^data\:image\/jpeg/);r.format=i?Se:Te,r.needsUpdate=!0,void 0!==t&&t(r)},n,i),r}}),Object.assign(Vl.prototype,{getPoint:function(){return console.warn("THREE.Curve: .getPoint() not implemented."),null},getPointAt:function(e,t){var n=this.getUtoTmapping(e);return this.getPoint(n,t)},getPoints:function(e){void 0===e&&(e=5);for(var t=[],n=0;n<=e;n++)t.push(this.getPoint(n/e));return t},getSpacedPoints:function(e){void 0===e&&(e=5);for(var t=[],n=0;n<=e;n++)t.push(this.getPointAt(n/e));return t},getLength:function(){var e=this.getLengths();return e[e.length-1]},getLengths:function(e){if(void 0===e&&(e=this.arcLengthDivisions),this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var t,n,i=[],r=this.getPoint(0),a=0;for(i.push(0),n=1;n<=e;n++)a+=(t=this.getPoint(n/e)).distanceTo(r),i.push(a),r=t;return this.cacheArcLengths=i,i},updateArcLengths:function(){this.needsUpdate=!0,this.getLengths()},getUtoTmapping:function(e,t){var n,i=this.getLengths(),r=0,a=i.length;n=t||e*i[a-1];for(var o,s=0,c=a-1;s<=c;)if((o=i[r=Math.floor(s+(c-s)/2)]-n)<0)s=r+1;else{if(!(o>0)){c=r;break}c=r-1}if(i[r=c]===n)return r/(a-1);var l=i[r];return(r+(n-l)/(i[r+1]-l))/(a-1)},getTangent:function(e){var t=e-1e-4,n=e+1e-4;t<0&&(t=0),n>1&&(n=1);var i=this.getPoint(t);return this.getPoint(n).clone().sub(i).normalize()},getTangentAt:function(e){var t=this.getUtoTmapping(e);return this.getTangent(t)},computeFrenetFrames:function(e,t){var n,i,r,a=new rn,o=[],s=[],c=[],l=new rn,h=new pn;for(n=0;n<=e;n++)i=n/e,o[n]=this.getTangentAt(i),o[n].normalize();s[0]=new rn,c[0]=new rn;var u=Number.MAX_VALUE,p=Math.abs(o[0].x),d=Math.abs(o[0].y),f=Math.abs(o[0].z);for(p<=u&&(u=p,a.set(1,0,0)),d<=u&&(u=d,a.set(0,1,0)),f<=u&&a.set(0,0,1),l.crossVectors(o[0],a).normalize(),s[0].crossVectors(o[0],l),c[0].crossVectors(o[0],s[0]),n=1;n<=e;n++)s[n]=s[n-1].clone(),c[n]=c[n-1].clone(),l.crossVectors(o[n-1],o[n]),l.length()>Number.EPSILON&&(l.normalize(),r=Math.acos(Wt.clamp(o[n-1].dot(o[n]),-1,1)),s[n].applyMatrix4(h.makeRotationAxis(l,r))),c[n].crossVectors(o[n],s[n]);if(!0===t)for(r=Math.acos(Wt.clamp(s[0].dot(s[e]),-1,1)),r/=e,o[0].dot(l.crossVectors(s[0],s[e]))>0&&(r=-r),n=1;n<=e;n++)s[n].applyMatrix4(h.makeRotationAxis(o[n],r*n)),c[n].crossVectors(o[n],s[n]);return{tangents:o,normals:s,binormals:c}},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.arcLengthDivisions=e.arcLengthDivisions,this},toJSON:function(){var e={metadata:{version:4.5,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e},fromJSON:function(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}}),kl.prototype=Object.create(Vl.prototype),kl.prototype.constructor=kl,kl.prototype.isEllipseCurve=!0,kl.prototype.getPoint=function(e,t){for(var n=t||new qt,i=2*Math.PI,r=this.aEndAngle-this.aStartAngle,a=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/c)+1)*c:0===u&&h===c-1&&(h=c-2,u=1),this.closed||h>0?n=s[(h-1)%c]:(ql.subVectors(s[0],s[1]).add(s[0]),n=ql),i=s[h%c],r=s[(h+1)%c],this.closed||h+2i.length-2?i.length-1:a+1],h=i[a>i.length-3?i.length-1:a+2];return n.set(Ql(o,s.x,c.x,l.x,h.x),Ql(o,s.y,c.y,l.y,h.y)),n},oh.prototype.copy=function(e){Vl.prototype.copy.call(this,e),this.points=[];for(var t=0,n=e.points.length;t=t){var r=n[i]-t,a=this.curves[i],o=a.getLength(),s=0===o?0:1-r/o;return a.getPointAt(s)}i++}return null},getLength:function(){var e=this.getCurveLengths();return e[e.length-1]},updateArcLengths:function(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var e=[],t=0,n=0,i=this.curves.length;n1&&!n[n.length-1].equals(n[0])&&n.push(n[0]),n},copy:function(e){Vl.prototype.copy.call(this,e),this.curves=[];for(var t=0,n=e.curves.length;t0){var l=c.getPoint(0);l.equals(this.currentPoint)||this.lineTo(l.x,l.y)}this.curves.push(c);var h=c.getPoint(1);return this.currentPoint.copy(h),this},copy:function(e){return ch.prototype.copy.call(this,e),this.currentPoint.copy(e.currentPoint),this},toJSON:function(){var e=ch.prototype.toJSON.call(this);return e.currentPoint=this.currentPoint.toArray(),e},fromJSON:function(e){return ch.prototype.fromJSON.call(this,e),this.currentPoint.fromArray(e.currentPoint),this}}),hh.prototype=Object.assign(Object.create(lh.prototype),{constructor:hh,getPointsHoles:function(e){for(var t=[],n=0,i=this.holes.length;n0:i.vertexColors=e.vertexColors),void 0!==e.uniforms)for(var r in e.uniforms){var a=e.uniforms[r];switch(i.uniforms[r]={},a.type){case"t":i.uniforms[r].value=n(a.value);break;case"c":i.uniforms[r].value=(new _i).setHex(a.value);break;case"v2":i.uniforms[r].value=(new qt).fromArray(a.value);break;case"v3":i.uniforms[r].value=(new rn).fromArray(a.value);break;case"v4":i.uniforms[r].value=(new Qt).fromArray(a.value);break;case"m3":i.uniforms[r].value=(new Xt).fromArray(a.value);case"m4":i.uniforms[r].value=(new pn).fromArray(a.value);break;default:i.uniforms[r].value=a.value}}if(void 0!==e.defines&&(i.defines=e.defines),void 0!==e.vertexShader&&(i.vertexShader=e.vertexShader),void 0!==e.fragmentShader&&(i.fragmentShader=e.fragmentShader),void 0!==e.extensions)for(var o in e.extensions)i.extensions[o]=e.extensions[o];if(void 0!==e.shading&&(i.flatShading=1===e.shading),void 0!==e.size&&(i.size=e.size),void 0!==e.sizeAttenuation&&(i.sizeAttenuation=e.sizeAttenuation),void 0!==e.map&&(i.map=n(e.map)),void 0!==e.matcap&&(i.matcap=n(e.matcap)),void 0!==e.alphaMap&&(i.alphaMap=n(e.alphaMap)),void 0!==e.bumpMap&&(i.bumpMap=n(e.bumpMap)),void 0!==e.bumpScale&&(i.bumpScale=e.bumpScale),void 0!==e.normalMap&&(i.normalMap=n(e.normalMap)),void 0!==e.normalMapType&&(i.normalMapType=e.normalMapType),void 0!==e.normalScale){var s=e.normalScale;!1===Array.isArray(s)&&(s=[s,s]),i.normalScale=(new qt).fromArray(s)}return void 0!==e.displacementMap&&(i.displacementMap=n(e.displacementMap)),void 0!==e.displacementScale&&(i.displacementScale=e.displacementScale),void 0!==e.displacementBias&&(i.displacementBias=e.displacementBias),void 0!==e.roughnessMap&&(i.roughnessMap=n(e.roughnessMap)),void 0!==e.metalnessMap&&(i.metalnessMap=n(e.metalnessMap)),void 0!==e.emissiveMap&&(i.emissiveMap=n(e.emissiveMap)),void 0!==e.emissiveIntensity&&(i.emissiveIntensity=e.emissiveIntensity),void 0!==e.specularMap&&(i.specularMap=n(e.specularMap)),void 0!==e.envMap&&(i.envMap=n(e.envMap)),void 0!==e.envMapIntensity&&(i.envMapIntensity=e.envMapIntensity),void 0!==e.reflectivity&&(i.reflectivity=e.reflectivity),void 0!==e.refractionRatio&&(i.refractionRatio=e.refractionRatio),void 0!==e.lightMap&&(i.lightMap=n(e.lightMap)),void 0!==e.lightMapIntensity&&(i.lightMapIntensity=e.lightMapIntensity),void 0!==e.aoMap&&(i.aoMap=n(e.aoMap)),void 0!==e.aoMapIntensity&&(i.aoMapIntensity=e.aoMapIntensity),void 0!==e.gradientMap&&(i.gradientMap=n(e.gradientMap)),void 0!==e.clearcoatNormalMap&&(i.clearcoatNormalMap=n(e.clearcoatNormalMap)),void 0!==e.clearcoatNormalScale&&(i.clearcoatNormalScale=(new qt).fromArray(e.clearcoatNormalScale)),i},setTextures:function(e){return this.textures=e,this}});var Sh={decodeText:function(e){if("undefined"!=typeof TextDecoder)return(new TextDecoder).decode(e);for(var t="",n=0,i=e.length;n0){var a=new Ul(new Cl(t));a.setCrossOrigin(this.crossOrigin);for(var o=0,s=e.length;o0?new ds(o,s):new dr(o,s);break;case"InstancedMesh":o=r(e.geometry),s=a(e.material);var c=e.count,l=e.instanceMatrix;(i=new ws(o,s,c)).instanceMatrix=new Pi(new Float32Array(l.array),16);break;case"LOD":i=new ps;break;case"Line":i=new Rs(r(e.geometry),a(e.material),e.mode);break;case"LineLoop":i=new Ds(r(e.geometry),a(e.material));break;case"LineSegments":i=new Os(r(e.geometry),a(e.material));break;case"PointCloud":case"Points":i=new Us(r(e.geometry),a(e.material));break;case"Sprite":i=new cs(a(e.material));break;case"Group":i=new Go;break;default:i=new Pn}if(i.uuid=e.uuid,void 0!==e.name&&(i.name=e.name),void 0!==e.matrix?(i.matrix.fromArray(e.matrix),void 0!==e.matrixAutoUpdate&&(i.matrixAutoUpdate=e.matrixAutoUpdate),i.matrixAutoUpdate&&i.matrix.decompose(i.position,i.quaternion,i.scale)):(void 0!==e.position&&i.position.fromArray(e.position),void 0!==e.rotation&&i.rotation.fromArray(e.rotation),void 0!==e.quaternion&&i.quaternion.fromArray(e.quaternion),void 0!==e.scale&&i.scale.fromArray(e.scale)),void 0!==e.castShadow&&(i.castShadow=e.castShadow),void 0!==e.receiveShadow&&(i.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.bias&&(i.shadow.bias=e.shadow.bias),void 0!==e.shadow.radius&&(i.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&i.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(i.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(i.visible=e.visible),void 0!==e.frustumCulled&&(i.frustumCulled=e.frustumCulled),void 0!==e.renderOrder&&(i.renderOrder=e.renderOrder),void 0!==e.userData&&(i.userData=e.userData),void 0!==e.layers&&(i.layers.mask=e.layers),void 0!==e.children)for(var h=e.children,u=0;uNumber.EPSILON){if(l<0&&(o=t[a],c=-c,s=t[r],l=-l),e.ys.y)continue;if(e.y===o.y){if(e.x===o.x)return!0}else{var h=l*(e.x-o.x)-c*(e.y-o.y);if(0===h)return!0;if(h<0)continue;i=!i}}else{if(e.y!==o.y)continue;if(s.x<=e.x&&e.x<=o.x||o.x<=e.x&&e.x<=s.x)return!0}}return i}var r=Oc.isClockWise,a=this.subPaths;if(0===a.length)return[];if(!0===t)return n(a);var o,s,c,l=[];if(1===a.length)return s=a[0],(c=new hh).curves=s.curves,l.push(c),l;var h=!r(a[0].getPoints());h=e?!h:h;var u,p,d=[],f=[],m=[],g=0;f[g]=void 0,m[g]=[];for(var v=0,y=a.length;v1){for(var x=!1,b=[],_=0,w=f.length;_0&&(x||(m=d))}v=0;for(var L=f.length;v0){this.source.connect(this.filters[0]);for(var e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(var e=1,t=this.filters.length;e=.5)for(var a=0;a!==r;++a)e[t+a]=e[n+a]},_slerp:function(e,t,n,i){en.slerpFlat(e,t,e,t,e,n,i)},_lerp:function(e,t,n,i,r){for(var a=1-i,o=0;o!==r;++o){var s=t+o;e[s]=e[s]*a+e[n+o]*i}}});var cu=new RegExp("[\\[\\]\\.:\\/]","g"),lu="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",hu=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]"),uu=/(WCOD+)?/.source.replace("WCOD",lu),pu=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),du=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"),fu=new RegExp("^"+hu+uu+pu+du+"$"),mu=["material","materials","bones"];function gu(e,t,n){var i=n||vu.parseTrackName(t);this._targetGroup=e,this._bindings=e.subscribe_(t,i)}function vu(e,t,n){this.path=t,this.parsedPath=n||vu.parseTrackName(t),this.node=vu.findNode(e,this.parsedPath.nodeName)||e,this.rootNode=e}function yu(){this.uuid=Wt.generateUUID(),this._objects=Array.prototype.slice.call(arguments),this.nCachedObjects_=0;var e={};this._indicesByUUID=e;for(var t=0,n=arguments.length;t!==n;++t)e[arguments[t].uuid]=t;this._paths=[],this._parsedPaths=[],this._bindings=[],this._bindingsIndicesByPath={};var i=this;this.stats={objects:{get total(){return i._objects.length},get inUse(){return this.total-i.nCachedObjects_}},get bindingsPerObject(){return i._bindings.length}}}function xu(e,t,n){this._mixer=e,this._clip=t,this._localRoot=n||null;for(var i=t.tracks,r=i.length,a=new Array(r),o={endingStart:St,endingEnd:St},s=0;s!==r;++s){var c=i[s].createInterpolant(null);a[s]=c,c.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(r),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=Mt,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}function bu(e){this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}function _u(e){"string"==typeof e&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),e=arguments[1]),this.value=e}function wu(e,t,n){Wo.call(this,e,t),this.meshPerAttribute=n||1}function Mu(e,t,n,i){this.ray=new ni(e,t),this.near=n||0,this.far=i||1/0,this.camera=null,this.layers=new gn,this.params={Mesh:{},Line:{threshold:1},LOD:{},Points:{threshold:1},Sprite:{}},Object.defineProperties(this.params,{PointCloud:{get:function(){return console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points."),this.Points}}})}function Su(e,t){return e.distance-t.distance}function Tu(e,t,n,i){if(e.layers.test(t.layers)&&e.raycast(t,n),!0===i)for(var r=e.children,a=0,o=r.length;a=t){var h=t++,u=e[h];n[u.uuid]=l,e[l]=u,n[c]=h,e[h]=s;for(var p=0,d=r;p!==d;++p){var f=i[p],m=f[h],g=f[l];f[l]=m,f[h]=g}}}this.nCachedObjects_=t},uncache:function(){for(var e=this._objects,t=e.length,n=this.nCachedObjects_,i=this._indicesByUUID,r=this._bindings,a=r.length,o=0,s=arguments.length;o!==s;++o){var c=arguments[o].uuid,l=i[c];if(void 0!==l)if(delete i[c],l0)for(var c=this._interpolants,l=this._propertyBindings,h=0,u=c.length;h!==u;++h)c[h].evaluate(o),l[h].accumulate(i,s)}else this._updateWeight(e)},_updateWeight:function(e){var t=0;if(this.enabled){t=this.weight;var n=this._weightInterpolant;if(null!==n){var i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=t,t},_updateTimeScale:function(e){var t=0;if(!this.paused){t=this.timeScale;var n=this._timeScaleInterpolant;if(null!==n)t*=n.evaluate(e)[0],e>n.parameterPositions[1]&&(this.stopWarping(),0===t?this.paused=!0:this.timeScale=t)}return this._effectiveTimeScale=t,t},_updateTime:function(e){var t=this.time+e,n=this._clip.duration,i=this.loop,r=this._loopCount,a=2202===i;if(0===e)return-1===r?t:a&&1==(1&r)?n-t:t;if(2200===i){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(t>=n)t=n;else{if(!(t<0)){this.time=t;break e}t=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=t,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(-1===r&&(e>=0?(r=0,this._setEndings(!0,0===this.repetitions,a)):this._setEndings(0===this.repetitions,!0,a)),t>=n||t<0){var o=Math.floor(t/n);t-=n*o,r+=Math.abs(o);var s=this.repetitions-r;if(s<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,t=e>0?n:0,this.time=t,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(1===s){var c=e<0;this._setEndings(c,!c,a)}else this._setEndings(!1,!1,a);this._loopCount=r,this.time=t,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:o})}}else this.time=t;if(a&&1==(1&r))return n-t}return t},_setEndings:function(e,t,n){var i=this._interpolantSettings;n?(i.endingStart=2401,i.endingEnd=2401):(i.endingStart=e?this.zeroSlopeAtStart?2401:St:2402,i.endingEnd=t?this.zeroSlopeAtEnd?2401:St:2402)},_scheduleFading:function(e,t,n){var i=this._mixer,r=i.time,a=this._weightInterpolant;null===a&&(a=i._lendControlInterpolant(),this._weightInterpolant=a);var o=a.parameterPositions,s=a.sampleValues;return o[0]=r,s[0]=t,o[1]=r+e,s[1]=n,this}}),bu.prototype=Object.assign(Object.create(Ht.prototype),{constructor:bu,_bindAction:function(e,t){var n=e._localRoot||this._root,i=e._clip.tracks,r=i.length,a=e._propertyBindings,o=e._interpolants,s=n.uuid,c=this._bindingsByRootAndName,l=c[s];void 0===l&&(l={},c[s]=l);for(var h=0;h!==r;++h){var u=i[h],p=u.name,d=l[p];if(void 0!==d)a[h]=d;else{if(void 0!==(d=a[h])){null===d._cacheIndex&&(++d.referenceCount,this._addInactiveBinding(d,s,p));continue}var f=t&&t._propertyBindings[h].binding.parsedPath;++(d=new su(vu.create(n,p,f),u.ValueTypeName,u.getValueSize())).referenceCount,this._addInactiveBinding(d,s,p),a[h]=d}o[h].resultBuffer=d.buffer}},_activateAction:function(e){if(!this._isActiveAction(e)){if(null===e._cacheIndex){var t=(e._localRoot||this._root).uuid,n=e._clip.uuid,i=this._actionsByClip[n];this._bindAction(e,i&&i.knownActions[0]),this._addInactiveAction(e,n,t)}for(var r=e._propertyBindings,a=0,o=r.length;a!==o;++a){var s=r[a];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(e)}},_deactivateAction:function(e){if(this._isActiveAction(e)){for(var t=e._propertyBindings,n=0,i=t.length;n!==i;++n){var r=t[n];0==--r.useCount&&(r.restoreOriginalState(),this._takeBackBinding(r))}this._takeBackAction(e)}},_initMemoryManager:function(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;var e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}},_isActiveAction:function(e){var t=e._cacheIndex;return null!==t&&tthis.max.x||e.ythis.max.y)},containsBox:function(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y},getParameter:function(e,t){return void 0===t&&(console.warn("THREE.Box2: .getParameter() target is now required"),t=new qt),t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(e){return!(e.max.xthis.max.x||e.max.ythis.max.y)},clampPoint:function(e,t){return void 0===t&&(console.warn("THREE.Box2: .clampPoint() target is now required"),t=new qt),t.copy(e).clamp(this.min,this.max)},distanceToPoint:function(e){return Lu.copy(e).clamp(this.min,this.max).sub(e).length()},intersect:function(e){return this.min.max(e.min),this.max.min(e.max),this},union:function(e){return this.min.min(e.min),this.max.max(e.max),this},translate:function(e){return this.min.add(e),this.max.add(e),this},equals:function(e){return e.min.equals(this.min)&&e.max.equals(this.max)}});var Pu=new rn,Cu=new rn;function Ou(e,t){this.start=void 0!==e?e:new rn,this.end=void 0!==t?t:new rn}function Du(e){Pn.call(this),this.material=e,this.render=function(){}}Object.assign(Ou.prototype,{set:function(e,t){return this.start.copy(e),this.end.copy(t),this},clone:function(){return(new this.constructor).copy(this)},copy:function(e){return this.start.copy(e.start),this.end.copy(e.end),this},getCenter:function(e){return void 0===e&&(console.warn("THREE.Line3: .getCenter() target is now required"),e=new rn),e.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(e){return void 0===e&&(console.warn("THREE.Line3: .delta() target is now required"),e=new rn),e.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(e,t){return void 0===t&&(console.warn("THREE.Line3: .at() target is now required"),t=new rn),this.delta(t).multiplyScalar(e).add(this.start)},closestPointToPointParameter:function(e,t){Pu.subVectors(e,this.start),Cu.subVectors(this.end,this.start);var n=Cu.dot(Cu),i=Cu.dot(Pu)/n;return t&&(i=Wt.clamp(i,0,1)),i},closestPointToPoint:function(e,t,n){var i=this.closestPointToPointParameter(e,t);return void 0===n&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),n=new rn),this.delta(n).multiplyScalar(i).add(this.start)},applyMatrix4:function(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this},equals:function(e){return e.start.equals(this.start)&&e.end.equals(this.end)}}),Du.prototype=Object.create(Pn.prototype),Du.prototype.constructor=Du,Du.prototype.isImmediateRenderObject=!0;var Iu=new rn;function Nu(e,t){Pn.call(this),this.light=e,this.light.updateMatrixWorld(),this.matrix=e.matrixWorld,this.matrixAutoUpdate=!1,this.color=t;for(var n=new Zi,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1],r=0,a=1;r<32;r++,a++){var o=r/32*Math.PI*2,s=a/32*Math.PI*2;i.push(Math.cos(o),Math.sin(o),1,Math.cos(s),Math.sin(s),1)}n.setAttribute("position",new Fi(i,3));var c=new Ms({fog:!1});this.cone=new Os(n,c),this.add(this.cone),this.update()}Nu.prototype=Object.create(Pn.prototype),Nu.prototype.constructor=Nu,Nu.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},Nu.prototype.update=function(){this.light.updateMatrixWorld();var e=this.light.distance?this.light.distance:1e3,t=e*Math.tan(this.light.angle);this.cone.scale.set(t,t,e),Iu.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(Iu),void 0!==this.color?this.cone.material.color.set(this.color):this.cone.material.color.copy(this.light.color)};var Bu=new rn,zu=new pn,Fu=new pn;function Uu(e){for(var t=function e(t){var n=[];t&&t.isBone&&n.push(t);for(var i=0;i.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{sp.set(e.z,0,-e.x).normalize();var t=Math.acos(e.y);this.quaternion.setFromAxisAngle(sp,t)}},cp.prototype.setLength=function(e,t,n){void 0===t&&(t=.2*e),void 0===n&&(n=.2*t),this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(n,t,n),this.cone.position.y=e,this.cone.updateMatrix()},cp.prototype.setColor=function(e){this.line.material.color.set(e),this.cone.material.color.set(e)},cp.prototype.copy=function(e){return Pn.prototype.copy.call(this,e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this},cp.prototype.clone=function(){return(new this.constructor).copy(this)},lp.prototype=Object.create(Os.prototype),lp.prototype.constructor=lp;var hp=4,up=8,pp=Math.pow(2,up),dp=[.125,.215,.35,.446,.526,.582],fp=up-hp+1+dp.length,mp=20,gp={};gp[Tt]=0,gp[Et]=1,gp[Lt]=2,gp[Pt]=3,gp[Ct]=4,gp[Ot]=5,gp[At]=6;var vp,yp,xp,bp,_p=new yh,wp=(vp=mp,yp=new Float32Array(vp),xp=new rn(0,1,0),(bp=new al({defines:{n:vp},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:yp},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:xp},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform sampler2D envMap;\nuniform int samples;\nuniform float weights[n];\nuniform bool latitudinal;\nuniform float dTheta;\nuniform float mipInt;\nuniform vec3 poleAxis;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\n#define ENVMAP_TYPE_CUBE_UV\n#include \n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tfor (int i = 0; i < n; i++) {\n\t\tif (i >= samples)\n\t\t\tbreak;\n\t\tfor (int dir = -1; dir < 2; dir += 2) {\n\t\t\tif (i == 0 && dir == 1)\n\t\t\t\tcontinue;\n\t\t\tvec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection);\n\t\t\tif (all(equal(axis, vec3(0.0))))\n\t\t\t\taxis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection);\n\t\t\taxis = normalize(axis);\n\t\t\tfloat theta = dTheta * float(dir * i);\n\t\t\tfloat cosTheta = cos(theta);\n\t\t\t// Rodrigues' axis-angle rotation\n\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross(axis, vOutputDirection) * sin(theta)\n\t\t\t\t\t+ axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);\n\t\t\tgl_FragColor.rgb +=\n\t\t\t\t\tweights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);\n\t\t}\n\t}\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1})).type="SphericalGaussianBlur",bp),Mp=null,Sp=null,Tp=function(){for(var e=[],t=[],n=[],i=up,r=0;rup-hp?o=dp[r-up+hp-1]:0==r&&(o=0),n.push(o);for(var s=1/(a-1),c=-s/2,l=1+s/2,h=[c,c,l,c,l,l,c,c,l,l,c,l],u=new Float32Array(108),p=new Float32Array(72),d=new Float32Array(36),f=0;f<6;f++){var m=f%3*2/3-1,g=f>2?0:-1,v=[m,g,0,m+2/3,g,0,m+2/3,g+1,0,m,g,0,m+2/3,g+1,0,m,g+1,0];u.set(v,18*f),p.set(h,12*f);var y=[f,f,f,f,f,f];d.set(y,6*f)}var x=new Zi;x.setAttribute("position",new Pi(u,3)),x.setAttribute("uv",new Pi(p,2)),x.setAttribute("faceIndex",new Pi(d,1)),e.push(x),i>hp&&i--}return{_lodPlanes:e,_sizeLods:t,_sigmas:n}}(),Ep=Tp._lodPlanes,Ap=Tp._sizeLods,Lp=Tp._sigmas,Rp=null,Pp=null,Cp=null,Op=(1+Math.sqrt(5))/2,Dp=1/Op,Ip=[new rn(1,1,1),new rn(-1,1,1),new rn(1,1,-1),new rn(-1,1,-1),new rn(0,Op,Dp),new rn(0,Op,-Dp),new rn(Dp,0,Op),new rn(-Dp,0,Op),new rn(Op,Dp,0),new rn(-Op,Dp,0)];function Np(e){Pp=e,Fp(wp)}function Bp(e){var t={magFilter:ae,minFilter:ae,generateMipmaps:!1,type:e?e.type:ue,format:e?e.format:Le,encoding:e?e.encoding:Lt,depthBuffer:!1,stencilBuffer:!1},n=Up(t);return n.depthBuffer=!e,Rp=Up(t),n}function zp(e){Rp.dispose(),Pp.setRenderTarget(Cp),e.scissorTest=!1,e.setSize(e.width,e.height)}function Fp(e){var t=new Cn;t.add(new dr(Ep[0],e)),Pp.compile(t,_p)}function Up(e){var t=new Kt(3*pp,3*pp,e);return t.texture.mapping=ee,t.texture.name="PMREM.cubeUv",t.scissorTest=!0,t}function Gp(e,t,n,i,r){e.viewport.set(t,n,i,r),e.scissor.set(t,n,i,r)}function Hp(e){var t=Pp.autoClear;Pp.autoClear=!1;for(var n=1;nmp&&console.warn("sigmaRadians, "+r+", is too large and will clip, as it requested "+p+" samples when the maximum is set to "+mp);for(var d=[],f=0,m=0;mup-hp?i-up+hp:0),3*y,2*y),Pp.setRenderTarget(t),Pp.render(s,_p)}function jp(){var e=new al({uniforms:{envMap:{value:null},texelSize:{value:new qt(1,1)},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform sampler2D envMap;\nuniform vec2 texelSize;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tvec3 outputDirection = normalize(vOutputDirection);\n\tvec2 uv;\n\tuv.y = asin(clamp(outputDirection.y, -1.0, 1.0)) * RECIPROCAL_PI + 0.5;\n\tuv.x = atan(outputDirection.z, outputDirection.x) * RECIPROCAL_PI2 + 0.5;\n\tvec2 f = fract(uv / texelSize - 0.5);\n\tuv -= f * texelSize;\n\tvec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.x += texelSize.x;\n\tvec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.y += texelSize.y;\n\tvec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tuv.x -= texelSize.x;\n\tvec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n\tvec3 tm = mix(tl, tr, f.x);\n\tvec3 bm = mix(bl, br, f.x);\n\tgl_FragColor.rgb = mix(tm, bm, f.y);\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1});return e.type="EquirectangularToCubeUV",e}function Wp(){var e=new al({uniforms:{envMap:{value:null},inputEncoding:{value:gp[Tt]},outputEncoding:{value:gp[Tt]}},vertexShader:"\nprecision mediump float;\nprecision mediump int;\nattribute vec3 position;\nattribute vec2 uv;\nattribute float faceIndex;\nvarying vec3 vOutputDirection;\nvec3 getDirection(vec2 uv, float face) {\n\tuv = 2.0 * uv - 1.0;\n\tvec3 direction = vec3(uv, 1.0);\n\tif (face == 0.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 1.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.z *= -1.0;\n\t} else if (face == 3.0) {\n\t\tdirection = direction.zyx;\n\t\tdirection.x *= -1.0;\n\t} else if (face == 4.0) {\n\t\tdirection = direction.xzy;\n\t\tdirection.y *= -1.0;\n\t} else if (face == 5.0) {\n\t\tdirection.xz *= -1.0;\n\t}\n\treturn direction;\n}\nvoid main() {\n\tvOutputDirection = getDirection(uv, faceIndex);\n\tgl_Position = vec4( position, 1.0 );\n}\n\t",fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform samplerCube envMap;\n\n\nuniform int inputEncoding;\nuniform int outputEncoding;\n\n#include \n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t\n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tgl_FragColor.rgb = envMapTexelToLinear(textureCube(envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ))).rgb;\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t",blending:h,depthTest:!1,depthWrite:!1});return e.type="CubemapToCubeUV",e}Np.prototype={constructor:Np,fromScene:function(e,t,n,i){void 0===t&&(t=0),void 0===n&&(n=.1),void 0===i&&(i=100),Cp=Pp.getRenderTarget();var r=Bp();return function(e,t,n,i){var r=new Pr(90,1,t,n),a=[1,1,1,1,-1,1],o=[1,1,-1,-1,-1,1],s=Pp.outputEncoding,c=Pp.toneMapping,l=Pp.toneMappingExposure,h=Pp.getClearColor(),u=Pp.getClearAlpha();Pp.toneMapping=j,Pp.toneMappingExposure=1,Pp.outputEncoding=Tt,e.scale.z*=-1;var p=e.background;if(p&&p.isColor){p.convertSRGBToLinear();var d=Math.max(p.r,p.g,p.b),f=Math.min(Math.max(Math.ceil(Math.log2(d)),-128),127);p=p.multiplyScalar(Math.pow(2,-f));var m=(f+128)/255;Pp.setClearColor(p,m),e.background=null}for(var g=0;g<6;g++){var v=g%3;0==v?(r.up.set(0,a[g],0),r.lookAt(o[g],0,0)):1==v?(r.up.set(0,0,a[g]),r.lookAt(0,o[g],0)):(r.up.set(0,a[g],0),r.lookAt(0,0,o[g])),Gp(i,v*pp,g>2?pp:0,pp,pp),Pp.setRenderTarget(i),Pp.render(e,r)}Pp.toneMapping=c,Pp.toneMappingExposure=l,Pp.outputEncoding=s,Pp.setClearColor(h,u),e.scale.z*=-1}(e,n,i,r),t>0&&Vp(r,0,0,t),Hp(r),zp(r),r},fromEquirectangular:function(e){return e.magFilter=ae,e.minFilter=ae,e.generateMipmaps=!1,this.fromCubemap(e)},fromCubemap:function(e){Cp=Pp.getRenderTarget();var t=Bp(e);return function(e,t){var n=new Cn;e.isCubeTexture?null==Sp&&(Sp=Wp()):null==Mp&&(Mp=jp());var i=e.isCubeTexture?Sp:Mp;n.add(new dr(Ep[0],i));var r=i.uniforms;r.envMap.value=e,e.isCubeTexture||r.texelSize.value.set(1/e.image.width,1/e.image.height);r.inputEncoding.value=gp[e.encoding],r.outputEncoding.value=gp[e.encoding],Gp(t,0,0,3*pp,2*pp),Pp.setRenderTarget(t),Pp.render(n,_p)}(e,t),Hp(t),zp(t),t},compileCubemapShader:function(){null==Sp&&Fp(Sp=Wp())},compileEquirectangularShader:function(){null==Mp&&Fp(Mp=jp())},dispose:function(){wp.dispose(),null!=Sp&&Sp.dispose(),null!=Mp&&Mp.dispose();for(var e=0;e - +