From e4f072171f5db3c6bdabfeeabad0ccbf9bf7b59d 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 | 6 ++++ .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, 98 insertions(+), 60 deletions(-) create mode 100644 .gitattributes 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 new file mode 100644 index 00000000..20a1577d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# 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 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 7ab6e00594ce610d3366b321297cb23865755f34 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Thu, 5 Dec 2024 08:06:26 -0800 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 | 24 +- appveyor.yml | 2 +- basisu.manifest | 1 - basisu.vcxproj | 4 +- basisu.vcxproj.filters | 4 +- basisu_tool.cpp | 197 +++-- 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 | 3 +- encoder/3rdparty/tinyexr.h | 10 +- encoder/basisu_astc_hdr_enc.cpp | 141 ++- encoder/basisu_astc_hdr_enc.h | 43 +- 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 | 299 ++++--- encoder/basisu_comp.h | 115 ++- encoder/basisu_enc.cpp | 236 ++--- encoder/basisu_enc.h | 230 +++-- 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 | 173 ++-- encoder/basisu_gpu_texture.h | 19 +- encoder/basisu_kernels_imp.h | 18 +- encoder/basisu_kernels_sse.cpp | 1 - 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_ssim.cpp | 6 +- encoder/basisu_uastc_enc.cpp | 111 ++- encoder/basisu_uastc_enc.h | 34 +- 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 | 75 +- transcoder/basisu_astc_helpers.h | 274 +++--- transcoder/basisu_containers.h | 82 +- transcoder/basisu_containers_impl.h | 6 +- transcoder/basisu_file_headers.h | 38 +- transcoder/basisu_transcoder.cpp | 586 ++++++------- transcoder/basisu_transcoder.h | 69 +- transcoder/basisu_transcoder_internal.h | 47 +- transcoder/basisu_transcoder_uastc.h | 20 +- webgl/README.md | 2 +- webgl/encoder/CMakeLists.txt | 44 +- 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 | 130 +-- webgl/ktx2_encode_test/renderer.js | 1 - webgl/texture_test/index.html | 124 +-- webgl/texture_test/renderer.js | 7 +- webgl/transcoder/CMakeLists.txt | 36 +- webgl/transcoder/basis_wrappers.cpp | 34 +- webgl/video_test/index.html | 184 ++-- webgl/video_test/renderer.js | 9 +- zstd/zstd.c | 12 +- zstd/zstddeclib.c | 8 +- 105 files changed, 3026 insertions(+), 3069 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8345623d..5a16b181 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,18 +68,18 @@ 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() @@ -87,7 +87,7 @@ if (NOT MSVC) set(CMAKE_CXX_FLAGS -std=c++11) 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-misleading-indentation -Wno-maybe-uninitialized -Wno-unused-function -Wno-stringop-overflow -Wno-unknown-warning-option") set(GCC_CXX_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") set(GCC_CXX_COMPILE_FLAGS "${GCC_CXX_COMPILE_FLAGS} -m32") @@ -106,7 +106,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) @@ -116,7 +116,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 5f71373b..86680798 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 texture video content in a way that is compatible with any GPU or rendering/graphics API. @@ -19,7 +19,7 @@ Links - [Release Notes](https://github.com/BinomialLLC/basis_universal/wiki/Release-Notes) -- [Live Encoder/Transcoder WebGL Examples](https://subquantumtech.com/uastchdr2/) +- [Live Encoder/Transcoder WebGL Examples](https://subquantumtech.com/uastchdr2/) - [Javascript API/WASM/WebGL info](https://github.com/BinomialLLC/basis_universal/tree/master/webgl) @@ -133,13 +133,13 @@ Compressing and Unpacking .KTX2/.basis Files Note the .EXR reader we're using is [TinyEXR's](https://github.com/syoyo/tinyexr), which doesn't support all possible .EXR compression modes. Tools like [ImageMagick](https://imagemagick.org/) can be used to create .EXR files that TinyEXR can read. -Alternatively, LDR images (such as .PNG) can be compressed to UASTC HDR by specifying `-hdr`. By default, LDR images, when compressed to UASTC HDR, are first converted from sRGB to linear light before compression. This conversion step can be disabled by specifying `-hdr_ldr_no_srgb_to_linear`. +Alternatively, LDR images (such as .PNG) can be compressed to UASTC HDR by specifying `-hdr`. By default, LDR images, when compressed to UASTC HDR, are first converted from sRGB to linear light before compression. This conversion step can be disabled by specifying `-hdr_ldr_no_srgb_to_linear`. -Importantly, for best quality, you should **supply basisu with original uncompressed source images**. Any other type of lossy compression applied before basisu (including ETC1/BC1-5, BC7, JPEG, etc.) will cause multi-generational artifacts to appear in the final output textures. +Importantly, for best quality, you should **supply basisu with original uncompressed source images**. Any other type of lossy compression applied before basisu (including ETC1/BC1-5, BC7, JPEG, etc.) will cause multi-generational artifacts to appear in the final output textures. ### 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). @@ -147,7 +147,7 @@ Importantly, for best quality, you should **supply basisu with original uncompre - `-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.) @@ -174,7 +174,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): @@ -201,11 +201,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 -------------- @@ -216,10 +216,10 @@ The 'WebGL' directory contains four simple WebGL demos that use the transcoder a ![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 1a8989b6..37a6fef3 100644 --- a/basisu.vcxproj +++ b/basisu.vcxproj @@ -1,4 +1,4 @@ - + @@ -187,4 +187,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 b065ba9e..8b4c029a 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) #endif @@ -75,7 +75,7 @@ enum tool_mode static void print_usage() { printf("\nUsage: basisu filename [filename ...] \n"); - + puts("\n" "The default 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" @@ -286,7 +286,7 @@ static bool load_listing_file(const std::string &f, basisu::vector { if (read_filename[0] == ' ') read_filename.erase(0, 1); - else + else break; } @@ -295,7 +295,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; } @@ -341,7 +341,7 @@ class command_line_params m_parallel_compression(false) { m_comp_params.m_compression_level = basisu::maximum(0, BASISU_DEFAULT_COMPRESSION_LEVEL - 1); - + m_comp_params.m_uastc_hdr_options.set_quality_level(astc_hdr_codec_options::cDefaultLevel); m_test_file_dir = "../test_files"; @@ -511,15 +511,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_flags &= ~cPackUASTCLevelMask; m_comp_params.m_pack_uastc_flags |= s_level_flags[uastc_level]; m_comp_params.m_uastc_hdr_options.set_quality_level(uastc_level); - + arg_count++; } else if (strcasecmp(pArg, "-resample") == 0) @@ -738,7 +738,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) @@ -865,7 +865,7 @@ class command_line_params arg_index += arg_count; } - + if (m_comp_params.m_quality_level != -1) { m_comp_params.m_max_endpoint_clusters = 0; @@ -887,7 +887,7 @@ class command_line_params else m_comp_params.m_mip_srgb = false; } - + return true; } @@ -918,12 +918,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; @@ -932,7 +932,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; @@ -950,9 +950,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; @@ -968,13 +968,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('!'); @@ -986,15 +986,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); @@ -1005,8 +1005,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; @@ -1071,7 +1071,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"); @@ -1083,7 +1083,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()) { @@ -1093,7 +1093,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) @@ -1103,7 +1103,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) @@ -1115,7 +1115,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; @@ -1126,15 +1126,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()) { @@ -1150,7 +1150,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(); @@ -1199,7 +1199,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 @@ -1387,7 +1387,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) @@ -1396,8 +1396,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); } @@ -1406,11 +1406,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) @@ -1421,7 +1421,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; @@ -1456,15 +1456,15 @@ 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()); printf("Mipmap Levels: %u\n", dec.get_levels()); printf("Texture Array Size (layers): %u\n", dec.get_layers()); printf("Total Faces: %u (%s)\n", dec.get_faces(), (dec.get_faces() == 6) ? "CUBEMAP" : "2D"); printf("Is Texture Video: %u\n", dec.is_video()); - + const bool is_etc1s = (dec.get_format() == basist::basis_tex_format::cETC1S); - + const char* pFmt_str = "ETC1S"; if (dec.get_format() == basist::basis_tex_format::cUASTC4x4) pFmt_str = "UASTC"; @@ -1472,7 +1472,7 @@ static bool unpack_and_validate_ktx2_file( pFmt_str = "UASTC_HDR"; printf("Supercompression Format: %s\n", pFmt_str); - + printf("Supercompression Scheme: "); switch (dec.get_header().m_supercompression_scheme) { @@ -1485,9 +1485,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: %u\n", dec.get_dfd().size()); printf("DFD color model: %u\n", dec.get_dfd_color_model()); @@ -1504,7 +1504,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++) { @@ -1524,13 +1524,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)) )) { @@ -1703,7 +1703,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; @@ -1711,7 +1711,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_format())) @@ -1720,7 +1720,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)) { @@ -1741,7 +1741,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)); @@ -1942,7 +1942,7 @@ static bool unpack_and_validate_ktx2_file( } printf("Wrote PNG file \"%s\"\n", rgba_filename.c_str()); } - + } // is_hdr } // level_index @@ -1962,7 +1962,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, @@ -1985,7 +1985,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; } } @@ -2013,7 +2013,7 @@ static bool unpack_and_validate_basis_file( printf(" Slices size: %u\n", fileinfo.m_slices_size); const bool is_hdr = (fileinfo.m_tex_format == basist::basis_tex_format::cUASTC_HDR_4x4); - + printf(" Texture format: %s\n", is_hdr ? "UASTC_HDR" : ((fileinfo.m_tex_format == basist::basis_tex_format::cUASTC4x4) ? "UASTC" : "ETC1S")); printf(" Texture type: %s\n", basist::basis_get_texture_type_name(fileinfo.m_tex_type)); @@ -2108,7 +2108,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); @@ -2254,7 +2254,7 @@ static bool unpack_and_validate_basis_file( 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); @@ -2499,7 +2499,7 @@ static bool unpack_and_validate_basis_file( } printf("Wrote PNG file \"%s\"\n", rgba_filename.c_str()); } - + } // is_hdr } // level_index @@ -2539,7 +2539,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); @@ -2878,7 +2878,7 @@ static bool unpack_and_validate_basis_file( } // level_index } // image_index - + } // is_hdr } // if ((opts.m_format_only == -1) && (!validate_flag)) @@ -2919,7 +2919,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()) { @@ -2986,7 +2986,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)) { @@ -3023,10 +3023,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; @@ -3049,7 +3049,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; @@ -3095,7 +3095,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 "); @@ -3187,7 +3187,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)); @@ -3230,7 +3230,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"); @@ -3412,7 +3412,7 @@ static bool compare_mode(command_line_params &opts) } } // display_plot - + return true; } @@ -3451,7 +3451,7 @@ static bool split_image_mode(command_line_params& opts) } printf("Wrote file %s\n", buf); } - + return true; } @@ -3496,7 +3496,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); @@ -3538,7 +3538,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); for (uint32_t y = 0; y < height; y++) @@ -4167,7 +4167,7 @@ static bool bench_mode(command_line_params& opts) // HACK HACK const uint32_t max_rdo_jobs = 4; - + char rdo_fname[256]; FILE* pFile = nullptr; for (uint32_t try_index = 0; try_index < 100; try_index++) @@ -4179,7 +4179,7 @@ static bool bench_mode(command_line_params& opts) fclose(pFile); continue; } - + pFile = fopen(rdo_fname, "w"); if (!pFile) printf("Cannot open CSV file %s\n", rdo_fname); @@ -4198,7 +4198,7 @@ static bool bench_mode(command_line_params& opts) p.m_lambda = q; p.m_max_allowed_rms_increase_ratio = 10.0f; p.m_skip_block_rms_thresh = 8.0f; - + bool rdo_status = uastc_rdo((uint32_t)ublocks.size(), &ublocks[0], &orig_block_pixels[0], p, flags, &jpool, max_rdo_jobs); if (!rdo_status) { @@ -4262,7 +4262,7 @@ static bool bench_mode(command_line_params& opts) } if (pFile) fclose(pFile); - + { size_t comp_size = 0; void* pComp_data = tdefl_compress_mem_to_heap(&ublocks[0], ublocks.size() * 16, &comp_size, TDEFL_MAX_PROBES_MASK);// TDEFL_DEFAULT_MAX_PROBES); @@ -4288,7 +4288,7 @@ static bool bench_mode(command_line_params& opts) total_rdo_raw_size += ublocks.size() * 16; total_comp_blocks += ublocks.size(); } - + printf("Total blocks: %u\n", total_blocks); printf("Total BC1 hint 0's: %u %3.1f%%\n", total_bc1_hint0s, total_bc1_hint0s * 100.0f / total_blocks); printf("Total BC1 hint 1's: %u %3.1f%%\n", total_bc1_hint1s, total_bc1_hint1s * 100.0f / total_blocks); @@ -4333,7 +4333,7 @@ static bool bench_mode(command_line_params& opts) c[i] = (uint8_t)v; } - + } #endif @@ -4454,7 +4454,7 @@ static bool bench_mode(command_line_params& opts) em.print("RDOUASTC RGBA "); total_rdo_uastc_rgba_psnr += (float)basisu::minimum(99.0f, em.m_psnr); - // UASTC2 + // UASTC2 em.calc(img, uastc2_img, 0, 3); em.print("UASTC2 RGB "); total_uastc2_psnr += (float)basisu::minimum(99.0f, em.m_psnr); @@ -4547,7 +4547,7 @@ static bool bench_mode(command_line_params& opts) total_obc1_psnr += (float)basisu::minimum(99.0f, em.m_psnr); total_obc1_psnr_sq += (float)(basisu::minimum(99.0f, em.m_psnr) * basisu::minimum(99.0f, em.m_psnr)); #endif - + em.calc(img, opt_bc1_2_img, 0, 3); em.print("OBC1 2 RGB "); total_obc1_2_psnr += (float)basisu::minimum(99.0f, em.m_psnr); @@ -4681,7 +4681,7 @@ static bool bench_mode(command_line_params& opts) } // image_index printf("Total time: %f secs\n", otm.get_elapsed_secs()); - + printf("Total Non-RDO UASTC size: %llu, compressed size: %llu, %3.2f bits/texel\n", (unsigned long long)total_raw_size, (unsigned long long)total_comp_size, @@ -4793,10 +4793,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 }, @@ -4874,7 +4874,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"); @@ -5038,7 +5038,7 @@ static bool test_mode_hdr(command_line_params& opts) BASISU_ASSUME(astc_hdr_codec_options::cMaxLevel == 4); 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; @@ -5046,7 +5046,7 @@ static bool test_mode_hdr(command_line_params& opts) // 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; for (uint32_t i = 0; i < TOTAL_HDR_TEST_FILES; i++) @@ -5068,7 +5068,7 @@ static bool test_mode_hdr(command_line_params& opts) } 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 <= 4; uastc_hdr_level++) { image_stats stats; @@ -5092,7 +5092,7 @@ static bool test_mode_hdr(command_line_params& opts) 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_psnr, g_hdr_test_files[i].m_level_psnr_astc[uastc_hdr_level], delta1 = fabs(stats.m_basis_rgb_avg_psnr - g_hdr_test_files[i].m_level_psnr_astc[uastc_hdr_level]), stats.m_basis_rgb_avg_bc6h_psnr, g_hdr_test_files[i].m_level_psnr_bc6h[uastc_hdr_level], delta2 = fabs(stats.m_basis_rgb_avg_bc6h_psnr - g_hdr_test_files[i].m_level_psnr_bc6h[uastc_hdr_level])); @@ -5133,7 +5133,7 @@ static bool test_mode_hdr(command_line_params& opts) 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) @@ -5171,14 +5171,14 @@ static int main_internal(int argc, const char **argv) #ifdef FORCE_SAN_FAILURE force_san_failure(); #endif - + //interval_timer tm; //tm.start(); // 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)) @@ -5195,15 +5195,15 @@ static int main_internal(int argc, const char **argv) #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)) { @@ -5216,7 +5216,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; @@ -5300,7 +5300,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 @@ -5322,4 +5322,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 5abfe2fa..0e0924d1 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), @@ -838,8 +838,8 @@ void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" -#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" +#endif switch (numValues) { // \note Fall-throughs. @@ -853,7 +853,7 @@ void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& } #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif const deUint32 T = (T7 << 7) | (T56 << 5) | (T4 << 4) | (T23 << 2) | (T01 << 0); @@ -900,8 +900,8 @@ void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& #ifdef __GNUC__ #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" -#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough=" +#endif switch (numValues) { // \note Fall-throughs. @@ -913,7 +913,7 @@ void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& } #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif const deUint32 Q = (Q56 << 5) | (Q34 << 3) | (Q012 << 0); @@ -1058,7 +1058,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; @@ -1181,7 +1181,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; @@ -1209,7 +1209,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); @@ -1417,7 +1417,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); @@ -1462,7 +1462,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 @@ -1515,7 +1515,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); @@ -1529,7 +1529,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; } } @@ -1705,7 +1705,7 @@ DecompressResult setTexelColors (void* dst, ColorEndpointPair* colorEndpoints, T ((float*)dst)[texelNdx * 4 + channelNdx] = deFloat16To32(isFloat16InfOrNan(cf) ? 0x7bff : cf); } - + } // channelNdx } } // texelX @@ -1717,26 +1717,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) || @@ -1748,7 +1748,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); @@ -1762,28 +1762,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; @@ -1836,7 +1836,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])) @@ -1986,7 +1986,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) { @@ -2022,7 +2022,7 @@ bool decompress_hdr(float* pDstRGBA, const uint8_t* data, int blockWidth, int bl } convert_to_half_prec(blockWidth * blockHeight * 4, pDstRGBA); - + return true; } @@ -2031,7 +2031,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 11a44bec..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]) @@ -2081,4 +2081,3 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - diff --git a/encoder/3rdparty/tinyexr.h b/encoder/3rdparty/tinyexr.h index 405827ed..2b759ee3 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_enc.cpp b/encoder/basisu_astc_hdr_enc.cpp index d698a7ff..be9ce89f 100644 --- a/encoder/basisu_astc_hdr_enc.cpp +++ b/encoder/basisu_astc_hdr_enc.cpp @@ -86,7 +86,7 @@ void astc_hdr_codec_options::init() void astc_hdr_codec_options::set_quality_best() { m_mode11_direct_only = false; - + // highest achievable quality m_use_solid = true; @@ -165,7 +165,7 @@ void astc_hdr_codec_options::set_quality_fastest() void astc_hdr_codec_options::set_quality_level(int level) { level = clamp(level, cMinLevel, cMaxLevel); - + m_level = level; switch (level) @@ -602,7 +602,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; @@ -920,7 +920,7 @@ double compute_block_error(const half_float* pOrig_block, const half_float* pPac const float G_WEIGHT = coptions.m_g_err_scale; double total_error = 0; - + for (uint32_t p = 0; p < 16; p++) { double rd = q(pOrig_block[p * 3 + 0]) - q(pPacked_block[p * 3 + 0]); @@ -991,14 +991,14 @@ static bool pack_astc_mode11_submode(uint32_t submode, uint8_t* pEndpoints, cons // this is better const half_float l = qlog16_to_half_slow((uint32_t)std::round(low_q16[c])); val_q[0][c] = half_to_qlog7_12(l, a_bits); - + const half_float h = qlog16_to_half_slow((uint32_t)std::round(high_q16[c])); val_q[1][c] = half_to_qlog7_12(h, a_bits); #else val_q[0][c] = quant_qlog16((uint32_t)std::round(low_q16[c]), a_bits); val_q[1][c] = quant_qlog16((uint32_t)std::round(high_q16[c]), a_bits); #endif - + #if 1 if (val_q[0][c] == val_q[1][c]) { @@ -1330,7 +1330,7 @@ static void pack_astc_mode11_direct(uint8_t* pEndpoints, const vec3F& l_q16, con } } #endif - + if (i == 2) { assert(l_q <= (int)MAX_QLOG7 && h_q <= (int)MAX_QLOG7); @@ -1478,7 +1478,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1492,7 +1492,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1506,7 +1506,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1520,7 +1520,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1535,7 +1535,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1548,7 +1548,7 @@ static bool pack_astc_mode7_submode(uint32_t submode, uint8_t* pEndpoints, const 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; @@ -1642,8 +1642,8 @@ static bool try_mode11(uint32_t num_pixels, uint8_t* pEndpoints, uint8_t* pWeights, double& cur_block_error, uint32_t& submode_used, vec3F& low_color_q16, const vec3F& high_color_q16, half_float block_pixels_half[16][3], - uint32_t num_weight_levels, uint32_t ise_weight_range, const astc_hdr_codec_options& coptions, bool direct_only, uint32_t ise_endpoint_range, - bool constrain_ise_weight8_selectors, + uint32_t num_weight_levels, uint32_t ise_weight_range, const astc_hdr_codec_options& coptions, bool direct_only, uint32_t ise_endpoint_range, + bool constrain_ise_weight8_selectors, int32_t first_submode, int32_t last_submode) // -1, 7 { assert((ise_weight_range >= 1) && (ise_weight_range <= MAX_SUPPORTED_ISE_WEIGHT_INDEX)); @@ -1685,11 +1685,11 @@ static bool try_mode11(uint32_t num_pixels, if ((did_clamp) && (max_clamp_mag > MAX_CLAMP_MAG_ACCEPT_THRESH)) continue; } - + // This will distort the endpoints if the ISE endpoint range isn't 256 levels (20). // It could massively distort the endpoints, but still result in a valid encoding. quantize_ise_endpoints(ise_endpoint_range, orig_trial_endpoints, trial_endpoints, NUM_MODE11_ENDPOINTS); - + if (!get_astc_hdr_mode_11_block_colors(trial_endpoints, &decoded_half[0][0], decoded_float, num_weight_levels, ise_weight_range, ise_endpoint_range)) continue; @@ -1710,7 +1710,7 @@ static bool try_mode11(uint32_t num_pixels, // If it didn't clamp it was a lossless encode at this precision, so we can stop early as there's probably no use trying lower precision submodes. // (Although it may be, because a lower precision pack could try nearby voxel coords.) // However, at lower levels quantization may cause the decoded endpoints to be very distorted, so we need to evaluate up to direct. - if (ise_endpoint_range == astc_helpers::BISE_256_LEVELS) + if (ise_endpoint_range == astc_helpers::BISE_256_LEVELS) { if (!did_clamp) break; @@ -1727,7 +1727,7 @@ static bool try_mode7( uint8_t* pEndpoints, uint8_t* pWeights, double& cur_block_error, uint32_t& submode_used, vec3F& high_color_q16, const float s_q16, half_float block_pixels_half[16][3], - uint32_t num_weight_levels, uint32_t ise_weight_range, const astc_hdr_codec_options& coptions, + uint32_t num_weight_levels, uint32_t ise_weight_range, const astc_hdr_codec_options& coptions, uint32_t ise_endpoint_range) { assert((ise_weight_range >= 1) && (ise_weight_range <= MAX_SUPPORTED_ISE_WEIGHT_INDEX)); @@ -1804,7 +1804,7 @@ static double encode_astc_hdr_block_mode_11( half_float block_pixels_half[16][3]; vec4F block_pixels_q16[16]; - + // TODO: This is done redundantly. for (uint32_t i = 0; i < num_pixels; i++) { @@ -1821,7 +1821,7 @@ static double encode_astc_hdr_block_mode_11( } const uint32_t num_weight_levels = astc_helpers::get_ise_levels(ise_weight_range); - + // TODO: should match MAX_SUPPORTED_ISE_WEIGHT_INDEX const uint32_t MAX_WEIGHT_LEVELS = 32; (void)MAX_WEIGHT_LEVELS; @@ -1861,21 +1861,21 @@ static double encode_astc_hdr_block_mode_11( low_color_q16[i] = lerp(old_low_color_q16[i], old_high_color_q16[i], 1.0f / 64.0f); high_color_q16[i] = lerp(old_low_color_q16[i], old_high_color_q16[i], 63.0f / 64.0f); } - + uint8_t trial_blk_endpoints[NUM_MODE11_ENDPOINTS]; uint8_t trial_blk_weights[16]; uint32_t trial_best_submode = 0; - + clear_obj(trial_blk_endpoints); clear_obj(trial_blk_weights); - + double trial_blk_error = 1e+30f; 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, block_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight8_selectors, first_submode, last_submode); - + // If we couldn't find ANY usable solution due to endpoint quantization, just return. There's nothing we can do. if (!did_improve) return cur_block_error; @@ -1888,7 +1888,7 @@ static double encode_astc_hdr_block_mode_11( memcpy(blk_weights, trial_blk_weights, num_pixels); best_submode = trial_best_submode; } - + #define USE_LEAST_SQUARES (1) #if USE_LEAST_SQUARES // least squares on the most promising trial weight indices found @@ -1913,7 +1913,7 @@ static double encode_astc_hdr_block_mode_11( } // pass #endif - + if (uber_mode) { // Try varying the current best weight indices. This can be expanded/improved, but at potentially great cost. @@ -1960,7 +1960,7 @@ static double encode_astc_hdr_block_mode_11( { if (try_mode11(num_pixels, blk_endpoints, blk_weights, cur_block_error, best_submode, l_q16, h_q16, - block_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight8_selectors, + block_pixels_half, num_weight_levels, ise_weight_range, coptions, direct_only, ise_endpoint_range, constrain_ise_weight8_selectors, first_submode, last_submode)) { was_improved = true; @@ -2341,9 +2341,9 @@ static bool pack_solid(const vec4F* pBlock_linear_colors, basisu::vector& all_results, - const astc_hdr_codec_options& coptions, + const vec4F* pBlock_linear_colors, + basisu::vector& all_results, + const astc_hdr_codec_options& coptions, uint32_t first_weight_ise_range, uint32_t last_weight_ise_range, bool constrain_ise_weight8_selectors) { uint8_t trial_endpoints[NUM_MODE11_ENDPOINTS], trial_weights[16]; @@ -2351,11 +2351,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; @@ -2363,8 +2363,8 @@ static void pack_mode11( { assert(weight_ise_range < astc_helpers::BISE_16_LEVELS); } - - double trial_error = encode_astc_hdr_block_mode_11(16, pBlock_linear_colors, weight_ise_range, trial_submode11, 1e+30f, trial_endpoints, trial_weights, coptions, direct_only, + + double trial_error = encode_astc_hdr_block_mode_11(16, pBlock_linear_colors, weight_ise_range, trial_submode11, 1e+30f, 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_weight8_selectors, coptions.m_first_mode11_submode, coptions.m_last_mode11_submode); if (trial_error < 1e+30f) @@ -2376,12 +2376,12 @@ static void pack_mode11( results.m_best_submodes[0] = trial_submode11; results.m_constrained_weights = constrain_ise_weight8_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 = weight_ise_range; results.m_best_blk.m_endpoint_ise_range = 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); @@ -2396,7 +2396,7 @@ static void pack_mode11( 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); @@ -2414,7 +2414,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); @@ -2462,18 +2462,18 @@ static void pack_mode7_single_part(const vec4F* pBlock_linear_colors, basisu::ve 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 = weight_ise_range; results.m_best_blk.m_endpoint_ise_range = 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)) @@ -2623,13 +2623,13 @@ static void pack_mode7_2part(const vec4F* pBlock_linear_colors, basisu::vector& all_results) { @@ -2905,7 +2905,7 @@ bool astc_hdr_enc_block( } all_results.resize(0); - + vec4F block_linear_colors[16]; // Sanity check the input block. @@ -2935,15 +2935,15 @@ bool astc_hdr_enc_block( assert(0); return false; } - + block_linear_colors[i][j] = v; } - + block_linear_colors[i][3] = 1.0f; } assert(coptions.m_use_solid || coptions.m_use_mode11 || coptions.m_use_mode7_part2 || coptions.m_use_mode7_part1 || coptions.m_use_mode11_part2); - + bool is_solid = false; if (coptions.m_use_solid) is_solid = pack_solid(block_linear_colors, all_results, coptions); @@ -2961,7 +2961,7 @@ bool astc_hdr_enc_block( pack_mode11(block_linear_colors, all_results, coptions, astc_helpers::BISE_16_LEVELS, astc_helpers::BISE_16_LEVELS, 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) @@ -2972,13 +2972,13 @@ bool astc_hdr_enc_block( } } } - + if (coptions.m_use_mode7_part1) { // Mode 7 1-subset never requires endpoint quantization, so it cannot fail to find at least one usable solution. pack_mode7_single_part(block_linear_colors, all_results, coptions); } - + bool have_est = false; int best_parts[basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2]; @@ -2992,21 +2992,21 @@ bool astc_hdr_enc_block( { const size_t cur_num_results = all_results.size(); - pack_mode7_2part(block_linear_colors, all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, + pack_mode7_2part(block_linear_colors, 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(block_linear_colors, all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts, + pack_mode7_2part(block_linear_colors, 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. @@ -3092,7 +3092,7 @@ bool astc_hdr_refine_weights(const half_float *pSource_block, astc_hdr_pack_resu 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); @@ -3100,7 +3100,7 @@ bool astc_hdr_refine_weights(const half_float *pSource_block, astc_hdr_pack_resu 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); @@ -3116,11 +3116,11 @@ bool astc_hdr_refine_weights(const half_float *pSource_block, astc_hdr_pack_resu { const half_float orig_c = pSource_block[(x + y * 4) * 3 + c]; const double orig_c_q = q(orig_c); - + const half_float astc_c = unpacked_astc_blk_rgba[y][x][c]; const double astc_c_q = q(astc_c); 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); const double bc6h_e = square(bc6h_c_q - orig_c_q) * c_weights[c]; @@ -3307,4 +3307,3 @@ void astc_hdr_block_stats::print() } } // namespace basisu - diff --git a/encoder/basisu_astc_hdr_enc.h b/encoder/basisu_astc_hdr_enc.h index ee122ff7..6e4d0c29 100644 --- a/encoder/basisu_astc_hdr_enc.h +++ b/encoder/basisu_astc_hdr_enc.h @@ -16,7 +16,7 @@ namespace basisu const uint32_t MODE11_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE11_PART2_LAST_ISE_RANGE = astc_helpers::BISE_4_LEVELS; 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; - + struct astc_hdr_codec_options { float m_bc6h_err_weight; @@ -60,7 +60,7 @@ namespace basisu astc_hdr_codec_options(); void init(); - + // TODO: set_quality_level() is preferred to configure the codec for transcoding purposes. static const int cMinLevel = 0; static const int cMaxLevel = 4; @@ -76,21 +76,21 @@ namespace basisu struct astc_hdr_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; @@ -111,26 +111,26 @@ 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; } }; - + void interpolate_qlog12_colors( const int e[2][3], basist::half_float* pDecoded_half, vec3F* pDecoded_float, uint32_t n, uint32_t ise_weight_range); - + bool get_astc_hdr_mode_11_block_colors( const uint8_t* pEndpoints, basist::half_float* pDecoded_half, vec3F* pDecoded_float, uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range); - + bool get_astc_hdr_mode_7_block_colors( const uint8_t* pEndpoints, basist::half_float* pDecoded_half, @@ -149,20 +149,20 @@ namespace basisu double compute_block_error(const basist::half_float* pOrig_block, const basist::half_float* pPacked_block, const astc_hdr_codec_options& coptions); // 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_enc_block( const float* pRGBPixels, @@ -170,7 +170,7 @@ namespace basisu basisu::vector &all_results); bool astc_hdr_pack_results_to_block(basist::astc_blk& dst_blk, const astc_hdr_pack_results& results); - + bool astc_hdr_refine_weights(const basist::half_float* pSource_block, astc_hdr_pack_results& cur_results, const astc_hdr_codec_options& coptions, float bc6h_weight, bool* pImproved_flag); struct astc_hdr_block_stats @@ -190,11 +190,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_block_stats() { clear(); } void clear() @@ -216,9 +216,8 @@ namespace basisu } void update(const astc_hdr_pack_results& log_blk); - + void print(); }; - -} // namespace basisu +} // 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 cfd5c2ba..f46dbbfe 100644 --- a/encoder/basisu_comp.cpp +++ b/encoder/basisu_comp.cpp @@ -60,7 +60,7 @@ namespace basisu m_opencl_failed(false) { debug_printf("basis_compressor::basis_compressor\n"); - + assert(g_library_initialized); } @@ -192,7 +192,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"); @@ -204,14 +204,14 @@ 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)) m_params.m_validate_output_data = true; check_for_hdr_inputs(); - + if (m_params.m_debug) { debug_printf("basis_compressor::init:\n"); @@ -220,7 +220,7 @@ namespace basisu #define PRINT_INT_VALUE(v) debug_printf("%s: %i %u\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); #define PRINT_UINT_VALUE(v) debug_printf("%s: %u %u\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); #define PRINT_FLOAT_VALUE(v) debug_printf("%s: %f %u\n", BASISU_STRINGIZE2(v), static_cast(m_params.v), m_params.v.was_changed()); - + debug_printf("Source LDR images: %u, HDR images: %u, filenames: %u, alpha filenames: %i, LDR mipmap images: %u, HDR mipmap images: %u\n", m_params.m_source_images.size(), m_params.m_source_images_hdr.size(), m_params.m_source_filenames.size(), m_params.m_source_alpha_filenames.size(), @@ -266,10 +266,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); @@ -289,7 +289,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_flags: 0x%X\n", m_params.m_pack_uastc_flags); - + PRINT_BOOL_VALUE(m_rdo_uastc); PRINT_FLOAT_VALUE(m_rdo_uastc_quality_scalar); PRINT_INT_VALUE(m_rdo_uastc_dict_size); @@ -303,7 +303,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) { @@ -326,7 +326,7 @@ namespace basisu PRINT_BOOL_VALUE(m_hdr_ldr_srgb_to_linear_conversion); debug_printf("Allow UASTC HDR uber mode: %u\n", m_params.m_uastc_hdr_options.m_allow_uber_mode); PRINT_BOOL_VALUE(m_hdr_favor_astc); - + #undef PRINT_BOOL_VALUE #undef PRINT_INT_VALUE #undef PRINT_UINT_VALUE @@ -335,7 +335,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(); @@ -345,7 +345,7 @@ namespace basisu return true; } - + basis_compressor::error_code basis_compressor::process() { debug_printf("basis_compressor::process\n"); @@ -396,7 +396,7 @@ namespace basisu // ETC1S if (m_params.m_status_output) printf("Mode: ETC1S Quality %i, Level %i\n", m_params.m_quality_level, (int)m_params.m_compression_level); - + if (!process_frontend()) return cECFailedFrontEnd; @@ -444,7 +444,7 @@ namespace basisu m_params.m_uastc_hdr_options.m_r_err_scale = 1.0f; m_params.m_uastc_hdr_options.m_g_err_scale = 1.0f; } - + const float DEFAULT_BC6H_ERROR_WEIGHT = .85f; const float LOWEST_BC6H_ERROR_WEIGHT = .1f; m_params.m_uastc_hdr_options.m_bc6h_err_weight = m_params.m_hdr_favor_astc ? LOWEST_BC6H_ERROR_WEIGHT : DEFAULT_BC6H_ERROR_WEIGHT; @@ -453,7 +453,7 @@ namespace basisu any_failures = false; astc_hdr_block_stats enc_stats; - + struct uastc_blk_desc { uint32_t m_solid_flag; @@ -477,7 +477,7 @@ namespace basisu return false; } - + bool operator== (const uastc_blk_desc& desc) const { if (this == &desc) @@ -504,7 +504,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]; @@ -518,16 +518,16 @@ namespace basisu std::atomic total_blocks_processed; total_blocks_processed = 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); - + // FIXME: This sucks, but we're having a stack size related problem with std::function with emscripten. #ifndef __EMSCRIPTEN__ - 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] { #endif @@ -546,7 +546,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++) @@ -560,7 +560,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_enc_block(&rgb_pixels[0], m_params.m_uastc_hdr_options, all_results); if (!status) { @@ -570,10 +570,10 @@ namespace basisu double best_err = 1e+30f; int best_result_index = -1; - + const double bc6h_err_weight = m_params.m_uastc_hdr_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]; @@ -591,9 +591,9 @@ namespace basisu } const astc_hdr_pack_results& best_results = all_results[best_result_index]; - + astc_hdr_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_options.m_level > 0) @@ -626,12 +626,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); @@ -651,7 +651,7 @@ namespace basisu #ifndef __EMSCRIPTEN__ }); #endif - + } // block_index_iter #ifndef __EMSCRIPTEN__ @@ -667,7 +667,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_hdr: Total time: %3.3f secs\n", tm.get_elapsed_secs()); if (m_params.m_debug) @@ -714,11 +714,11 @@ namespace basisu debug_printf(" }\n"); } #endif - + c++; } printf("\n"); - + enc_stats.print(); } @@ -738,7 +738,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]; @@ -749,7 +749,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 = 0; @@ -765,7 +765,7 @@ namespace basisu { #endif BASISU_NOTE_UNUSED(num_blocks_y); - + uint32_t uastc_flags = m_params.m_pack_uastc_flags; if ((m_params.m_rdo_uastc) && (m_params.m_rdo_uastc_favor_simpler_modes_in_rdo_mode)) uastc_flags |= cPackUASTCFavorSimplerModes; @@ -784,7 +784,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) { @@ -812,7 +812,7 @@ namespace basisu rdo_params.m_lz_dict_size = m_params.m_rdo_uastc_dict_size; rdo_params.m_smooth_block_max_error_scale = m_params.m_rdo_uastc_max_smooth_block_error_scale; rdo_params.m_max_smooth_block_std_dev = m_params.m_rdo_uastc_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_flags, m_params.m_rdo_uastc_multithreading ? m_params.m_pJob_pool : nullptr, (m_params.m_rdo_uastc_multithreading && m_params.m_pJob_pool) ? basisu::minimum(4, (uint32_t)m_params.m_pJob_pool->get_total_threads()) : 0); @@ -824,11 +824,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; } @@ -864,8 +864,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) @@ -920,12 +920,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) @@ -933,7 +933,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(); } @@ -1055,7 +1055,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++) @@ -1124,7 +1124,7 @@ namespace basisu ldr_mips.erase(0U); m_params.m_source_mipmap_images.back().swap(ldr_mips); - + any_mipmaps = true; } } @@ -1144,7 +1144,7 @@ namespace basisu hdr_mips.erase(0U); m_params.m_source_mipmap_images_hdr.back().swap(hdr_mips); - + any_mipmaps = true; } @@ -1168,7 +1168,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; } @@ -1176,7 +1176,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) @@ -1200,7 +1200,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. @@ -1323,7 +1323,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]]); } @@ -1459,7 +1459,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()) @@ -1472,7 +1472,7 @@ namespace basisu } } } - else + else { if (m_params.m_source_mipmap_images.size()) { @@ -1513,23 +1513,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. @@ -1611,10 +1611,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; @@ -1633,7 +1633,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); @@ -1655,7 +1655,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]; @@ -1706,10 +1706,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]; @@ -1772,7 +1772,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++) { @@ -1782,7 +1782,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) @@ -1805,8 +1805,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); } @@ -1861,20 +1861,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); } @@ -1897,7 +1897,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; @@ -1983,7 +1983,7 @@ namespace basisu bool basis_compressor::process_frontend() { debug_printf("basis_compressor::process_frontend\n"); - + #if 0 // TODO basis_etc1_pack_params pack_params; @@ -2034,21 +2034,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_quality_level != -1) { const float quality = saturate(m_params.m_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; @@ -2059,7 +2059,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); @@ -2070,12 +2070,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 @@ -2099,7 +2099,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; } @@ -2126,12 +2126,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]; @@ -2147,7 +2147,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; @@ -2156,7 +2156,7 @@ namespace basisu error_printf("basisu_frontend::init() failed!\n"); return false; } - + m_frontend.compress(); if (m_frontend.get_opencl_failed()) @@ -2167,18 +2167,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); } } @@ -2242,13 +2242,13 @@ namespace basisu backend_params.m_debug_images = m_params.m_debug_images; backend_params.m_etc1s = true; backend_params.m_compression_level = m_params.m_compression_level; - + if (!m_params.m_no_endpoint_rdo) backend_params.m_endpoint_rdo_quality_thresh = m_params.m_endpoint_rdo_thresh; if (!m_params.m_no_selector_rdo) backend_params.m_selector_rdo_quality_thresh = m_params.m_selector_rdo_thresh; - + backend_params.m_used_global_codebooks = m_frontend.get_params().m_pGlobal_codebooks != nullptr; backend_params.m_validate = m_params.m_validate_output_data; @@ -2277,7 +2277,7 @@ namespace basisu error_printf("basis_compressor::create_basis_file_and_transcode: basisu_backend:init() failed!\n"); return false; } - + const uint8_vec &comp_data = m_basis_file.get_compressed_data(); m_output_basis_file = comp_data; @@ -2357,11 +2357,11 @@ namespace basisu gpu_image decoded_texture; decoded_texture.init( - tex_format, + tex_format, m_slice_descs[i].m_width, m_slice_descs[i].m_height); tm.start(); - + uint32_t bytes_per_block = m_params.m_uastc ? 16 : 8; if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i, @@ -2407,7 +2407,7 @@ namespace basisu error_printf("Transcoding failed to ASTC HDR on slice %u!\n", i); return false; } - + m_decoded_output_textures_astc_hdr[i] = decoded_texture; } } @@ -2420,14 +2420,14 @@ namespace basisu { gpu_image decoded_texture; decoded_texture.init(texture_format::cBC7, m_slice_descs[i].m_width, m_slice_descs[i].m_height); - + if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i, reinterpret_cast(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cBC7, 16)) { error_printf("Transcoding failed to BC7 on slice %u!\n", i); return false; } - + m_decoded_output_textures_bc7[i] = decoded_texture; } } @@ -2443,7 +2443,7 @@ namespace basisu bool status = m_decoded_output_textures[i].unpack_hdr(m_decoded_output_textures_bc6h_hdr_unpacked[i]); assert(status); BASISU_NOTE_UNUSED(status); - + // ASTC HDR status = m_decoded_output_textures_astc_hdr[i].unpack_hdr(m_decoded_output_textures_astc_hdr_unpacked[i]); assert(status); @@ -2462,7 +2462,7 @@ namespace basisu } } - debug_printf("Transcoded to %s in %3.3fms, %f texels/sec\n", + debug_printf("Transcoded to %s in %3.3fms, %f texels/sec\n", m_params.m_hdr ? "BC6H" : (m_params.m_uastc ? "ASTC" : "ETC1"), total_time_etc1s_or_astc * 1000.0f, total_orig_pixels / total_time_etc1s_or_astc); @@ -2480,7 +2480,7 @@ namespace basisu } } // if (m_params.m_validate_output_data) - + return true; } @@ -2519,7 +2519,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) { @@ -2587,7 +2587,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_num_blocks_x * m_slice_descs[i].m_num_blocks_y) * 16; - + m_basis_bits_per_texel = comp_size * 8.0f / total_texels; debug_printf("Output file size: %u, LZ compressed file size: %u, %3.2f bits/texel\n", @@ -2597,7 +2597,7 @@ namespace basisu } m_stats.resize(m_slice_descs.size()); - + if (m_params.m_validate_output_data) { if (m_params.m_hdr) @@ -2668,7 +2668,7 @@ namespace basisu printf("\n"); } } - + if (m_params.m_debug_images) { std::string out_basename; @@ -2684,7 +2684,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()); @@ -2694,7 +2694,7 @@ 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"); write_astc_file(filename1.c_str(), astc_tex.get_ptr(), 4, 4, slice_desc.m_orig_width, slice_desc.m_orig_height); printf("Wrote .ASTC file %s\n", filename1.c_str()); @@ -2708,7 +2708,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()); @@ -2743,7 +2743,7 @@ namespace basisu printf("Slice: %u\n", slice_index); image_stats& s = m_stats[slice_index]; - + image_metrics em; // ---- .basis stats @@ -2919,10 +2919,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() { @@ -2966,12 +2966,12 @@ namespace basisu 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 }; - + static uint8_t g_ktx2_uastc_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 }; static uint8_t g_ktx2_uastc_alpha_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,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF }; // HDR TODO - what is the best Khronos DFD to use for UASTC HDR? - static uint8_t g_ktx2_uastc_hdr_nonalpha_dfd[44] = + static uint8_t g_ktx2_uastc_hdr_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0, // 0 totalSize 0x0,0x0,0x0,0x0, // 1 descriptorType/vendorId @@ -2985,7 +2985,7 @@ namespace basisu 0x0,0x0,0x0,0x0, // 9 sampleLower (0.0) 0x00, 0x00, 0x80, 0x3F // 10 sampleHigher (1.0) }; - + void basis_compressor::get_dfd(uint8_vec &dfd, const basist::ktx2_header &header) { const uint8_t* pDFD; @@ -3022,14 +3022,14 @@ namespace basisu dfd_len = sizeof(g_ktx2_etc1s_nonalpha_dfd); } } - + assert(dfd_len >= 44); dfd.resize(dfd_len); memcpy(dfd.data(), pDFD, dfd_len); uint32_t dfd_bits = basisu::read_le_dword(dfd.data() + 3 * sizeof(uint32_t)); - + dfd_bits &= ~(0xFF << 16); if (m_params.m_hdr) @@ -3062,7 +3062,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); @@ -3086,7 +3086,7 @@ namespace basisu // Determine the width/height, number of array layers, mipmap levels, and the number of faces (1 for 2D, 6 for cubemap). // This does not support 1D or 3D. uint32_t base_width = 0, base_height = 0, total_layers = 0, total_levels = 0, total_faces = 1; - + for (uint32_t i = 0; i < m_slice_descs.size(); i++) { if ((m_slice_descs[i].m_mip_index == 0) && (!base_width)) @@ -3104,7 +3104,7 @@ namespace basisu if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray) { assert((total_layers % 6) == 0); - + total_layers /= 6; assert(total_layers >= 1); @@ -3118,7 +3118,7 @@ namespace basisu header.m_pixel_width = base_width; header.m_pixel_height = base_height; header.m_face_count = total_faces; - + if (m_params.m_hdr) header.m_vk_format = basist::KTX2_FORMAT_UASTC_4x4_SFLOAT_BLOCK; else @@ -3195,7 +3195,7 @@ namespace basisu // No supercompression compressed_level_data_bytes = level_data_bytes; } - + uint8_vec etc1s_global_data; // Create ETC1S global supercompressed data @@ -3249,14 +3249,14 @@ namespace basisu append_vector(etc1s_global_data, backend_output.m_endpoint_palette); append_vector(etc1s_global_data, backend_output.m_selector_palette); append_vector(etc1s_global_data, backend_output.m_slice_image_tables); - + header.m_supercompression_scheme = basist::KTX2_SS_BASISLZ; } // Key values basist::ktx2_transcoder::key_value_vec key_values(m_params.m_ktx2_key_values); key_values.enlarge(1); - + const char* pKTXwriter = "KTXwriter"; key_values.back().m_key.resize(strlen(pKTXwriter) + 1); memcpy(key_values.back().m_key.data(), pKTXwriter, strlen(pKTXwriter) + 1); @@ -3317,7 +3317,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 + key_value_data.size(); uint32_t bytes_needed_to_pad = (16 - (kvd_end_file_offset & 15)) & 15; @@ -3336,13 +3336,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); @@ -3350,13 +3350,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()); @@ -3365,7 +3365,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 = dfd.size(); @@ -3425,7 +3425,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)); @@ -3459,7 +3459,7 @@ namespace basisu std::atomic result; result = true; - + std::atomic opencl_failed; opencl_failed = false; @@ -3474,19 +3474,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 = true; @@ -3515,7 +3515,7 @@ namespace basisu else { results.m_error_code = basis_compressor::cECFailedInitializing; - + result = false; } @@ -3541,7 +3541,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) { @@ -3578,7 +3578,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) { @@ -3610,7 +3610,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; @@ -3641,9 +3641,9 @@ namespace basisu comp_params.m_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. @@ -3779,7 +3779,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; @@ -3820,7 +3820,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); @@ -3862,11 +3862,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 1cc75fc8..e2e8c080 100644 --- a/encoder/basisu_comp.h +++ b/encoder/basisu_comp.h @@ -42,10 +42,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; @@ -74,7 +74,7 @@ namespace basisu m_filename.clear(); m_width = 0; m_height = 0; - + m_basis_rgb_avg_psnr = 0.0f; m_basis_rgba_avg_psnr = 0.0f; m_basis_a_avg_psnr = 0.0f; @@ -90,7 +90,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; @@ -121,7 +121,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; @@ -278,7 +278,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"; @@ -326,10 +326,10 @@ namespace basisu m_hdr_ldr_srgb_to_linear_conversion.clear(); m_hdr_favor_astc.clear(); - + m_pJob_pool = nullptr; } - + // True to generate UASTC .basis/.KTX2 file data, otherwise ETC1S. bool_param m_uastc; @@ -338,22 +338,22 @@ namespace basisu 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; @@ -364,19 +364,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; @@ -392,20 +392,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]; @@ -414,25 +414,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; - - // Codebook size (quality) control. + + // Codebook size (quality) control. // If m_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_max_endpoint_clusters; uint32_t m_max_selector_clusters; int m_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; @@ -469,13 +469,13 @@ namespace basisu bool_param m_validate_output_data; - // If true, LDR images (such as PNG) will be converted to normalized [0,1] linear light (via a sRGB->Linear conversion) 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) and then processed as HDR. // Otherwise, LDR images will be processed as HDR as-is. bool_param m_hdr_ldr_srgb_to_linear_conversion; // 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; }; @@ -490,7 +490,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, @@ -511,7 +511,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; } @@ -519,16 +519,16 @@ 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; - + basisu::vector m_slice_images; basisu::vector m_slice_images_hdr; @@ -536,11 +536,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; pixel_block_vec m_source_blocks; @@ -557,7 +557,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; @@ -568,7 +568,7 @@ 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; @@ -597,8 +597,8 @@ namespace basisu void get_dfd(uint8_vec& dfd, const basist::ktx2_header& hdr); bool create_ktx2_file(); }; - - // 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. // @@ -607,16 +607,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 { @@ -630,24 +630,24 @@ 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 - + cFlagUASTC = 1 << 17, // use UASTC compression vs. ETC1S cFlagUASTCRDO = 1 << 18, // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar) - + cFlagPrintStats = 1 << 19, // print image stats to stdout cFlagPrintStatus = 1 << 20, // print status to stdout - + cFlagHDR = 1 << 21, // Force encoder into HDR mode, even if source image is LDR. cFlagHDRLDRImageSRGBToLinearConversion = 1 << 22, // In HDR mode, convert LDR source images to linear before encoding. - + cFlagDebugImages = 1 << 23 // enable status output }; - // 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. @@ -661,7 +661,7 @@ namespace basisu // Important: The returned block MUST be manually freed using basis_free_data(). void* basis_compress( const basisu::vector& source_images_hdr, - uint32_t flags_and_quality, + uint32_t flags_and_quality, size_t* pSize, image_stats* pStats = nullptr); @@ -694,7 +694,7 @@ namespace basisu double m_basis_bits_per_texel; bool m_any_source_image_has_alpha; - parallel_results() + parallel_results() { clear(); } @@ -710,7 +710,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. @@ -718,6 +718,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 0636d71d..ccacf288 100644 --- a/encoder/basisu_enc.cpp +++ b/encoder/basisu_enc.cpp @@ -76,7 +76,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 (!) @@ -178,7 +178,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) { @@ -220,7 +220,7 @@ namespace basisu { char buf[8192]; -#ifdef _WIN32 +#ifdef _WIN32 vsprintf_s(buf, sizeof(buf), pFmt, args); #else vsnprintf(buf, sizeof(buf), pFmt, args); @@ -273,7 +273,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) @@ -307,7 +307,7 @@ namespace basisu timer_ticks delta = stop_time - m_start_time; return delta * g_timer_freq; } - + void interval_timer::init() { if (!g_timer_freq) @@ -351,21 +351,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; } @@ -381,7 +381,7 @@ namespace basisu return false; } } - + img.resize(w, h); const uint8_t *pSrc = pImage_data; @@ -424,7 +424,7 @@ namespace basisu { interval_timer tm; tm.start(); - + if (!buf_size) return false; @@ -442,7 +442,7 @@ namespace basisu return true; } - + bool load_png(const char* pFilename, image& img) { uint8_vec buffer; @@ -461,9 +461,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; @@ -558,7 +558,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); } @@ -617,7 +617,7 @@ namespace basisu return true; } - + bool load_image_hdr(const char* pFilename, imagef& img, bool ldr_srgb_to_linear) { std::string ext(string_get_extension(std::string(pFilename))); @@ -634,7 +634,7 @@ namespace basisu return false; return true; } - + if (strcasecmp(pExt, "exr") == 0) { int n_chans = 0; @@ -654,12 +654,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; @@ -677,7 +677,7 @@ namespace basisu else { bool has_alpha = false; - + if ((image_save_flags & cImageSaveIgnoreAlpha) == 0) has_alpha = img.has_alpha(); @@ -694,7 +694,7 @@ namespace basisu pDst[0] = pSrc->r; pDst[1] = pSrc->g; pDst[2] = pSrc->b; - + pSrc++; pDst += 3; } @@ -718,10 +718,10 @@ namespace basisu } free(pPNG_data); - + return status; } - + bool read_file_to_vec(const char* pFilename, uint8_vec& data) { FILE* pFile = nullptr; @@ -732,7 +732,7 @@ namespace basisu #endif if (!pFile) return false; - + fseek(pFile, 0, SEEK_END); #ifdef _WIN32 int64_t filesize = _ftelli64(pFile); @@ -803,7 +803,7 @@ namespace basisu return false; } fseek(pFile, 0, SEEK_SET); - + if (fread(pData, 1, (size_t)len, pFile) != (size_t)len) { fclose(pFile); @@ -836,19 +836,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"); @@ -857,10 +857,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"); @@ -891,7 +891,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); @@ -951,7 +951,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++) @@ -984,7 +984,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) @@ -1077,7 +1077,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++) @@ -1110,9 +1110,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) { @@ -1204,7 +1204,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); @@ -1395,7 +1395,7 @@ namespace basisu uint32_t total_used = tab.get_total_used_codes(); put_bits(total_used, cHuffmanMaxSymsLog2); - + if (!total_used) return 0; @@ -1459,7 +1459,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) @@ -1486,7 +1486,7 @@ namespace basisu huffman_encoding_table etab; etab.init(h, 16); - + { bitwise_coder c; c.init(1024); @@ -1621,9 +1621,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); @@ -1726,7 +1726,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)); @@ -1740,13 +1740,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++) @@ -1761,7 +1761,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); @@ -1796,10 +1796,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); @@ -1825,7 +1825,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; } @@ -1843,7 +1843,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++) @@ -1854,7 +1854,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; @@ -1907,7 +1907,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; @@ -1944,7 +1944,7 @@ namespace basisu } // x } // y - + double total_values = (double)width * (double)height; if (avg_comp_error) total_values *= (double)clamp(total_chans, 1, 4); @@ -2036,7 +2036,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); @@ -2049,23 +2049,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; @@ -2079,7 +2079,7 @@ namespace basisu default: break; } - + h ^= h << 3; h += h >> 5; h ^= h << 4; @@ -2090,7 +2090,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(false) { @@ -2110,17 +2110,17 @@ 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 = true; - + m_has_work.notify_all(); // Wait for all workers to die. 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); @@ -2140,7 +2140,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(); @@ -2176,7 +2176,7 @@ namespace basisu { BASISU_NOTE_UNUSED(index); //debug_printf("job_pool::job_thread: starting %u\n", index); - + while (true) { std::unique_lock lock(m_mutex); @@ -2202,9 +2202,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) @@ -2263,7 +2263,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)) @@ -2422,13 +2422,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; @@ -2450,7 +2450,7 @@ namespace basisu int pixels_remaining = width; uint8_t *pDst = &input_line_buf[0]; - do + do { if (!run_remaining) { @@ -2635,7 +2635,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); } @@ -2782,13 +2782,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); @@ -2826,7 +2826,7 @@ namespace basisu if ((dim < 1) || (dim > MAX_SUPPORTED_DIM)) return false; } - + // temp image: width=minor, height=major img.resize(minor_dim, major_dim); @@ -2854,7 +2854,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); @@ -2976,7 +2976,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); @@ -2993,10 +2993,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; @@ -3055,7 +3055,7 @@ namespace basisu return buf; } - + static uint8_vec& append_string(uint8_vec& buf, const std::string& str) { if (!str.size()) @@ -3072,7 +3072,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; @@ -3085,14 +3085,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); @@ -3125,7 +3125,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; @@ -3138,7 +3138,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; } } @@ -3148,12 +3148,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]; @@ -3178,7 +3178,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)); @@ -3190,7 +3190,7 @@ namespace basisu for (uint32_t c = 0; c < 4; c++) { int raw_ofs = -1; - + uint32_t x = 0; while (x < width) { @@ -3205,7 +3205,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) @@ -3229,7 +3229,7 @@ namespace basisu raw_ofs = -1; file_data.push_back(cur_byte); - + x++; } } // x @@ -3248,7 +3248,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; @@ -3256,7 +3256,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) { @@ -3275,7 +3275,7 @@ namespace basisu } img.resize(width, height); - + if (n_chans == 1) { const float* pSrc = out_rgba; @@ -3329,16 +3329,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++) @@ -3367,7 +3367,7 @@ namespace basisu assert(0); return false; } - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) @@ -3391,7 +3391,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. @@ -3402,37 +3402,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); @@ -3446,7 +3446,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); @@ -3471,7 +3471,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; @@ -3491,15 +3491,15 @@ 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) { uint32_t width = hdr_img.get_width(), height = hdr_img.get_height(); ldr_img.resize(width, height); - + for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) @@ -3527,7 +3527,7 @@ namespace basisu c[3] = c[3] * 255.0f; color_rgba& o = ldr_img(x, y); - + o[0] = (uint8_t)std::round(c[0]); o[1] = (uint8_t)std::round(c[1]); o[2] = (uint8_t)std::round(c[2]); @@ -3692,5 +3692,5 @@ namespace basisu return true; } - + } // namespace basisu diff --git a/encoder/basisu_enc.h b/encoder/basisu_enc.h index 780605e7..2b7d5e01 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, ...); - + // Helpers inline uint8_t clamp255(int32_t i) @@ -83,18 +83,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); } @@ -143,7 +143,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; } @@ -168,10 +168,10 @@ namespace basisu } bool string_begins_with(const std::string& str, const char* pPhrase); - + // 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); @@ -182,7 +182,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); @@ -401,7 +401,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; } @@ -410,14 +410,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); } @@ -468,7 +468,7 @@ namespace basisu typedef vec<1, float> vec1F; typedef vec<16, float> vec16F; - + template class matrix { @@ -729,7 +729,7 @@ namespace basisu } #undef BASISU_GET_KEY - + // Very simple job pool with no dependencies. class job_pool { @@ -739,24 +739,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; void job_thread(uint32_t index); @@ -799,7 +799,7 @@ namespace basisu return *this; } }; - + class color_rgba { public: @@ -923,7 +923,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; @@ -959,7 +959,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 basist::color32 get_color32() const @@ -996,7 +996,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) { @@ -1017,7 +1017,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); @@ -1034,7 +1034,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); @@ -1142,11 +1142,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); @@ -1196,7 +1196,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, @@ -1228,7 +1228,7 @@ namespace basisu if ((pDir->size()) && (pDir->back() != '/')) *pDir += "/"; } - + if (pFilename) { *pFilename = pBaseName; @@ -1255,7 +1255,7 @@ namespace basisu return (c == '/'); #endif } - + inline bool is_drive_separator(char c) { #ifdef _WIN32 @@ -1283,7 +1283,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); @@ -1485,7 +1485,7 @@ namespace basisu codebook.resize(0); codebook.reserve(max_clusters); - + uint32_t node_index = 0; while (true) @@ -1496,7 +1496,7 @@ namespace basisu { codebook.resize(codebook.size() + 1); codebook.back() = cur.m_training_vecs; - + if (node_stack.empty()) break; @@ -1504,7 +1504,7 @@ namespace basisu node_stack.pop_back(); continue; } - + node_stack.push_back(cur.m_right_index); node_index = cur.m_left_index; } @@ -1545,7 +1545,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)) @@ -1634,7 +1634,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++; @@ -1648,7 +1648,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)) @@ -1675,10 +1675,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; } @@ -1774,7 +1774,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); } @@ -1855,8 +1855,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); @@ -1908,7 +1908,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; @@ -2010,7 +2010,7 @@ namespace basisu } Quantizer quantizers[cMaxThreads]; - + bool success_flags[cMaxThreads]; clear_obj(success_flags); @@ -2112,10 +2112,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(); @@ -2124,7 +2124,7 @@ namespace basisu unique_vecs.reserve(20000); weighted_block_group g; - + if (even_odd_input_pairs_equal) { g.m_indices.resize(2); @@ -2209,7 +2209,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); } } @@ -2286,7 +2286,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]) @@ -2295,7 +2295,7 @@ namespace basisu return e; } }; - + struct sym_freq { uint32_t m_key; @@ -2305,7 +2305,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: @@ -2326,7 +2326,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; } @@ -2393,7 +2393,7 @@ namespace basisu m_bit_buffer = 0; m_bit_buffer_size = 0; - + return 8; } @@ -2442,7 +2442,7 @@ namespace basisu if (v < u) return put_bits(v, k); - + uint32_t x = v + u; assert((x >> 1) >= u); @@ -2454,20 +2454,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); } @@ -2477,13 +2477,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; @@ -2495,7 +2495,7 @@ namespace basisu } uint32_t emit_huffman_table(const huffman_encoding_table &tab); - + private: uint8_vec m_bytes; uint32_t m_bit_buffer, m_bit_buffer_size; @@ -2523,7 +2523,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; @@ -2577,7 +2577,7 @@ namespace basisu return true; } - + inline uint32_t emit_next_sym(bitwise_coder &c) { uint32_t bits = 0; @@ -2607,7 +2607,7 @@ namespace basisu bool huffman_test(int rand_seed); // VQ index reordering - + class palette_index_reorderer { public: @@ -2628,7 +2628,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; } @@ -2649,12 +2649,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); @@ -2695,7 +2695,7 @@ namespace basisu image &clear() { - m_width = 0; + m_width = 0; m_height = 0; m_pitch = 0; clear_vector(m_pixels); @@ -2717,7 +2717,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++) @@ -2803,7 +2803,7 @@ namespace basisu p = w; clear(); - + if ((!p) || (!w) || (!h)) return *this; @@ -2882,8 +2882,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; @@ -3039,7 +3039,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, ...); - + private: uint32_t m_width, m_height, m_pitch; // all in pixels color_rgba_vec m_pixels; @@ -3052,12 +3052,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); @@ -3092,7 +3092,7 @@ namespace basisu imagef &clear() { - m_width = 0; + m_width = 0; m_height = 0; m_pitch = 0; clear_vector(m_pixels); @@ -3142,7 +3142,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) @@ -3161,7 +3161,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++) @@ -3224,8 +3224,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; @@ -3308,7 +3308,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)) @@ -3353,14 +3353,14 @@ namespace basisu fprintf(stderr, "One or more 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 pixels had to be clamped to %f.\n", highest_mag); @@ -3385,7 +3385,7 @@ namespace basisu return *this; } - + private: uint32_t m_width, m_height, m_pitch; // all in pixels vec4F_vec m_pixels; @@ -3403,7 +3403,7 @@ namespace basisu float srgb_to_linear(float s); // Image metrics - + class image_metrics { public: @@ -3451,7 +3451,7 @@ namespace basisu bool load_jpg(const char *pFilename, 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); } @@ -3473,7 +3473,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; @@ -3485,13 +3485,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; } }; @@ -3503,7 +3503,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 @@ -3513,7 +3513,7 @@ namespace basisu // Supports 1 (Y), 3 (RGB), or 4 (RGBA) channel images. bool write_exr(const char* pFilename, imagef& img, uint32_t n_chans, uint32_t flags); - + enum { cImageSaveGrayscale = 1, @@ -3522,26 +3522,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 @@ -3554,7 +3554,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(); @@ -3624,8 +3624,8 @@ namespace basisu inline const T &operator[] (uint32_t i) const { return m_values[i]; } inline T &operator[] (uint32_t i) { return m_values[i]; } - - inline const T &at_clamped(int x, int y) const { return (*this)(clamp(x, 0, m_width - 1), clamp(y, 0, m_height - 1)); } + + inline const T &at_clamped(int x, int y) const { return (*this)(clamp(x, 0, m_width - 1), clamp(y, 0, m_height - 1)); } inline T &at_clamped(int x, int y) { return (*this)(clamp(x, 0, m_width - 1), clamp(y, 0, m_height - 1)); } void clear() @@ -3725,7 +3725,7 @@ namespace basisu void tonemap_image_reinhard(image& ldr_img, const imagef& hdr_img, float exposure); bool tonemap_image_compressive(image& dst_img, const imagef& hdr_test_img); - + // Intersection enum eClear { cClear = 0 }; enum eInitExpand { cInitExpand = 0 }; @@ -4023,7 +4023,5 @@ namespace basisu return o.f; } - -} // namespace basisu - +} // namespace basisu 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 750f706a..42d388ec 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++) { @@ -428,7 +428,7 @@ namespace basisu #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job([this, first_index, last_index, pass] { #endif - + 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]; @@ -441,7 +441,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)) @@ -564,7 +564,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; } @@ -598,9 +598,9 @@ namespace basisu const uint32_t new_selector_cluster_index = (uint32_t)m_optimized_cluster_selectors.size(); 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()) @@ -608,7 +608,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)); @@ -624,10 +624,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; @@ -703,7 +703,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); } @@ -732,7 +732,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); @@ -743,7 +743,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); } @@ -753,11 +753,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; @@ -767,7 +767,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; @@ -778,7 +778,7 @@ namespace basisu m_opencl_failed = true; } } - + if (use_cpu) { const uint32_t N = 4096; @@ -841,16 +841,16 @@ namespace basisu #endif } // 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; @@ -864,12 +864,12 @@ namespace basisu #endif 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); @@ -877,7 +877,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); @@ -949,12 +949,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) @@ -968,7 +968,7 @@ namespace basisu } } } - + if (m_params.m_debug_stats) debug_printf("Total endpoint clusters: %u, parent clusters: %u\n", (uint32_t)m_endpoint_clusters.size(), (uint32_t)m_endpoint_parent_clusters.size()); } @@ -1026,7 +1026,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()); } @@ -1039,8 +1039,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((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N); + const uint32_t first_index = cluster_index_iter; + const uint32_t last_index = minimum((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N); #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index] { @@ -1071,7 +1071,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); @@ -1103,7 +1103,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); @@ -1124,7 +1124,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"); @@ -1195,9 +1195,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--; @@ -1233,23 +1233,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(); @@ -1262,7 +1262,7 @@ namespace basisu const uint32_t total_clusters = m_endpoint_clusters.size(); basisu::vector pixel_clusters(total_clusters); - + std::vector input_pixels; input_pixels.reserve(m_total_blocks * 16); @@ -1295,7 +1295,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++) { @@ -1347,7 +1347,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]; @@ -1395,7 +1395,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); @@ -1407,7 +1407,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]; @@ -1440,9 +1440,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; @@ -1492,7 +1492,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]; @@ -1500,7 +1500,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; @@ -1689,7 +1689,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(); @@ -1710,9 +1710,9 @@ namespace basisu } // cluster_indices_iter } - + //---------------------------------------------------------- - + // Create a new endpoint clusterization interval_timer tm; @@ -1729,7 +1729,7 @@ namespace basisu const uint32_t total_parent_clusters = 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++) @@ -1743,7 +1743,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; @@ -1769,11 +1769,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]); @@ -1788,7 +1788,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(), @@ -1946,7 +1946,7 @@ namespace basisu break; } } // j - + best_cluster_indices[block_index] = best_cluster_index; } // block_index @@ -1960,9 +1960,9 @@ namespace basisu #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); #endif - + } // 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()); @@ -2005,7 +2005,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]; @@ -2020,7 +2020,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()) @@ -2038,7 +2038,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]); @@ -2046,7 +2046,7 @@ namespace basisu i = j; } - + if (m_endpoint_clusters.size() != new_endpoint_clusters.size()) { if (m_params.m_debug_stats) @@ -2061,7 +2061,7 @@ namespace basisu void basisu_frontend::create_initial_packed_texture() { debug_printf("create_initial_packed_texture\n"); - + interval_timer tm; tm.start(); @@ -2074,7 +2074,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]; @@ -2142,7 +2142,7 @@ namespace basisu #endif } // use_cpu - + m_orig_encoded_blocks = m_encoded_blocks; debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); @@ -2159,7 +2159,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 @@ -2184,7 +2184,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()); } @@ -2193,11 +2193,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) { @@ -2227,10 +2227,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 #ifndef __EMSCRIPTEN__ @@ -2295,7 +2295,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++) { @@ -2327,7 +2327,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) @@ -2335,7 +2335,7 @@ namespace basisu const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)total_selector_clusters, cluster_index_iter + N); -#ifndef __EMSCRIPTEN__ +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job([this, first_index, last_index] { #endif @@ -2417,7 +2417,7 @@ namespace basisu #endif 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; @@ -2443,7 +2443,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)); @@ -2465,7 +2465,7 @@ namespace basisu interval_timer tm; tm.start(); - + if (m_params.m_validate) { // Sanity checks @@ -2480,7 +2480,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. @@ -2501,7 +2501,7 @@ namespace basisu return; } - + bool use_cpu = true; if ((m_params.m_pOpenCL_context) && m_use_hierarchical_selector_codebooks) @@ -2510,17 +2510,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]; @@ -2530,7 +2530,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); } @@ -2538,7 +2538,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++) { @@ -2562,7 +2562,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"); @@ -2576,7 +2576,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]; @@ -2608,7 +2608,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) { @@ -2624,7 +2624,7 @@ namespace basisu 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))) @@ -2632,18 +2632,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) @@ -2720,7 +2720,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]; @@ -2753,7 +2753,7 @@ namespace basisu m_block_selector_cluster_index[block_index] = best_cluster_index; prev_best_cluster_index = best_cluster_index; - + } // block_index #ifndef __EMSCRIPTEN__ @@ -2765,7 +2765,7 @@ namespace basisu #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); #endif - + for (uint32_t i = 0; i < m_selector_cluster_block_indices.size(); i++) { m_selector_cluster_block_indices[i].resize(0); @@ -2779,7 +2779,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()); @@ -2789,7 +2789,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); @@ -2970,7 +2970,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; } @@ -3062,7 +3062,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) { @@ -3074,12 +3074,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); #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &cluster_improved, &cluster_valid, &new_endpoint_cluster_block_indices, &pBlock_selector_indices ] { @@ -3101,13 +3101,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)); @@ -3119,14 +3119,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]; @@ -3165,7 +3165,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; } @@ -3182,13 +3182,13 @@ namespace basisu #ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); #endif - + 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++) @@ -3223,7 +3223,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); @@ -3236,13 +3236,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; @@ -3278,7 +3278,7 @@ namespace basisu debug_printf("Final (post-RDO) endpoint clusters: %u\n", m_endpoint_clusters.size()); } - + //debug_printf("validate_output: %u\n", validate_output()); } @@ -3306,7 +3306,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; } } @@ -3330,7 +3330,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 @@ -3344,7 +3344,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++) { @@ -3369,7 +3369,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); @@ -3383,11 +3383,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)); @@ -3407,7 +3407,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 } @@ -3460,4 +3460,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 000869a5..bfd9f725 100644 --- a/encoder/basisu_gpu_texture.cpp +++ b/encoder/basisu_gpu_texture.cpp @@ -34,9 +34,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; @@ -70,16 +70,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); @@ -125,9 +125,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)]; } } @@ -135,9 +135,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)]); } } @@ -204,9 +204,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)]; } } @@ -214,9 +214,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)]); } } @@ -242,7 +242,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) @@ -261,9 +261,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)]; } } @@ -271,9 +271,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)]); } } @@ -296,7 +296,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); @@ -307,7 +307,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); @@ -362,7 +362,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) { @@ -372,7 +372,7 @@ namespace basisu success = false; unpack_bc4(pBlock_bits, &pPixels[0].a, sizeof(color_rgba)); - + return success; } @@ -382,7 +382,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 @@ -430,9 +430,9 @@ namespace basisu for (uint32_t i = 0; i < 16; i++) { const uint32_t s = sels & 3; - + pPixels[i] = c[s]; - + sels >>= 2; } } @@ -455,12 +455,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; @@ -470,7 +470,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); @@ -522,7 +522,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); @@ -534,21 +534,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++) @@ -587,11 +587,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)); @@ -693,10 +693,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); } @@ -709,7 +709,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]; @@ -753,7 +753,7 @@ namespace basisu return false; } - + static inline int bc6h_sign_extend(int val, int bits) { assert((bits >= 1) && (bits < 32)); @@ -1103,7 +1103,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; @@ -1153,7 +1153,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]; @@ -1214,7 +1214,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]); @@ -1237,10 +1237,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); @@ -1249,11 +1249,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 @@ -1329,9 +1329,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); @@ -1360,7 +1360,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) { @@ -1437,7 +1437,7 @@ namespace basisu if (!status) return false; - + break; } case texture_format::cATC_RGB: @@ -1500,7 +1500,7 @@ namespace basisu return false; #else 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; @@ -1545,7 +1545,7 @@ namespace basisu assert(0); return false; } - + bool gpu_image::unpack(image& img) const { img.resize(get_pixel_width(), get_pixel_height()); @@ -1557,10 +1557,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(); @@ -1595,7 +1595,7 @@ namespace basisu bool gpu_image::unpack_hdr(imagef& img) const { - if ((m_fmt != texture_format::cASTC_HDR_4x4) && + if ((m_fmt != texture_format::cASTC_HDR_4x4) && (m_fmt != texture_format::cUASTC_HDR_4x4) && (m_fmt != texture_format::cBC6HUnsigned) && (m_fmt != texture_format::cBC6HSigned)) @@ -1632,14 +1632,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, @@ -1669,7 +1669,7 @@ namespace basisu KTX_COMPRESSED_R11_EAC = 0x9270, KTX_COMPRESSED_RG11_EAC = 0x9272 }; - + struct ktx_header { uint8_t m_identifier[12]; @@ -1711,7 +1711,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]; @@ -2100,7 +2100,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); }; @@ -2110,7 +2110,7 @@ namespace basisu uint32_t mipmap_sizes[32]; const void* mipmap_ptrs[32]; - + clear_obj(mipmap_sizes); clear_obj(mipmap_ptrs); @@ -2128,7 +2128,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: @@ -2157,7 +2157,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; @@ -2179,7 +2179,7 @@ namespace basisu fprintf(stderr, "write_dds_file: Failed creating DDS file\n"); return false; } - + return true; } @@ -2198,7 +2198,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; @@ -2209,7 +2209,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); }; @@ -2249,7 +2249,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); @@ -2258,7 +2258,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); @@ -2270,7 +2270,7 @@ namespace basisu error_printf("DDS texture dimensions too large in file \"%s\"\n", pFilename); goto failure; } - + tfmt = TinyDDS_GetFormat(ctx); switch (tfmt) { @@ -2318,7 +2318,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. @@ -2347,7 +2347,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); @@ -2357,7 +2357,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]); @@ -2431,7 +2431,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; @@ -2463,11 +2463,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) @@ -2509,6 +2509,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_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 e0611c18..323c59c1 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); @@ -938,7 +938,7 @@ namespace basisu assert(pContext->m_ocl_pixel_blocks); if (!pContext->m_ocl_pixel_blocks) return false; - + cl_encode_etc1s_param_struct ps; ps.m_total_blocks = pContext->m_ocl_total_pixel_blocks; ps.m_perceptual = perceptual; @@ -948,7 +948,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; @@ -986,7 +986,7 @@ namespace basisu interval_timer tm; tm.start(); - + cl_encode_etc1s_param_struct ps; ps.m_total_blocks = total_clusters; ps.m_perceptual = perceptual; @@ -1003,7 +1003,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)); @@ -1062,7 +1062,7 @@ namespace basisu assert(pContext->m_ocl_pixel_blocks); if (!pContext->m_ocl_pixel_blocks) return false; - + cl_rec_param_struct ps; ps.m_total_blocks = pContext->m_ocl_total_pixel_blocks; ps.m_perceptual = perceptual; @@ -1073,7 +1073,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; @@ -1087,7 +1087,7 @@ namespace basisu goto exit; debug_printf("opencl_refine_endpoint_clusterization: Elapsed time: %3.3f secs\n", tm.get_elapsed_secs()); - + status = true; exit: @@ -1121,7 +1121,7 @@ namespace basisu fosc_param_struct ps; ps.m_total_blocks = 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); @@ -1192,9 +1192,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); @@ -1202,7 +1202,7 @@ namespace basisu return status; } -#else +#else namespace basisu { // No OpenCL support - all dummy functions that return false; @@ -1269,7 +1269,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 2546a18d..8c4766ba 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 46cd8373..7e89cfaf 100644 --- a/encoder/basisu_resample_filters.cpp +++ b/encoder/basisu_resample_filters.cpp @@ -310,21 +310,21 @@ namespace basisu const resample_filter g_resample_filters[] = { - { "box", box_filter, BOX_FILTER_SUPPORT }, - { "tent", tent_filter, TENT_FILTER_SUPPORT }, - { "bell", bell_filter, BELL_SUPPORT }, + { "box", box_filter, BOX_FILTER_SUPPORT }, + { "tent", tent_filter, TENT_FILTER_SUPPORT }, + { "bell", bell_filter, BELL_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, GAUSSIAN_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 a00c6333..4db2f27f 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_ssim.cpp b/encoder/basisu_ssim.cpp index 608ce937..3ff42c6f 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) { @@ -316,14 +316,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 51f6e979..ef467a07 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; @@ -3838,8 +3838,8 @@ namespace basisu uint64_t m_total; uint64_t m_total2; }; - - 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); @@ -3848,7 +3848,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]; @@ -3898,7 +3898,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); @@ -3953,7 +3953,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) { @@ -4075,7 +4075,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; @@ -4102,7 +4102,7 @@ namespace basisu // Write the modified block pBlocks[block_index] = best_block; - + } // if (best_block_index != block_index) { @@ -4118,8 +4118,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. @@ -4160,7 +4160,7 @@ namespace basisu { std::lock_guard lck(stat_mutex); - + all_succeeded = all_succeeded && status; total_skipped += job_skipped; total_modified += job_modified; @@ -4183,12 +4183,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/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 539d3ed8..46e698a4 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 a6d3bee0..0791f9ff 100644 --- a/encoder_lib/encoder_lib.vcxproj +++ b/encoder_lib/encoder_lib.vcxproj @@ -232,4 +232,4 @@ - \ No newline at end of file + diff --git a/encoder_lib/encoder_lib.vcxproj.filters b/encoder_lib/encoder_lib.vcxproj.filters index 305ecccb..e3ddd739 100644 --- a/encoder_lib/encoder_lib.vcxproj.filters +++ b/encoder_lib/encoder_lib.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -242,4 +242,4 @@ Source Files\encoder - \ No newline at end of file + diff --git a/example/example.cpp b/example/example.cpp index 34201708..69be9032 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; @@ -171,7 +171,7 @@ static bool encode_uastc_ldr() static bool encode_uastc_hdr() { const uint32_t W = 256, H = 256; - + imagef img(W, H); #if 1 @@ -194,7 +194,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. @@ -217,13 +217,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() { @@ -250,10 +250,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); @@ -421,7 +421,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); @@ -429,7 +429,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); @@ -468,7 +468,7 @@ static bool block_unpack_and_transcode_example(void) return false; } } // test_block_iter - + printf("Transcode test OK\n"); return true; @@ -490,7 +490,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 @@ -566,7 +566,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); @@ -574,7 +574,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 147e21fe..f816b535 100644 --- a/example/example.vcxproj +++ b/example/example.vcxproj @@ -169,4 +169,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 939ee79e..d9343c05 100644 --- a/transcoder/basisu.h +++ b/transcoder/basisu.h @@ -125,16 +125,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 template inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; } @@ -142,7 +142,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); } @@ -166,7 +166,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); } @@ -214,8 +214,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()) @@ -266,7 +266,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; @@ -332,7 +332,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 @@ -342,41 +342,41 @@ 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; } #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); } @@ -398,13 +398,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; @@ -418,14 +418,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 @@ -451,13 +451,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 @@ -475,11 +475,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, @@ -526,7 +526,7 @@ namespace basisu default: break; } - + // Everything else is 16 bytes/block. return 16; } @@ -566,6 +566,5 @@ namespace basisu return true; return false; } - -} // namespace basisu +} // namespace basisu diff --git a/transcoder/basisu_astc_helpers.h b/transcoder/basisu_astc_helpers.h index 09a234b2..402c9eaa 100644 --- a/transcoder/basisu_astc_helpers.h +++ b/transcoder/basisu_astc_helpers.h @@ -83,7 +83,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 { @@ -92,7 +92,7 @@ namespace astc_helpers CCS_RGA_B = 2, CCS_RGB_A = 3 }; - + struct astc_block { uint32_t m_vals[4]; @@ -106,13 +106,13 @@ namespace astc_helpers struct log_astc_block { bool m_error_flag; - + bool m_solid_color_flag_ldr, m_solid_color_flag_hdr; uint16_t m_solid_color[4]; // Rest is only valid if !m_solid_color_flag_ldr && !m_solid_color_flag_hdr uint32_t m_grid_width, m_grid_height; // weight grid dimensions, not the dimension of the block - + bool m_dual_plane; uint32_t m_weight_ise_range; // 0-11 @@ -122,12 +122,12 @@ namespace astc_helpers uint32_t m_num_partitions; // or the # of subsets, 1-4 (1-3 if dual plane mode) uint32_t m_partition_id; // 10-bits, must be 0 if m_num_partitions==1 - + uint32_t m_color_endpoint_modes[MAX_PARTITIONS]; // each subset's CEM's - + // ISE weight grid values. In dual plane mode, the order is p0,p1, p0,p1, etc. uint8_t m_weights[MAX_GRID_WEIGHTS]; - + // ISE endpoint values // Endpoint order examples: // 1 subset LA : LL0 LH0 AL0 AH0 @@ -161,8 +161,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]; } @@ -175,7 +175,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); @@ -194,10 +194,10 @@ namespace astc_helpers void pack_void_extent_hdr(astc_block& blk, uint16_t rh, uint16_t gh, uint16_t bh, uint16_t ah); // 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 @@ -221,7 +221,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); } @@ -230,7 +230,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) { @@ -299,10 +299,10 @@ namespace astc_helpers extern dequant_tables g_dequant_tables; void init_tables(bool init_rank_tabs); - + // 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); @@ -318,7 +318,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 @@ -335,7 +335,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 @@ -349,11 +349,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] = @@ -382,7 +382,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); @@ -522,7 +522,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++) @@ -568,14 +568,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 @@ -612,7 +612,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)) { @@ -640,7 +640,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)) { @@ -662,7 +662,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]); @@ -673,7 +673,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]); return true; } - + if ((log_block.m_num_partitions < 1) || (log_block.m_num_partitions > MAX_PARTITIONS)) return false; @@ -687,7 +687,7 @@ namespace astc_helpers if (log_block.m_color_component_selector > 3) return false; - + uint32_t config_bits = 0; if (!get_config_bits(log_block, config_bits)) return false; @@ -722,7 +722,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; @@ -737,7 +737,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; @@ -772,7 +772,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); } @@ -814,7 +814,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); @@ -1008,12 +1008,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]; @@ -1054,7 +1054,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); @@ -1067,11 +1067,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)); @@ -1187,22 +1187,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; } @@ -1229,13 +1229,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) + void pack_void_extent_hdr(astc_block& blk, uint16_t rh, uint16_t gh, uint16_t bh, uint16_t ah) { 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; @@ -1245,7 +1245,7 @@ namespace astc_helpers pDst[14] = (uint8_t)ah; pDst[15] = (uint8_t)(ah >> 8); } - + bool is_cem_ldr(uint32_t mode) { switch (mode) @@ -1264,7 +1264,7 @@ namespace astc_helpers default: break; } - + return false; } @@ -1319,7 +1319,7 @@ namespace astc_helpers return false; } - + dequant_tables g_dequant_tables; void precompute_texel_partitions_4x4(); @@ -1327,7 +1327,7 @@ namespace astc_helpers void init_tables(bool init_rank_tabs) { g_dequant_tables.init(init_rank_tabs); - + precompute_texel_partitions_4x4(); } @@ -1524,13 +1524,13 @@ 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; } 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; @@ -1545,7 +1545,7 @@ namespace astc_helpers b |= (a & 0x80); a >>= 1; a &= 0x3F; - if ((a & 0x20) != 0) + if ((a & 0x20) != 0) a -= 0x40; } @@ -1779,7 +1779,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: @@ -1796,11 +1796,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; @@ -1811,36 +1811,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; @@ -1864,25 +1864,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); @@ -1906,7 +1906,7 @@ namespace astc_helpers e0_a = 0x780; e1_a = 0x780; - if (majcomp == 3) + if (majcomp == 3) { e0_r = v0 << 4; e0_g = v2 << 4; @@ -2007,12 +2007,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; } } @@ -2031,7 +2031,7 @@ namespace astc_helpers } } } - + static inline bool is_half_inf_or_nan(half_float v) { return get_bits(v, 10, 14) == 31; @@ -2170,7 +2170,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; @@ -2184,9 +2184,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 { @@ -2222,7 +2222,7 @@ namespace astc_helpers exp_shared += 1; assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); } - else + else { assert(maxm <= MAX_RGB9E5_MANTISSA); } @@ -2234,7 +2234,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); } @@ -2245,7 +2245,7 @@ namespace astc_helpers if (!x) return 17; - + uint32_t n = 0; while ((x & 0x10000) == 0) { @@ -2322,18 +2322,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) { @@ -2407,7 +2407,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++) @@ -2420,7 +2420,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; @@ -2444,7 +2444,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 @@ -2455,7 +2455,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]); } @@ -2473,13 +2473,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++) { @@ -2516,7 +2516,7 @@ namespace astc_helpers const bool small_block = num_blk_pixels < 31; const bool use_precomputed_texel_partitions = (blk_width == 4) && (blk_height == 4) && (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) @@ -2527,7 +2527,7 @@ namespace astc_helpers for (uint32_t x = 0; x < blk_width; x++) { const uint32_t pixel_index = x + y * blk_width; - const uint32_t subset = (log_blk.m_num_partitions > 1) ? + const uint32_t subset = (log_blk.m_num_partitions > 1) ? (use_precomputed_texel_partitions ? get_precompute_texel_partitions_4x4(log_blk.m_partition_id, x, y, log_blk.m_num_partitions) : compute_texel_partition(log_blk.m_partition_id, x, y, 0, log_blk.m_num_partitions, small_block)) : 0; @@ -2568,7 +2568,7 @@ namespace astc_helpers if (is_half_inf_or_nan((half_float)comp[c])) comp[c] = 0x7BFF; } - + } // c uint32_t packed; @@ -2585,7 +2585,7 @@ 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++) { @@ -2631,13 +2631,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; } @@ -2688,7 +2688,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); } @@ -2697,7 +2697,7 @@ namespace astc_helpers } // x } // y } - + return success; } @@ -3093,7 +3093,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) @@ -3105,9 +3105,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; @@ -3129,7 +3129,7 @@ namespace astc_helpers if (is_half_inf_or_nan(log_blk.m_solid_color[c])) return false; } - + return true; } @@ -3142,7 +3142,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 @@ -3164,14 +3164,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); @@ -3217,7 +3217,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); @@ -3226,7 +3226,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); @@ -3234,10 +3234,10 @@ namespace astc_helpers uint32_t p = p0 | (p1 << 1) | (p2 << 2); if (p < 2) return false; - + log_blk.m_grid_width = W; log_blk.m_grid_height = H; - + log_blk.m_weight_ise_range = (p - 2) + (P * BISE_10_LEVELS); assert(log_blk.m_weight_ise_range <= LAST_VALID_WEIGHT_ISE_RANGE); @@ -3353,7 +3353,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]) @@ -3394,24 +3394,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; @@ -3425,16 +3425,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; @@ -3471,9 +3471,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; @@ -3539,7 +3539,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) @@ -3581,7 +3581,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 bfc51bb4..d6667bff 100644 --- a/transcoder/basisu_containers.h +++ b/transcoder/basisu_containers.h @@ -290,15 +290,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, m_size * sizeof(T)); #ifndef __EMSCRIPTEN__ #ifdef __GNUC__ #pragma GCC diagnostic pop -#endif +#endif #endif } else @@ -345,15 +345,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 @@ -383,28 +383,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 @@ -412,7 +412,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]; } @@ -420,42 +420,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 @@ -747,7 +747,7 @@ namespace basisu insert(m_size, p, n); return *this; } - + inline void erase(uint32_t start, uint32_t n) { assert((start + n) <= m_size); @@ -778,7 +778,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 @@ -787,12 +787,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; while (pDst != pDst_end) @@ -1012,7 +1012,7 @@ namespace basisu if (!m) break; cmp = -cmp; i += (((m + 1) >> 1) ^ cmp) - cmp; - if (i < 0) + if (i < 0) break; } } @@ -1045,15 +1045,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 @@ -1171,7 +1171,7 @@ namespace basisu public: class iterator; class const_iterator; - + private: friend class iterator; friend class const_iterator; @@ -1359,7 +1359,7 @@ namespace basisu if (new_hash_size > m_values.size()) rehash((uint32_t)new_hash_size); } - + class iterator { friend class hash_map; @@ -1794,7 +1794,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); @@ -2011,11 +2011,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 diff --git a/transcoder/basisu_containers_impl.h b/transcoder/basisu_containers_impl.h index 60c0b3d8..39c2ee01 100644 --- a/transcoder/basisu_containers_impl.h +++ b/transcoder/basisu_containers_impl.h @@ -31,9 +31,9 @@ namespace basisu fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n"); abort(); } - + const uint64_t desired_size_u64 = (uint64_t)element_size * new_capacity; - + const size_t desired_size = (size_t)desired_size_u64; if (desired_size_u64 != desired_size) { @@ -97,7 +97,7 @@ namespace basisu if (m_p) free(m_p); - + m_p = new_p; } diff --git a/transcoder/basisu_file_headers.h b/transcoder/basisu_file_headers.h index d29e3feb..22050dab 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 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 { @@ -112,7 +112,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 @@ -122,11 +122,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 @@ -134,7 +134,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 ea994b0c..3172d316 100644 --- a/transcoder/basisu_transcoder.cpp +++ b/transcoder/basisu_transcoder.cpp @@ -179,7 +179,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) @@ -241,7 +241,7 @@ namespace basist return static_cast(~crc); } - + enum etc_constants { cETC1BytesPerBlock = 8U, @@ -314,14 +314,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; @@ -589,7 +589,7 @@ namespace basist { return (m_bytes[3] & 2) != 0; } - + inline uint32_t get_inten_table(uint32_t subblock_id) const { assert(subblock_id < 2); @@ -604,7 +604,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; @@ -722,7 +722,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); @@ -851,7 +851,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]; @@ -1027,7 +1027,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]; @@ -1419,9 +1419,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] = @@ -1911,18 +1911,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(); @@ -1938,7 +1938,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(); @@ -2198,7 +2198,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)); @@ -2358,7 +2358,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); @@ -2371,7 +2371,7 @@ namespace basist uint32_t g0 = color0.g & 1; uint32_t g1 = color1.g & 1; - + color0.g >>= 1; color1.g >>= 1; @@ -2379,7 +2379,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); @@ -2393,7 +2393,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; @@ -2714,7 +2714,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; @@ -2797,7 +2797,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, @@ -2821,7 +2821,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, @@ -2845,7 +2845,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, @@ -2869,7 +2869,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, @@ -2976,10 +2976,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); @@ -3026,7 +3026,7 @@ namespace basist a = g_pvrtc_alpha[a]; } - + return color32(r, g, b, a); } @@ -3035,7 +3035,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; @@ -3150,7 +3150,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) @@ -3203,7 +3203,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); @@ -3428,7 +3428,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]; @@ -3436,7 +3436,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]; @@ -3585,8 +3585,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) { @@ -3609,7 +3609,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]; @@ -3617,7 +3617,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]; @@ -3631,13 +3631,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) { @@ -3780,7 +3780,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] = { @@ -3802,11 +3802,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 }, @@ -3831,7 +3831,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); @@ -3978,7 +3978,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; @@ -4057,7 +4057,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; @@ -4068,7 +4068,7 @@ namespace basist best_k = k; } } // k - + total_err += best_mapping_err; output_selectors |= (best_k << (s * 2)); } // s @@ -4083,7 +4083,7 @@ namespace basist } // lo } // hi - + fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, best_output_selectors); n++; if ((n & 31) == 31) @@ -4122,7 +4122,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 @@ -4150,9 +4150,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"); } @@ -4176,7 +4176,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; @@ -4302,7 +4302,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 @@ -4323,7 +4323,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); @@ -4353,7 +4353,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) @@ -4403,7 +4403,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; @@ -4873,7 +4873,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" @@ -4938,7 +4938,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; @@ -4959,7 +4959,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++) @@ -5035,7 +5035,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))) @@ -5064,9 +5064,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"); @@ -5149,14 +5149,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. @@ -5178,7 +5178,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 }; @@ -5187,7 +5187,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) { @@ -5225,7 +5225,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; @@ -5251,7 +5251,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; @@ -5279,7 +5279,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++) @@ -5357,7 +5357,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++) { @@ -5372,9 +5372,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) @@ -5396,7 +5396,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) @@ -5411,7 +5411,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; @@ -5455,7 +5455,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); @@ -5475,7 +5475,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); @@ -5522,7 +5522,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 @@ -5555,12 +5555,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)) { @@ -5594,7 +5594,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]; @@ -5602,7 +5602,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++) @@ -5646,10 +5646,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; @@ -5791,7 +5791,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]; @@ -5835,7 +5835,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; @@ -5937,7 +5937,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; @@ -6102,8 +6102,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); @@ -6157,7 +6157,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; @@ -6292,7 +6292,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; @@ -6366,7 +6366,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; @@ -6396,7 +6396,7 @@ namespace basist } // inten fclose(pFile); - + // PVRTC2 45 fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_45.inc", "w"); @@ -6441,7 +6441,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; @@ -6518,7 +6518,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; @@ -6595,7 +6595,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; @@ -6672,7 +6672,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; @@ -6800,12 +6800,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; @@ -6815,7 +6815,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) { @@ -6929,7 +6929,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; } @@ -6947,9 +6947,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) { @@ -7004,13 +7004,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++) { @@ -7039,14 +7039,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); @@ -7075,14 +7075,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; @@ -7157,7 +7157,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); @@ -7169,7 +7169,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) || @@ -7220,7 +7220,7 @@ namespace basist } vec4F_normalize_in_place(&axis); - + if (vec4F_dot(&axis, &axis) < .5f) vec4F_set_scalar(&axis, .5f); @@ -7320,10 +7320,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); @@ -7396,7 +7396,7 @@ namespace basist } } } - + static void transcoder_init_pvrtc2() { for (uint32_t v = 0; v < 256; v++) @@ -7502,7 +7502,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; @@ -7632,7 +7632,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"); @@ -7657,7 +7657,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) @@ -7838,7 +7838,7 @@ namespace basist if (!output_rows_in_pixels) output_rows_in_pixels = orig_height; } - + basisu::vector* pPrev_frame_indices = nullptr; if (is_video) { @@ -7866,12 +7866,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); @@ -8119,7 +8119,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); @@ -8170,7 +8170,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); @@ -8186,7 +8186,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -8194,7 +8194,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); @@ -8202,7 +8202,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; @@ -8237,7 +8237,7 @@ namespace basist pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints; #else assert(0); -#endif +#endif break; } @@ -8321,7 +8321,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; @@ -8337,10 +8337,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); @@ -8354,7 +8354,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); } } @@ -8383,7 +8383,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]; @@ -8504,7 +8504,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); @@ -8636,7 +8636,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. @@ -8716,7 +8716,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; @@ -8747,7 +8747,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"); @@ -8872,7 +8872,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); } @@ -8910,8 +8910,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); @@ -9040,7 +9040,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); @@ -9100,7 +9100,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); } @@ -9121,7 +9121,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); @@ -9162,7 +9162,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); @@ -9266,14 +9266,14 @@ namespace basist } //------------------------------------------------------------------------------------------------ - + basisu_lowlevel_uastc_transcoder::basisu_lowlevel_uastc_transcoder() { } bool basisu_lowlevel_uastc_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) { @@ -9334,7 +9334,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) @@ -9370,7 +9370,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; @@ -9533,7 +9533,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, @@ -9555,7 +9555,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)) { @@ -9582,7 +9582,7 @@ namespace basist BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: output buffer size too small\n"); return false; } - + bool status = false; // UASTC4x4 @@ -9593,7 +9593,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"); @@ -9819,7 +9819,7 @@ namespace basist bool basisu_lowlevel_uastc_hdr_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) { @@ -9866,7 +9866,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; @@ -9901,7 +9901,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); @@ -9915,7 +9915,7 @@ namespace basist } // y } } - + break; } case block_format::cRGBA_HALF: @@ -9927,7 +9927,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); @@ -10121,7 +10121,7 @@ namespace basist } //------------------------------------------------------------------------------------------------ - + basisu_transcoder::basisu_transcoder() : m_ready_to_transcode(false) { @@ -10149,7 +10149,7 @@ namespace basist return false; } } -#endif +#endif return true; } @@ -10236,7 +10236,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) { @@ -10252,7 +10252,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)) ) @@ -10368,12 +10368,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; @@ -10496,13 +10496,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; @@ -10560,7 +10560,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; @@ -10625,7 +10625,7 @@ namespace basist return true; } - + bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size) { if (!validate_header_quick(pData, data_size)) @@ -10733,7 +10733,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); } } - + m_ready_to_transcode = true; return true; @@ -10744,7 +10744,7 @@ namespace basist m_lowlevel_etc1s_decoder.clear(); m_ready_to_transcode = false; - + return true; } @@ -10783,7 +10783,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 @@ -10846,7 +10846,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::cUASTC_HDR_4x4) { return m_lowlevel_uastc_hdr_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y, @@ -10941,7 +10941,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 @@ -11027,7 +11027,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; } @@ -11036,7 +11036,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) @@ -11073,7 +11073,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; @@ -11081,11 +11081,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::cUASTC_HDR_4x4) { const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index]; @@ -11108,7 +11108,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]; @@ -11134,14 +11134,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; @@ -11404,14 +11404,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: @@ -11425,7 +11425,7 @@ namespace basist } return 0; } - + uint32_t basis_get_block_width(transcoder_texture_format tex_type) { switch (tex_type) @@ -11443,7 +11443,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::cUASTC_HDR_4x4) @@ -11526,7 +11526,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 @@ -11557,9 +11557,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] = @@ -12284,7 +12284,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++) @@ -12576,7 +12576,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)); @@ -12632,7 +12632,7 @@ namespace basist return true; } - + if (read_hints) { if (g_uastc_mode_has_bc1_hint0[mode]) @@ -12665,7 +12665,7 @@ namespace basist } else bit_ofs += g_uastc_mode_total_hint_bits[mode]; - + uint32_t subsets = 1; switch (mode) { @@ -12878,7 +12878,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)); @@ -12886,31 +12886,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); @@ -12928,7 +12928,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); @@ -13474,7 +13474,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; @@ -14413,7 +14413,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: -- // -- @@ -15024,7 +15024,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; @@ -15112,7 +15112,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; @@ -15136,7 +15136,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); @@ -15159,7 +15159,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; @@ -15168,7 +15168,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)]; @@ -15211,11 +15211,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; @@ -15289,7 +15289,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); @@ -15341,19 +15341,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]; } @@ -15365,13 +15365,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; @@ -15405,7 +15405,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 @@ -15437,7 +15437,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++) { @@ -15461,7 +15461,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) @@ -15508,13 +15508,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) { @@ -15566,7 +15566,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; @@ -15615,8 +15615,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) @@ -15933,7 +15933,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 @@ -16163,7 +16163,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; @@ -16853,7 +16853,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) @@ -16912,7 +16912,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++) @@ -17028,9 +17028,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 }; @@ -17052,7 +17052,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; @@ -17064,9 +17064,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; } @@ -17101,7 +17101,7 @@ namespace basist // We only support UASTC LDR, UASTC HDR and ETC1S. // Note the DFD's contents are what we are guided by for decoding the KTX2 file, not this format field (currently). - if ((m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED) && + if ((m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED) && (m_header.m_vk_format != basist::KTX2_FORMAT_UASTC_4x4_SFLOAT_BLOCK)) { BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file must be in ETC1S or UASTC LDR/HDR format\n"); @@ -17139,7 +17139,7 @@ namespace basist return false; } } - + // 3.7 levelCount: "levelCount=0 is allowed, except for block-compressed formats" if (m_header.m_level_count < 1) { @@ -17196,7 +17196,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++) { @@ -17216,9 +17216,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"); @@ -17255,7 +17255,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)) @@ -17265,17 +17265,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) { @@ -17288,7 +17288,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; @@ -17304,11 +17304,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." // 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); @@ -17324,7 +17324,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); } @@ -17344,7 +17344,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"); @@ -17388,7 +17388,7 @@ namespace basist return nullptr; } - + bool ktx2_transcoder::start_transcoding() { if (!m_pData) @@ -17397,7 +17397,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()) @@ -17408,7 +17408,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. @@ -17464,7 +17464,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; @@ -17494,9 +17494,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, @@ -17510,7 +17510,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"); @@ -17539,7 +17539,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; @@ -17548,7 +17548,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. @@ -17566,12 +17566,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. @@ -17585,7 +17585,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()) { @@ -17621,7 +17621,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 @@ -17672,12 +17672,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) @@ -17696,7 +17696,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 @@ -17719,7 +17719,7 @@ namespace basist return true; } - + bool ktx2_transcoder::decompress_etc1s_global_data() { // Note: we don't actually support 3D textures in here yet @@ -17758,13 +17758,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; @@ -17798,7 +17798,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)) @@ -17806,7 +17806,7 @@ namespace basist BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_palettes() failed, file is likely corrupted\n"); return false; } - + return true; } @@ -17847,7 +17847,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); @@ -17868,7 +17868,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; @@ -17890,7 +17890,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"); @@ -17919,7 +17919,7 @@ namespace basist return true; } - + #endif // BASISD_SUPPORT_KTX2 bool basisu_transcoder_supports_ktx2() @@ -17986,10 +17986,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 @@ -18018,7 +18018,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} }, @@ -18069,7 +18069,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] { @@ -18093,7 +18093,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 }; - + struct bc6h_logical_block { uint32_t m_mode; @@ -18247,7 +18247,7 @@ namespace basist 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) { @@ -18263,7 +18263,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); } @@ -18392,7 +18392,7 @@ namespace basist log_blk.m_mode = mode; pack_bc6h_block(*pPacked_block, log_blk); - + return; } @@ -18796,13 +18796,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; @@ -19080,7 +19080,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; @@ -19150,7 +19150,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 @@ -19232,7 +19232,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 @@ -19241,7 +19241,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)) || @@ -19366,7 +19366,7 @@ namespace basist assert(0); return false; } - + if (log_blk.m_solid_color_flag_ldr) { // Don't support LDR solid colors. @@ -19382,7 +19382,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; @@ -19390,11 +19390,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; @@ -19440,7 +19440,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; @@ -19453,7 +19453,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; } diff --git a/transcoder/basisu_transcoder.h b/transcoder/basisu_transcoder.h index 8324e996..f6d6140c 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). 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) @@ -183,7 +183,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() { @@ -261,13 +261,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; @@ -288,7 +288,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, @@ -531,11 +531,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. @@ -591,7 +591,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, @@ -601,10 +601,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) @@ -749,12 +749,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"; @@ -762,7 +762,7 @@ namespace basist default: break; } return "?"; - } + } // Information about a single 2D texture "image" in a KTX2 file. struct ktx2_image_level_info @@ -793,7 +793,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 { @@ -811,9 +811,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 { @@ -854,8 +854,8 @@ namespace basist uint32_t get_layers() const { return m_header.m_layer_count; } // Returns cETC1S, cUASTC4x4, or cUASTC_HDR_4x4. 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; } bool is_uastc() const { return get_format() == basist::basis_tex_format::cUASTC4x4; } @@ -875,7 +875,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; } @@ -883,9 +883,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; } @@ -923,18 +923,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. @@ -944,7 +944,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; @@ -953,23 +953,23 @@ 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; basist::basisu_lowlevel_uastc_hdr_transcoder m_uastc_hdr_transcoder; - + ktx2_transcoder_state m_def_transcoder_state; bool m_has_alpha; @@ -989,4 +989,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 17c9dc7c..b5975d80 100644 --- a/transcoder/basisu_transcoder_internal.h +++ b/transcoder/basisu_transcoder_internal.h @@ -45,9 +45,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 @@ -57,9 +57,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 @@ -69,16 +69,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, @@ -91,7 +91,7 @@ namespace basist cUASTC_HDR_4x4, // HDR, transcodes only to 4x4 HDR ASTC, BC6H, or uncompressed cBC6H, cASTC_HDR_4x4, - + cTotalBlockFormats }; @@ -112,9 +112,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; @@ -232,7 +232,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; @@ -401,14 +401,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); @@ -426,7 +426,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; @@ -438,7 +438,7 @@ namespace basist if ((s & chunk_size) == 0) break; - + if (ofs >= 32) { assert(0); @@ -454,7 +454,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; @@ -465,7 +465,7 @@ namespace basist m_bit_buf_size += 8; assert(m_bit_buf_size <= 32); } - + int code_len; int sym; @@ -650,7 +650,7 @@ namespace basist }; struct decoder_etc_block; - + inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); @@ -674,7 +674,7 @@ namespace basist }; uint8_t c[4]; - + uint32_t m; }; @@ -954,7 +954,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) { @@ -968,7 +968,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); @@ -987,8 +987,5 @@ namespace basist void bc6h_enc_block_2subset_mode9_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index] void bc6h_enc_block_2subset_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index] bool bc6h_enc_block_solid_color(bc6h_block* pPacked_block, const half_float pColor[3]); - -} // 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 b2d69da7..30e815e7 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. diff --git a/webgl/encoder/CMakeLists.txt b/webgl/encoder/CMakeLists.txt index 7813950f..f754833d 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 11) - + 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_astc_hdr_enc.cpp ../../encoder/3rdparty/tinyexr.cpp @@ -49,29 +49,29 @@ if (EMSCRIPTEN) #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) - + #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 -s ASSERTIONS=2) - + # 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 ALLOW_MEMORY_GROWTH=1 -O3 -s STACK_SIZE=262144 -s ASSERTIONS=0 -s MALLOC=emmalloc -s MODULARIZE=1 -s EXPORT_NAME=BASIS ") - + #LINK_FLAGS "--bind -s INITIAL_MEMORY=299958272 -g -s STACK_SIZE=262144 -s DEMANGLE_SUPPORT=1 -s ALLOW_MEMORY_GROWTH=1 -O1 -s ASSERTIONS=1 -s MALLOC=emmalloc -s MODULARIZE=1 -s EXPORT_NAME=BASIS -fsanitize=undefined -fsanitize=address") - + #LINK_FLAGS "--bind -s INITIAL_MEMORY=299958272 -g -s STACK_SIZE=262144 -s DEMANGLE_SUPPORT=1 -s ALLOW_MEMORY_GROWTH=1 -O0 -s ASSERTIONS=2 -s MALLOC=emmalloc -s MODULARIZE=1 -s EXPORT_NAME=BASIS") - + # TODO: 300MB is really large - probably not necessary? LINK_FLAGS "--bind -s ALLOW_MEMORY_GROWTH=1 -O3 -s ASSERTIONS=0 -s INITIAL_MEMORY=299958272 -s STACK_SIZE=262144 -s MALLOC=emmalloc -s MODULARIZE=1 -s EXPORT_NAME=BASIS") endif() 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;eDisable RGBA_HALF'); } - + addButton(''); addButton(''); } - + function updateSupportedFormats() { let supportedFormats = []; @@ -1096,7 +1096,7 @@ console.log('bc6hSupported: ' + bc6hSupported); console.log('astcHDRSupported: ' + astcHDRSupported); console.log('rgbaHalfSupported: ' + rgbaHalfSupported); - + updateSupportedFormats(); updateDisableButtons(); } @@ -1112,16 +1112,16 @@
This demo uses the Basis Universal C++ transcoder (compiled to WebAssembly using Emscripten) to transcode a .ktx2 file to FORMAT
It also supports encoding .PNG, .EXR or .HDR files to LDR or HDR .KTX2 files.
Thanks to Evan Parker for providing
webgl-texture-utils and this test bed. Go back. - +

Supported WebGL formats:
- +
- +
.ktx2 file: @@ -1132,7 +1132,7 @@ .png/.exr/.hdr file: - +
- +

- +

- - ETC1S LDR Options: + + ETC1S LDR Options:

ETC1S Quality: 255 - +
@@ -1199,7 +1199,7 @@
Force UASTC HDR on LDR Inputs: - +
@@ -1207,25 +1207,25 @@
Convert LDR images to linear light (UASTC HDR mode): - +

UASTC LDR Options:
- +
UASTC LDR: - +
1 - +
UASTC LDR RDO: - + 1.0 @@ -1234,7 +1234,7 @@ Other Options:

- + Use sRGB/perceptual metrics:
@@ -1292,13 +1292,13 @@ runLoadFile(); } }, false); - + elem('imagefile').addEventListener('keydown', function (e) { if (e.keyCode == 13) { runEncodeImageFile(); } }, false); - + { // Get the slider element and display element let etc1SLevelSlider = document.getElementById('etc1s-comp-level-slider'); @@ -1309,7 +1309,7 @@ etc1sLevelSliderValueDisplay.textContent = this.value; // Update the display in real-time } } - + { // Get the slider element and display element let uastcHDRSlider = document.getElementById('uastc-hdr-quality-slider'); @@ -1320,7 +1320,7 @@ qualityHDRValueDisplay.textContent = this.value; // Update the display in real-time } } - + { // Get the slider element and display element let uastcLDRSlider = document.getElementById('uastc-ldr-quality-slider'); @@ -1331,7 +1331,7 @@ qualityLDRValueDisplay.textContent = this.value; // Update the display in real-time } } - + { // Get the slider and display element let rdoSlider = document.getElementById('rdo-quality-slider'); @@ -1342,7 +1342,7 @@ rdoValueDisplay.textContent = parseFloat(this.value).toFixed(1); // Show the value as a decimal with 1 decimal place } } - + { // Get the slider and display element let etc1SQualitySlider = document.getElementById('EncodeQuality'); diff --git a/webgl/ktx2_encode_test/renderer.js b/webgl/ktx2_encode_test/renderer.js index fbeb87ef..ff64dd5e 100644 --- a/webgl/ktx2_encode_test/renderer.js +++ b/webgl/ktx2_encode_test/renderer.js @@ -294,4 +294,3 @@ Renderer.fragmentShaderSource_ = [ ' gl_FragColor = c;', '}' ].join('\n'); - diff --git a/webgl/texture_test/index.html b/webgl/texture_test/index.html index 15bf8648..bab50338 100644 --- a/webgl/texture_test/index.html +++ b/webgl/texture_test/index.html @@ -1,5 +1,5 @@ - @@ -90,7 +90,7 @@ cTFFXT1_RGB: 17, cTFPVRTC2_4_RGB: 18, cTFPVRTC2_4_RGBA: 19, - cTFETC2_EAC_R11: 20, + cTFETC2_EAC_R11: 20, cTFETC2_EAC_RG11: 21, cTFBC6H: 22, cTFASTC_HDR_4x4_RGBA: 23, @@ -107,7 +107,7 @@ DXT_FORMAT_MAP = {}; DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC1] = COMPRESSED_RGB_S3TC_DXT1_EXT; DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC3] = COMPRESSED_RGBA_S3TC_DXT5_EXT; -DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC7] = COMPRESSED_RGBA_BPTC_UNORM; +DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC7] = COMPRESSED_RGBA_BPTC_UNORM; var astcSupported = false; var etcSupported = false; @@ -138,7 +138,7 @@ { var basisFileDesc = basisFile.getFileDesc(); - log('------'); + log('------'); log('getFileDesc():'); log('version: ' + basisFileDesc.version); log('us per frame: ' + basisFileDesc.usPerFrame); @@ -146,7 +146,7 @@ log('userdata0: ' + basisFileDesc.userdata0 + ' userdata1: ' + basisFileDesc.userdata1); log('texFormat: ' + basisFileDesc.texFormat); log('yFlipped: ' + basisFileDesc.yFlipped + ' hasAlphaSlices: ' + basisFileDesc.hasAlphaSlices); - + if (basisFileDesc.texFormat == Module.basis_tex_format.cETC1S.value) { log('numEndpoints: ' + basisFileDesc.numEndpoints); @@ -164,9 +164,9 @@ for (image_index = 0; image_index < basisFileDesc.totalImages; image_index++) { log('image: ' + image_index); - + var basisImageDesc = basisFile.getImageDesc(image_index); - + log('origWidth: ' + basisImageDesc.origWidth + ' origWidth: ' + basisImageDesc.origHeight); log('numBlocksX: ' + basisImageDesc.numBlocksX + ' origWidth: ' + basisImageDesc.numBlocksY); log('numLevels: ' + basisImageDesc.numLevels); @@ -177,15 +177,15 @@ for (level_index = 0; level_index < basisImageDesc.numLevels; level_index++) { var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); - - log('level: ' + level_index + + + log('level: ' + level_index + ' rgb_file_offset: ' + basisImageLevelDesc.rgbFileOfs + ' rgb_file_len: ' + basisImageLevelDesc.rgbFileLen); - if (basisFileDesc.hasAlphaSlices) + if (basisFileDesc.hasAlphaSlices) log('alpha_file_offset: ' + basisImageLevelDesc.alphaFileOfs + ' alpha_file_len: ' + basisImageLevelDesc.alphaFileLen); } } - + log('------'); } @@ -194,13 +194,13 @@ log('Done loading .basis file, decoded header:'); const { BasisFile, initializeBasis } = Module; - + drawMode = 0; drawScale = 1.0; linearToSRGBFlag = false; elem('scale-slider').value = 1.0; elem('scale-value').textContent = 1; - + initializeBasis(); const startTime = performance.now(); @@ -213,20 +213,20 @@ levels = basisFile.getNumLevels(0); has_alpha = basisFile.getHasAlpha(); is_hdr = basisFile.isHDR(); - + log('isHDR: ' + is_hdr); - + dumpBasisFileDesc(basisFile); - + if (!width || !height || !images || !levels) { console.warn('Invalid .basis file'); basisFile.close(); basisFile.delete(); return; } - + // Note: If the file is UASTC LDR, the preferred formats are ASTC/BC7. For UASTC HDR, ASTC/BC6H. - // If the file is ETC1S and doesn't have alpha, the preferred formats are ETC1 and BC1. For alpha, the preferred formats are ETC2, BC3 or BC7. + // If the file is ETC1S and doesn't have alpha, the preferred formats are ETC1 and BC1. For alpha, the preferred formats are ETC2, BC3 or BC7. var formatString = 'UNKNOWN'; if (is_hdr) @@ -250,7 +250,7 @@ { formatString = '32-bit RGBA'; format = BASIS_FORMAT.cTFRGBA_HALF; - + log('Decoding .basis data to 32-bit RGBA'); } } @@ -289,7 +289,7 @@ formatString = 'PVRTC1_RGB'; format = BASIS_FORMAT.cTFPVRTC1_4_RGB; } - + if ( ((width & (width - 1)) != 0) || ((height & (height - 1)) != 0) ) @@ -298,7 +298,7 @@ } if (width != height) { - log('ERROR: PVRTC1 requires square power of 2 textures'); + log('ERROR: PVRTC1 requires square power of 2 textures'); } } else if (etcSupported) @@ -314,7 +314,7 @@ } elem('format').innerText = formatString; - + log('format: ' + format); if (!basisFile.startTranscoding()) { @@ -324,26 +324,26 @@ basisFile.delete(); return; } - + const isUncompressedFormat = Module.formatIsUncompressed(format); - + const blockWidth = isUncompressedFormat ? 1 : 4, blockHeight = isUncompressedFormat ? 1 : 4; - + const bytesPerBlockOrPixel = Module.getBytesPerBlockOrPixel(format); log('isUncompressedFormat: ' + isUncompressedFormat + ' bytesPerBlockOrPixel: ' + bytesPerBlockOrPixel); - + const dstSize = basisFile.getImageTranscodedSizeInBytes(0, 0, format); const dst = new Uint8Array(dstSize); - + // log('getImageTranscodedSizeInBytes() returned ' + dstSize); - // Use the low or high level transcoding API's. The high level API's require .basis files, while the low-level API's just work off blobs of memory and parameters. + // Use the low or high level transcoding API's. The high level API's require .basis files, while the low-level API's just work off blobs of memory and parameters. if (elem('ContainerIndependentTranscoding').checked) { // Always transcode the first image and the first mipmap level const image_index = 0; const level_index = 0; - + // Get the .basis file description var basisFileDesc = basisFile.getFileDesc(); @@ -352,7 +352,7 @@ // Get the description of this image's mipmap level var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); - + var status = false; // If we're transcoding to ETC1S, use the LowLevelETC1SImageTranscoder class. Otherwise use the transcodeUASTCImage() function. @@ -366,7 +366,7 @@ var endpointPalette = new Uint8Array(data, basisFileDesc.endpointPaletteOfs, basisFileDesc.endpointPaletteLen); var tables = new Uint8Array(data, basisFileDesc.tablesOfs, basisFileDesc.tablesLen); - // Create a Uint8Array pointing to the image's compressed data. + // Create a Uint8Array pointing to the image's compressed data. // If it's an opaque .basis file, there will only be RGB data. For transparant .basis files, each RGB slice will be immediately followed by an alpha slice. // Compressed ETC1S alpha data is guaranteed to immediately follow the RGB data (it's always at odd slices in the .basis file). var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen + basisImageLevelDesc.alphaFileLen); @@ -391,7 +391,7 @@ basisFileDesc.isVideo, 0, 0); - + if (!status) log('transcodeImage() failed'); } @@ -404,9 +404,9 @@ { log('decodePalettes() failed'); } - + etc1s_transcoder.delete(); - + if (!status) { log('etc1s_transcoder failed'); @@ -422,7 +422,7 @@ } else { - // Create a Uint8Array pointing to the image's compressed data. + // Create a Uint8Array pointing to the image's compressed data. var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen); // Transcode the UASTC texture data to the desired output format. @@ -431,14 +431,14 @@ dst, dstSize / bytesPerBlockOrPixel, compData, basisImageDesc.numBlocksX, basisImageDesc.numBlocksY, basisImageDesc.origWidth, basisImageDesc.origHeight, level_index, - 0, basisImageLevelDesc.rgbFileLen, + 0, basisImageLevelDesc.rgbFileLen, 0, basisFileDesc.hasAlphaSlices, basisFileDesc.isVideo, 0, 0, -1, -1); - + if (!status) { log('transcodeUASTCImage() failed'); @@ -455,13 +455,13 @@ } else { - // Use the high-level transcode API, which requires a .basis file. + // Use the high-level transcode API, which requires a .basis file. if (!basisFile.transcodeImage(dst, 0, 0, format, 0, 0)) { log('basisFile.transcodeImage failed'); console.warn('transcodeImage failed'); basisFile.close(); basisFile.delete(); - + return; } } @@ -480,7 +480,7 @@ alignedWidth = (width + 3) & ~3; alignedHeight = (height + 3) & ~3; - + displayWidth = alignedWidth; displayHeight = alignedHeight; @@ -518,25 +518,25 @@ canvas.width = width; canvas.height = height; displayWidth = width; - displayHeight = height; - + displayHeight = height; + if (rgbaHalfSupported) { var numHalfs = dstSize / 2; - + // Create uint16 data from the uint8 data. var dstHalfs = new Uint16Array(numHalfs); - + // Convert the array of bytes to an array of uint16's. for (var i = 0; i < numHalfs; i++) dstHalfs[i] = dst[2 * i + 0] | (dst[2 * i + 1] << 8); - + tex = renderer.createHalfRGBATexture(dstHalfs, width, height, halfFloatWebGLFormat); } else { // No HDR texture formats are supported (TODO: 9e5?) Fall back to plain 32bpp RGBA, just to do *something*. (Could also convert to RGBM.) - const dstRGBA = new Uint8Array(width * height * 4); + const dstRGBA = new Uint8Array(width * height * 4); // Convert the array of half floats to uint8_t's, clamping as needed. var srcOfs = 0, dstOfs = 0; @@ -548,7 +548,7 @@ { var h = dst[srcOfs] | (dst[srcOfs + 1] << 8); var f = Module.convertHalfToFloat(h); - + dstRGBA[dstOfs] = Math.min(255, Math.max(0, Math.round(f * 255.0))); srcOfs += 2; @@ -556,8 +556,8 @@ } } } - - tex = renderer.createRgbaTexture(dstRGBA, width, height); + + tex = renderer.createRgbaTexture(dstRGBA, width, height); } } else @@ -567,7 +567,7 @@ displayWidth = width; displayHeight = height; - // Create 565 texture. + // Create 565 texture. var dstTex = new Uint16Array(width * height); // Convert the array of bytes to an array of uint16's. @@ -593,7 +593,7 @@ function viewAlpha() { drawMode = 2; redraw(); } function linearToSRGB() { linearToSRGBFlag = !linearToSRGBFlag; redraw(); } -function updateScale(value) +function updateScale(value) { document.getElementById('scale-value').textContent = value; drawScale = value; @@ -607,7 +607,7 @@ dxtSupported = !!gl.getExtension('WEBGL_compressed_texture_s3tc'); pvrtcSupported = !!(gl.getExtension('WEBGL_compressed_texture_pvrtc')) || !!(gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc')); bc7Supported = !!gl.getExtension('EXT_texture_compression_bptc'); - + // Check for BC6H support { var ext = gl.getExtension('EXT_texture_compression_bptc'); @@ -616,7 +616,7 @@ } } - // Check for ASTC HDR support + // Check for ASTC HDR support { var ext = gl.getExtension('WEBGL_compressed_texture_astc'); @@ -631,7 +631,7 @@ } } - // Check for half-float texture support. + // Check for half-float texture support. { var ext = gl.getExtension('OES_texture_half_float'); if (ext) @@ -640,7 +640,7 @@ halfFloatWebGLFormat = ext.HALF_FLOAT_OES; } } - + // HACK HACK - for testing uncompressed //astcSupported = false; //etcSupported = false; @@ -650,7 +650,7 @@ //bc6hSupported = false; //astcHDRSupported = false; //rgbaHalfSupported = false; - + console.log('astcSupported: ' + astcSupported); console.log('etcSupported: ' + etcSupported); console.log('dxtSupported: ' + dxtSupported); @@ -684,11 +684,11 @@
- + 1 - +

Use Container Independent Transcoding API's: @@ -697,16 +697,16 @@
- +