Ai_Assistant/client/node_modules/@pixiv/three-vrm-materials-mtoon/lib/three-vrm-materials-mtoon.module.js

839 lines
174 KiB
JavaScript
Raw Permalink Normal View History

2026-05-24 13:31:30 +02:00
/*!
* @pixiv/three-vrm-materials-mtoon v3.4.1
* MToon (toon material) module for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-materials-mtoon is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/MToonMaterialLoaderPlugin.ts
import * as THREE5 from "three";
// src/GLTFMToonMaterialParamsAssignHelper.ts
import * as THREE2 from "three";
// src/utils/setTextureColorSpace.ts
import * as THREE from "three";
var colorSpaceEncodingMap = {
// eslint-disable-next-line @typescript-eslint/naming-convention
"": 3e3,
srgb: 3001
};
function setTextureColorSpace(texture, colorSpace) {
if (parseInt(THREE.REVISION, 10) >= 152) {
texture.colorSpace = colorSpace;
} else {
texture.encoding = colorSpaceEncodingMap[colorSpace];
}
}
// src/GLTFMToonMaterialParamsAssignHelper.ts
var GLTFMToonMaterialParamsAssignHelper = class {
get pending() {
return Promise.all(this._pendings);
}
constructor(parser, materialParams) {
this._parser = parser;
this._materialParams = materialParams;
this._pendings = [];
}
assignPrimitive(key, value) {
if (value != null) {
this._materialParams[key] = value;
}
}
assignColor(key, value, convertSRGBToLinear) {
if (value != null) {
this._materialParams[key] = new THREE2.Color().fromArray(value);
if (convertSRGBToLinear) {
this._materialParams[key].convertSRGBToLinear();
}
}
}
assignTexture(key, texture, isColorTexture) {
return __async(this, null, function* () {
const promise = (() => __async(this, null, function* () {
if (texture != null) {
yield this._parser.assignTexture(this._materialParams, key, texture);
if (isColorTexture) {
setTextureColorSpace(this._materialParams[key], "srgb");
}
}
}))();
this._pendings.push(promise);
return promise;
});
}
assignTextureByIndex(key, textureIndex, isColorTexture) {
return __async(this, null, function* () {
return this.assignTexture(key, textureIndex != null ? { index: textureIndex } : void 0, isColorTexture);
});
}
};
// src/MToonMaterial.ts
import * as THREE4 from "three";
// src/shaders/mtoon.vert
var mtoon_default = "// #define PHONG\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n varying vec3 vNormal;\n#endif\n\n#include <common>\n\n// #include <uv_pars_vertex>\n#ifdef MTOON_USE_UV\n varying vec2 vUv;\n\n // COMPAT: pre-r151 uses a common uvTransform\n #if THREE_VRM_THREE_REVISION < 151\n uniform mat3 uvTransform;\n #endif\n#endif\n\n// #include <uv2_pars_vertex>\n// COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n#if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n attribute vec2 uv2;\n varying vec2 vUv2;\n uniform mat3 uv2Transform;\n #endif\n#endif\n\n// #include <displacementmap_pars_vertex>\n// #include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n\n#ifdef USE_OUTLINEWIDTHMULTIPLYTEXTURE\n uniform sampler2D outlineWidthMultiplyTexture;\n uniform mat3 outlineWidthMultiplyTextureUvTransform;\n#endif\n\nuniform float outlineWidthFactor;\n\nvoid main() {\n\n // #include <uv_vertex>\n #ifdef MTOON_USE_UV\n // COMPAT: pre-r151 uses a common uvTransform\n #if THREE_VRM_THREE_REVISION >= 151\n vUv = uv;\n #else\n vUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n #endif\n #endif\n\n // #include <uv2_vertex>\n // COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n #if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n vUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n #endif\n #endif\n\n #include <color_vertex>\n\n #include <beginnormal_vertex>\n #include <morphnormal_vertex>\n #include <skinbase_vertex>\n #include <skinnormal_vertex>\n\n // we need this to compute the outline properly\n objectNormal = normalize( objectNormal );\n\n #include <defaultnormal_vertex>\n\n #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\n vNormal = normalize( transformedNormal );\n #endif\n\n #include <begin_vertex>\n\n #include <morphtarget_vertex>\n #include <skinning_vertex>\n // #include <displacementmap_vertex>\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n\n vViewPosition = - mvPosition.xyz;\n\n #ifdef OUTLINE\n float worldNormalLength = length( transformedNormal );\n vec3 outlineOffset = outlineWidthFactor * worldNormalLength * objectNormal;\n\n #ifdef USE_OUTLINEWIDTHMULTIPLYTEXTURE\n vec2 outlineWidthMultiplyTextureUv = ( outlineWidthMultiplyTextureUvTransform * vec3( vUv, 1 ) ).xy;\n float outlineTex = texture2D( outlineWidthMultiplyTexture, outlineWidthMultiplyTextureUv ).g;\n outlineOffset *= outlineTex;\n #endif\n\n #ifdef OUTLINE_WIDTH_SCREEN\n outlineOffset *= vViewPosition.z / projectionMatrix[ 1 ].y;\n #endif\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( outlineOffset + transformed, 1.0 );\n\n gl_Position.z += 1E-6 * gl_Position.w; // anti-artifact magic\n #endif\n\n #include <worldpos_vertex>\n // #include <envmap_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n\n}";
// src/shaders/mtoon.frag
var mtoon_default2 = "// #define PHONG\n\nuniform vec3 litFactor;\n\nuniform float opacity;\n\nuniform vec3 shadeColorFactor;\n#ifdef USE_SHADEMULTIPLYTEXTURE\n uniform sampler2D shadeMultiplyTexture;\n uniform mat3 shadeMultiplyTextureUvTransform;\n#endif\n\nuniform float shadingShiftFactor;\nuniform float shadingToonyFactor;\n\n#ifdef USE_SHADINGSHIFTTEXTURE\n uniform sampler2D shadingShiftTexture;\n uniform mat3 shadingShiftTextureUvTransform;\n uniform float shadingShiftTextureScale;\n#endif\n\nuniform float giEqualizationFactor;\n\nuniform vec3 parametricRimColorFactor;\n#ifdef USE_RIMMULTIPLYTEXTURE\n uniform sampler2D rimMultiplyTexture;\n uniform mat3 rimMultiplyTextureUvTransform;\n#endif\nuniform float rimLightingMixFactor;\nuniform float parametricRimFresnelPowerFactor;\nuniform float parametricRimLiftFactor;\n\n#ifdef USE_MATCAPTEXTURE\n uniform vec3 matcapFactor;\n uniform sampler2D matcapTexture;\n uniform mat3 matcapTextureUvTransform;\n#endif\n\nuniform vec3 emissive;\nuniform float emissiveIntensity;\n\nuniform vec3 outlineColorFactor;\nuniform float outlineLightingMixFactor;\n\n#ifdef USE_UVANIMATIONMASKTEXTURE\n uniform sampler2D uvAnimationMaskTexture;\n uniform mat3 uvAnimationMaskTextureUvTransform;\n#endif\n\nuniform float uvAnimationScrollXOffset;\nuniform float uvAnimationScrollYOffset;\nuniform float uvAnimationRotationPhase;\n\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n\n// #include <uv_pars_fragment>\n#if ( defined( MTOON_USE_UV ) && !defined( MTOON_UVS_VERTEX_ONLY ) )\n varying vec2 vUv;\n#endif\n\n// #include <uv2_pars_fragment>\n// COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n#if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n varying vec2 vUv2;\n #endif\n#endif\n\n#include <map_pars_fragment>\n\n#ifdef USE_MAP\n uniform mat3 mapUvTransform;\n#endif\n\n// #include <alphamap_pars_fragment>\n\n#include <alphatest_pars_fragment>\n\n#include <aomap_pars_fragment>\n// #include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n\n#ifdef USE_EMISSIVEMAP\n uniform mat3 emissiveMapUvTransform;\n#endif\n\n// #include <envmap_common_pars_fragment>\n// #include <envmap_pars_fragment>\n// #include <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n\n// #include <bsdfs>\n// COMPAT: pre-r151 doesn't have BRDF_Lambert in <common>\n#if THREE_VRM_THREE_REVISION < 151\n vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n return RECIPROCAL_PI * diffuseColor;\n }\n#endif\n\n#include <lights_pars_begin>\n\n#include <normal_pars_fragment>\n\n// #include <lights_phong_pars_fragment>\nvarying vec3 vViewPosition;\n\nstruct MToonMaterial {\n vec3 diffuseColor;\n vec3 shadeColor;\n float shadingShift;\n};\n\nfloat linearstep( float a, float b, float t ) {\n return clamp( ( t - a ) / ( b - a ), 0.0, 1.0 );\n}\n\n/**\n * Convert NdotL into toon shading factor using shadingShift and shadingToony\n */\nfloat getShading(\n const in float dotNL,\n const in float shadow,\n const in float shadingShift\n) {\n float shading = dotNL;\n shading = shading + shadingShift;\n shading = linearstep( -1.0 + shadingToonyFactor, 1.0 - shadingToonyFactor, shading );\n shading *= shadow;\n return shading;\n}\n\n/**\n * Mix diffuseColor and shadeColor using shading factor and light color\n */\nvec3 getDiffuse(\n const in MToonMaterial material,\n const in float shading,\n in vec3 lightColor\n) {\n #ifdef DEBUG_LITSHADERATE\n return vec3( BRDF_Lambert( shading * lightColor ) );\n #endif\n\n vec3 col = lightColor * BRDF_Lambert( mix( material.shadeColor, material.diffuseColor, shading ) );\n\n // The \"comment out if you want to PBR absolutely\" line\n #ifdef V0_COMPAT_SHADE\n col = min( col, material.diffuseColor );\n #endif\n\n return col;\n}\n\n// COMPAT: pre-r156 uses a struct GeometricContext\n#if THREE_VRM_THREE_REVISION >= 157\n void RE_Direct_MToon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const
// src/MToonMaterialDebugMode.ts
var MToonMaterialDebugMode = {
/**
* Render normally.
*/
None: "none",
/**
* Visualize normals of the surface.
*/
Normal: "normal",
/**
* Visualize lit/shade of the surface.
*/
LitShadeRate: "litShadeRate",
/**
* Visualize UV of the surface.
*/
UV: "uv"
};
// src/MToonMaterialOutlineWidthMode.ts
var MToonMaterialOutlineWidthMode = {
None: "none",
WorldCoordinates: "worldCoordinates",
ScreenCoordinates: "screenCoordinates"
};
// src/utils/getTextureColorSpace.ts
import * as THREE3 from "three";
var encodingColorSpaceMap = {
// eslint-disable-next-line @typescript-eslint/naming-convention
3e3: "",
// eslint-disable-next-line @typescript-eslint/naming-convention
3001: "srgb"
};
function getTextureColorSpace(texture) {
if (parseInt(THREE3.REVISION, 10) >= 152) {
return texture.colorSpace;
} else {
return encodingColorSpaceMap[texture.encoding];
}
}
// src/MToonMaterial.ts
var MToonMaterial = class extends THREE4.ShaderMaterial {
constructor(parameters = {}) {
var _a;
super({ vertexShader: mtoon_default, fragmentShader: mtoon_default2 });
this.uvAnimationScrollXSpeedFactor = 0;
this.uvAnimationScrollYSpeedFactor = 0;
this.uvAnimationRotationSpeedFactor = 0;
/**
* Whether the material is affected by fog.
* `true` by default.
*/
this.fog = true;
/**
* Will be read in WebGLPrograms
*
* See: https://github.com/mrdoob/three.js/blob/4f5236ac3d6f41d904aa58401b40554e8fbdcb15/src/renderers/webgl/WebGLPrograms.js#L190-L191
*/
this.normalMapType = THREE4.TangentSpaceNormalMap;
/**
* When this is `true`, vertex colors will be ignored.
* `true` by default.
*/
this._ignoreVertexColor = true;
this._v0CompatShade = false;
this._debugMode = MToonMaterialDebugMode.None;
this._outlineWidthMode = MToonMaterialOutlineWidthMode.None;
this._isOutline = false;
if (parameters.transparentWithZWrite) {
parameters.depthWrite = true;
}
delete parameters.transparentWithZWrite;
parameters.fog = true;
parameters.lights = true;
parameters.clipping = true;
this.uniforms = THREE4.UniformsUtils.merge([
THREE4.UniformsLib.common,
// map
THREE4.UniformsLib.normalmap,
// normalMap
THREE4.UniformsLib.emissivemap,
// emissiveMap
THREE4.UniformsLib.fog,
THREE4.UniformsLib.lights,
{
litFactor: { value: new THREE4.Color(1, 1, 1) },
mapUvTransform: { value: new THREE4.Matrix3() },
colorAlpha: { value: 1 },
normalMapUvTransform: { value: new THREE4.Matrix3() },
shadeColorFactor: { value: new THREE4.Color(0, 0, 0) },
shadeMultiplyTexture: { value: null },
shadeMultiplyTextureUvTransform: { value: new THREE4.Matrix3() },
shadingShiftFactor: { value: 0 },
shadingShiftTexture: { value: null },
shadingShiftTextureUvTransform: { value: new THREE4.Matrix3() },
shadingShiftTextureScale: { value: 1 },
shadingToonyFactor: { value: 0.9 },
giEqualizationFactor: { value: 0.9 },
matcapFactor: { value: new THREE4.Color(1, 1, 1) },
matcapTexture: { value: null },
matcapTextureUvTransform: { value: new THREE4.Matrix3() },
parametricRimColorFactor: { value: new THREE4.Color(0, 0, 0) },
rimMultiplyTexture: { value: null },
rimMultiplyTextureUvTransform: { value: new THREE4.Matrix3() },
rimLightingMixFactor: { value: 1 },
parametricRimFresnelPowerFactor: { value: 5 },
parametricRimLiftFactor: { value: 0 },
emissive: { value: new THREE4.Color(0, 0, 0) },
emissiveIntensity: { value: 1 },
emissiveMapUvTransform: { value: new THREE4.Matrix3() },
outlineWidthMultiplyTexture: { value: null },
outlineWidthMultiplyTextureUvTransform: { value: new THREE4.Matrix3() },
outlineWidthFactor: { value: 0 },
outlineColorFactor: { value: new THREE4.Color(0, 0, 0) },
outlineLightingMixFactor: { value: 1 },
uvAnimationMaskTexture: { value: null },
uvAnimationMaskTextureUvTransform: { value: new THREE4.Matrix3() },
uvAnimationScrollXOffset: { value: 0 },
uvAnimationScrollYOffset: { value: 0 },
uvAnimationRotationPhase: { value: 0 }
},
(_a = parameters.uniforms) != null ? _a : {}
]);
this.setValues(parameters);
this._uploadUniformsWorkaround();
this.customProgramCacheKey = () => [
...Object.entries(this._generateDefines()).map(([token, macro]) => `${token}:${macro}`),
this.matcapTexture ? `matcapTextureColorSpace:${getTextureColorSpace(this.matcapTexture)}` : "",
this.shadeMultiplyTexture ? `shadeMultiplyTextureColorSpace:${getTextureColorSpace(this.shadeMultiplyTexture)}` : "",
this.rimMultiplyTexture ? `rimMultiplyTextureColorSpace:${getTextureColorSpace(this.rimMultiplyTexture)}` : ""
].join(",");
this.onBeforeCompile = (shader) => {
const threeRevision = parseInt(THREE4.REVISION, 10);
const defines = Object.entries(__spreadValues(__spreadValues({}, this._generateDefines()), this.defines)).filter(([token, macro]) => !!macro).map(([token, macro]) => `#define ${token} ${macro}`).join("\n") + "\n";
shader.vertexShader = defines + shader.vertexShader;
shader.fragmentShader = defines + shader.fragmentShader;
if (threeRevision < 154) {
shader.fragmentShader = shader.fragmentShader.replace(
"#include <colorspace_fragment>",
"#include <encodings_fragment>"
);
}
};
}
get color() {
return this.uniforms.litFactor.value;
}
set color(value) {
this.uniforms.litFactor.value = value;
}
get map() {
return this.uniforms.map.value;
}
set map(value) {
this.uniforms.map.value = value;
}
get normalMap() {
return this.uniforms.normalMap.value;
}
set normalMap(value) {
this.uniforms.normalMap.value = value;
}
get normalScale() {
return this.uniforms.normalScale.value;
}
set normalScale(value) {
this.uniforms.normalScale.value = value;
}
get emissive() {
return this.uniforms.emissive.value;
}
set emissive(value) {
this.uniforms.emissive.value = value;
}
get emissiveIntensity() {
return this.uniforms.emissiveIntensity.value;
}
set emissiveIntensity(value) {
this.uniforms.emissiveIntensity.value = value;
}
get emissiveMap() {
return this.uniforms.emissiveMap.value;
}
set emissiveMap(value) {
this.uniforms.emissiveMap.value = value;
}
get shadeColorFactor() {
return this.uniforms.shadeColorFactor.value;
}
set shadeColorFactor(value) {
this.uniforms.shadeColorFactor.value = value;
}
get shadeMultiplyTexture() {
return this.uniforms.shadeMultiplyTexture.value;
}
set shadeMultiplyTexture(value) {
this.uniforms.shadeMultiplyTexture.value = value;
}
get shadingShiftFactor() {
return this.uniforms.shadingShiftFactor.value;
}
set shadingShiftFactor(value) {
this.uniforms.shadingShiftFactor.value = value;
}
get shadingShiftTexture() {
return this.uniforms.shadingShiftTexture.value;
}
set shadingShiftTexture(value) {
this.uniforms.shadingShiftTexture.value = value;
}
get shadingShiftTextureScale() {
return this.uniforms.shadingShiftTextureScale.value;
}
set shadingShiftTextureScale(value) {
this.uniforms.shadingShiftTextureScale.value = value;
}
get shadingToonyFactor() {
return this.uniforms.shadingToonyFactor.value;
}
set shadingToonyFactor(value) {
this.uniforms.shadingToonyFactor.value = value;
}
get giEqualizationFactor() {
return this.uniforms.giEqualizationFactor.value;
}
set giEqualizationFactor(value) {
this.uniforms.giEqualizationFactor.value = value;
}
get matcapFactor() {
return this.uniforms.matcapFactor.value;
}
set matcapFactor(value) {
this.uniforms.matcapFactor.value = value;
}
get matcapTexture() {
return this.uniforms.matcapTexture.value;
}
set matcapTexture(value) {
this.uniforms.matcapTexture.value = value;
}
get parametricRimColorFactor() {
return this.uniforms.parametricRimColorFactor.value;
}
set parametricRimColorFactor(value) {
this.uniforms.parametricRimColorFactor.value = value;
}
get rimMultiplyTexture() {
return this.uniforms.rimMultiplyTexture.value;
}
set rimMultiplyTexture(value) {
this.uniforms.rimMultiplyTexture.value = value;
}
get rimLightingMixFactor() {
return this.uniforms.rimLightingMixFactor.value;
}
set rimLightingMixFactor(value) {
this.uniforms.rimLightingMixFactor.value = value;
}
get parametricRimFresnelPowerFactor() {
return this.uniforms.parametricRimFresnelPowerFactor.value;
}
set parametricRimFresnelPowerFactor(value) {
this.uniforms.parametricRimFresnelPowerFactor.value = value;
}
get parametricRimLiftFactor() {
return this.uniforms.parametricRimLiftFactor.value;
}
set parametricRimLiftFactor(value) {
this.uniforms.parametricRimLiftFactor.value = value;
}
get outlineWidthMultiplyTexture() {
return this.uniforms.outlineWidthMultiplyTexture.value;
}
set outlineWidthMultiplyTexture(value) {
this.uniforms.outlineWidthMultiplyTexture.value = value;
}
get outlineWidthFactor() {
return this.uniforms.outlineWidthFactor.value;
}
set outlineWidthFactor(value) {
this.uniforms.outlineWidthFactor.value = value;
}
get outlineColorFactor() {
return this.uniforms.outlineColorFactor.value;
}
set outlineColorFactor(value) {
this.uniforms.outlineColorFactor.value = value;
}
get outlineLightingMixFactor() {
return this.uniforms.outlineLightingMixFactor.value;
}
set outlineLightingMixFactor(value) {
this.uniforms.outlineLightingMixFactor.value = value;
}
get uvAnimationMaskTexture() {
return this.uniforms.uvAnimationMaskTexture.value;
}
set uvAnimationMaskTexture(value) {
this.uniforms.uvAnimationMaskTexture.value = value;
}
get uvAnimationScrollXOffset() {
return this.uniforms.uvAnimationScrollXOffset.value;
}
set uvAnimationScrollXOffset(value) {
this.uniforms.uvAnimationScrollXOffset.value = value;
}
get uvAnimationScrollYOffset() {
return this.uniforms.uvAnimationScrollYOffset.value;
}
set uvAnimationScrollYOffset(value) {
this.uniforms.uvAnimationScrollYOffset.value = value;
}
get uvAnimationRotationPhase() {
return this.uniforms.uvAnimationRotationPhase.value;
}
set uvAnimationRotationPhase(value) {
this.uniforms.uvAnimationRotationPhase.value = value;
}
/**
* When this is `true`, vertex colors will be ignored.
* `true` by default.
*/
get ignoreVertexColor() {
return this._ignoreVertexColor;
}
set ignoreVertexColor(value) {
this._ignoreVertexColor = value;
this.needsUpdate = true;
}
/**
* There is a line of the shader called "comment out if you want to PBR absolutely" in VRM0.0 MToon.
* When this is true, the material enables the line to make it compatible with the legacy rendering of VRM.
* Usually not recommended to turn this on.
* `false` by default.
*/
get v0CompatShade() {
return this._v0CompatShade;
}
/**
* There is a line of the shader called "comment out if you want to PBR absolutely" in VRM0.0 MToon.
* When this is true, the material enables the line to make it compatible with the legacy rendering of VRM.
* Usually not recommended to turn this on.
* `false` by default.
*/
set v0CompatShade(v) {
this._v0CompatShade = v;
this.needsUpdate = true;
}
/**
* Debug mode for the material.
* You can visualize several components for diagnosis using debug mode.
*
* See: {@link MToonMaterialDebugMode}
*/
get debugMode() {
return this._debugMode;
}
/**
* Debug mode for the material.
* You can visualize several components for diagnosis using debug mode.
*
* See: {@link MToonMaterialDebugMode}
*/
set debugMode(m) {
this._debugMode = m;
this.needsUpdate = true;
}
get outlineWidthMode() {
return this._outlineWidthMode;
}
set outlineWidthMode(m) {
this._outlineWidthMode = m;
this.needsUpdate = true;
}
get isOutline() {
return this._isOutline;
}
set isOutline(b) {
this._isOutline = b;
this.needsUpdate = true;
}
/**
* Readonly boolean that indicates this is a {@link MToonMaterial}.
*/
get isMToonMaterial() {
return true;
}
/**
* Update this material.
*
* @param delta deltaTime since last update
*/
update(delta) {
this._uploadUniformsWorkaround();
this._updateUVAnimation(delta);
}
copy(source) {
super.copy(source);
this.map = source.map;
this.normalMap = source.normalMap;
this.emissiveMap = source.emissiveMap;
this.shadeMultiplyTexture = source.shadeMultiplyTexture;
this.shadingShiftTexture = source.shadingShiftTexture;
this.matcapTexture = source.matcapTexture;
this.rimMultiplyTexture = source.rimMultiplyTexture;
this.outlineWidthMultiplyTexture = source.outlineWidthMultiplyTexture;
this.uvAnimationMaskTexture = source.uvAnimationMaskTexture;
this.normalMapType = source.normalMapType;
this.uvAnimationScrollXSpeedFactor = source.uvAnimationScrollXSpeedFactor;
this.uvAnimationScrollYSpeedFactor = source.uvAnimationScrollYSpeedFactor;
this.uvAnimationRotationSpeedFactor = source.uvAnimationRotationSpeedFactor;
this.ignoreVertexColor = source.ignoreVertexColor;
this.v0CompatShade = source.v0CompatShade;
this.debugMode = source.debugMode;
this.outlineWidthMode = source.outlineWidthMode;
this.isOutline = source.isOutline;
this.needsUpdate = true;
return this;
}
/**
* Update UV animation state.
* Intended to be called via {@link update}.
* @param delta deltaTime
*/
_updateUVAnimation(delta) {
this.uniforms.uvAnimationScrollXOffset.value += delta * this.uvAnimationScrollXSpeedFactor;
this.uniforms.uvAnimationScrollYOffset.value += delta * this.uvAnimationScrollYSpeedFactor;
this.uniforms.uvAnimationRotationPhase.value += delta * this.uvAnimationRotationSpeedFactor;
this.uniforms.alphaTest.value = this.alphaTest;
this.uniformsNeedUpdate = true;
}
/**
* Upload uniforms that need to upload but doesn't automatically because of reasons.
* Intended to be called via {@link constructor} and {@link update}.
*/
_uploadUniformsWorkaround() {
this.uniforms.opacity.value = this.opacity;
this._updateTextureMatrix(this.uniforms.map, this.uniforms.mapUvTransform);
this._updateTextureMatrix(this.uniforms.normalMap, this.uniforms.normalMapUvTransform);
this._updateTextureMatrix(this.uniforms.emissiveMap, this.uniforms.emissiveMapUvTransform);
this._updateTextureMatrix(this.uniforms.shadeMultiplyTexture, this.uniforms.shadeMultiplyTextureUvTransform);
this._updateTextureMatrix(this.uniforms.shadingShiftTexture, this.uniforms.shadingShiftTextureUvTransform);
this._updateTextureMatrix(this.uniforms.matcapTexture, this.uniforms.matcapTextureUvTransform);
this._updateTextureMatrix(this.uniforms.rimMultiplyTexture, this.uniforms.rimMultiplyTextureUvTransform);
this._updateTextureMatrix(
this.uniforms.outlineWidthMultiplyTexture,
this.uniforms.outlineWidthMultiplyTextureUvTransform
);
this._updateTextureMatrix(this.uniforms.uvAnimationMaskTexture, this.uniforms.uvAnimationMaskTextureUvTransform);
this.uniformsNeedUpdate = true;
}
/**
* Returns a map object of preprocessor token and macro of the shader program.
*/
_generateDefines() {
const threeRevision = parseInt(THREE4.REVISION, 10);
const useUvInVert = this.outlineWidthMultiplyTexture !== null;
const useUvInFrag = this.map !== null || this.normalMap !== null || this.emissiveMap !== null || this.shadeMultiplyTexture !== null || this.shadingShiftTexture !== null || this.rimMultiplyTexture !== null || this.uvAnimationMaskTexture !== null;
return {
// Temporary compat against shader change @ Three.js r126
// See: #21205, #21307, #21299
THREE_VRM_THREE_REVISION: threeRevision,
OUTLINE: this._isOutline,
MTOON_USE_UV: useUvInVert || useUvInFrag,
// we can't use `USE_UV` , it will be redefined in WebGLProgram.js
MTOON_UVS_VERTEX_ONLY: useUvInVert && !useUvInFrag,
V0_COMPAT_SHADE: this._v0CompatShade,
USE_SHADEMULTIPLYTEXTURE: this.shadeMultiplyTexture !== null,
USE_SHADINGSHIFTTEXTURE: this.shadingShiftTexture !== null,
USE_MATCAPTEXTURE: this.matcapTexture !== null,
USE_RIMMULTIPLYTEXTURE: this.rimMultiplyTexture !== null,
USE_OUTLINEWIDTHMULTIPLYTEXTURE: this._isOutline && this.outlineWidthMultiplyTexture !== null,
USE_UVANIMATIONMASKTEXTURE: this.uvAnimationMaskTexture !== null,
IGNORE_VERTEX_COLOR: this._ignoreVertexColor === true,
DEBUG_NORMAL: this._debugMode === "normal",
DEBUG_LITSHADERATE: this._debugMode === "litShadeRate",
DEBUG_UV: this._debugMode === "uv",
OUTLINE_WIDTH_SCREEN: this._isOutline && this._outlineWidthMode === MToonMaterialOutlineWidthMode.ScreenCoordinates
};
}
_updateTextureMatrix(src, dst) {
if (src.value) {
if (src.value.matrixAutoUpdate) {
src.value.updateMatrix();
}
dst.value.copy(src.value.matrix);
}
}
};
// src/MToonMaterialLoaderPlugin.ts
var POSSIBLE_SPEC_VERSIONS = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var _MToonMaterialLoaderPlugin = class _MToonMaterialLoaderPlugin {
get name() {
return _MToonMaterialLoaderPlugin.EXTENSION_NAME;
}
constructor(parser, options = {}) {
var _a, _b, _c, _d;
this.parser = parser;
this.materialType = (_a = options.materialType) != null ? _a : MToonMaterial;
this.renderOrderOffset = (_b = options.renderOrderOffset) != null ? _b : 0;
this.v0CompatShade = (_c = options.v0CompatShade) != null ? _c : false;
this.debugMode = (_d = options.debugMode) != null ? _d : "none";
this._mToonMaterialSet = /* @__PURE__ */ new Set();
}
beforeRoot() {
return __async(this, null, function* () {
this._removeUnlitExtensionIfMToonExists();
});
}
afterRoot(gltf) {
return __async(this, null, function* () {
gltf.userData.vrmMToonMaterials = Array.from(this._mToonMaterialSet);
});
}
getMaterialType(materialIndex) {
const v1Extension = this._getMToonExtension(materialIndex);
if (v1Extension) {
return this.materialType;
}
return null;
}
extendMaterialParams(materialIndex, materialParams) {
const extension = this._getMToonExtension(materialIndex);
if (extension) {
return this._extendMaterialParams(extension, materialParams);
}
return null;
}
loadMesh(meshIndex) {
return __async(this, null, function* () {
var _a;
const parser = this.parser;
const json = parser.json;
const meshDef = (_a = json.meshes) == null ? void 0 : _a[meshIndex];
if (meshDef == null) {
throw new Error(
`MToonMaterialLoaderPlugin: Attempt to use meshes[${meshIndex}] of glTF but the mesh doesn't exist`
);
}
const primitivesDef = meshDef.primitives;
const meshOrGroup = yield parser.loadMesh(meshIndex);
if (primitivesDef.length === 1) {
const mesh = meshOrGroup;
const materialIndex = primitivesDef[0].material;
if (materialIndex != null) {
this._setupPrimitive(mesh, materialIndex);
}
} else {
const group = meshOrGroup;
for (let i = 0; i < primitivesDef.length; i++) {
const mesh = group.children[i];
const materialIndex = primitivesDef[i].material;
if (materialIndex != null) {
this._setupPrimitive(mesh, materialIndex);
}
}
}
return meshOrGroup;
});
}
/**
* Delete use of `KHR_materials_unlit` from its `materials` if the material is using MToon.
*
* Since GLTFLoader have so many hardcoded procedure related to `KHR_materials_unlit`
* we have to delete the extension before we start to parse the glTF.
*/
_removeUnlitExtensionIfMToonExists() {
const parser = this.parser;
const json = parser.json;
const materialDefs = json.materials;
materialDefs == null ? void 0 : materialDefs.map((materialDef, iMaterial) => {
var _a;
const extension = this._getMToonExtension(iMaterial);
if (extension && ((_a = materialDef.extensions) == null ? void 0 : _a["KHR_materials_unlit"])) {
delete materialDef.extensions["KHR_materials_unlit"];
}
});
}
_getMToonExtension(materialIndex) {
var _a, _b;
const parser = this.parser;
const json = parser.json;
const materialDef = (_a = json.materials) == null ? void 0 : _a[materialIndex];
if (materialDef == null) {
console.warn(
`MToonMaterialLoaderPlugin: Attempt to use materials[${materialIndex}] of glTF but the material doesn't exist`
);
return void 0;
}
const extension = (_b = materialDef.extensions) == null ? void 0 : _b[_MToonMaterialLoaderPlugin.EXTENSION_NAME];
if (extension == null) {
return void 0;
}
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS.has(specVersion)) {
console.warn(
`MToonMaterialLoaderPlugin: Unknown ${_MToonMaterialLoaderPlugin.EXTENSION_NAME} specVersion "${specVersion}"`
);
return void 0;
}
return extension;
}
_extendMaterialParams(extension, materialParams) {
return __async(this, null, function* () {
var _a;
delete materialParams.metalness;
delete materialParams.roughness;
const assignHelper = new GLTFMToonMaterialParamsAssignHelper(this.parser, materialParams);
assignHelper.assignPrimitive("transparentWithZWrite", extension.transparentWithZWrite);
assignHelper.assignColor("shadeColorFactor", extension.shadeColorFactor);
assignHelper.assignTexture("shadeMultiplyTexture", extension.shadeMultiplyTexture, true);
assignHelper.assignPrimitive("shadingShiftFactor", extension.shadingShiftFactor);
assignHelper.assignTexture("shadingShiftTexture", extension.shadingShiftTexture, true);
assignHelper.assignPrimitive("shadingShiftTextureScale", (_a = extension.shadingShiftTexture) == null ? void 0 : _a.scale);
assignHelper.assignPrimitive("shadingToonyFactor", extension.shadingToonyFactor);
assignHelper.assignPrimitive("giEqualizationFactor", extension.giEqualizationFactor);
assignHelper.assignColor("matcapFactor", extension.matcapFactor);
assignHelper.assignTexture("matcapTexture", extension.matcapTexture, true);
assignHelper.assignColor("parametricRimColorFactor", extension.parametricRimColorFactor);
assignHelper.assignTexture("rimMultiplyTexture", extension.rimMultiplyTexture, true);
assignHelper.assignPrimitive("rimLightingMixFactor", extension.rimLightingMixFactor);
assignHelper.assignPrimitive("parametricRimFresnelPowerFactor", extension.parametricRimFresnelPowerFactor);
assignHelper.assignPrimitive("parametricRimLiftFactor", extension.parametricRimLiftFactor);
assignHelper.assignPrimitive("outlineWidthMode", extension.outlineWidthMode);
assignHelper.assignPrimitive("outlineWidthFactor", extension.outlineWidthFactor);
assignHelper.assignTexture("outlineWidthMultiplyTexture", extension.outlineWidthMultiplyTexture, false);
assignHelper.assignColor("outlineColorFactor", extension.outlineColorFactor);
assignHelper.assignPrimitive("outlineLightingMixFactor", extension.outlineLightingMixFactor);
assignHelper.assignTexture("uvAnimationMaskTexture", extension.uvAnimationMaskTexture, false);
assignHelper.assignPrimitive("uvAnimationScrollXSpeedFactor", extension.uvAnimationScrollXSpeedFactor);
assignHelper.assignPrimitive("uvAnimationScrollYSpeedFactor", extension.uvAnimationScrollYSpeedFactor);
assignHelper.assignPrimitive("uvAnimationRotationSpeedFactor", extension.uvAnimationRotationSpeedFactor);
assignHelper.assignPrimitive("v0CompatShade", this.v0CompatShade);
assignHelper.assignPrimitive("debugMode", this.debugMode);
yield assignHelper.pending;
});
}
/**
* This will do two processes that is required to render MToon properly.
*
* - Set render order
* - Generate outline
*
* @param mesh A target GLTF primitive
* @param materialIndex The material index of the primitive
*/
_setupPrimitive(mesh, materialIndex) {
const extension = this._getMToonExtension(materialIndex);
if (extension) {
const renderOrder = this._parseRenderOrder(extension);
mesh.renderOrder = renderOrder + this.renderOrderOffset;
this._generateOutline(mesh);
this._addToMaterialSet(mesh);
return;
}
}
/**
* Check whether the material should generate outline or not.
* @param surfaceMaterial The material to check
* @returns True if the material should generate outline
*/
_shouldGenerateOutline(surfaceMaterial) {
return typeof surfaceMaterial.outlineWidthMode === "string" && surfaceMaterial.outlineWidthMode !== "none" && typeof surfaceMaterial.outlineWidthFactor === "number" && surfaceMaterial.outlineWidthFactor > 0;
}
/**
* Generate outline for the given mesh, if it needs.
*
* @param mesh The target mesh
*/
_generateOutline(mesh) {
const surfaceMaterial = mesh.material;
if (!(surfaceMaterial instanceof THREE5.Material)) {
return;
}
if (!this._shouldGenerateOutline(surfaceMaterial)) {
return;
}
mesh.material = [surfaceMaterial];
const outlineMaterial = surfaceMaterial.clone();
outlineMaterial.name += " (Outline)";
outlineMaterial.isOutline = true;
outlineMaterial.side = THREE5.BackSide;
mesh.material.push(outlineMaterial);
const geometry = mesh.geometry;
const primitiveVertices = geometry.index ? geometry.index.count : geometry.attributes.position.count / 3;
geometry.addGroup(0, primitiveVertices, 0);
geometry.addGroup(0, primitiveVertices, 1);
}
_addToMaterialSet(mesh) {
const materialOrMaterials = mesh.material;
const materialSet = /* @__PURE__ */ new Set();
if (Array.isArray(materialOrMaterials)) {
materialOrMaterials.forEach((material) => materialSet.add(material));
} else {
materialSet.add(materialOrMaterials);
}
for (const material of materialSet) {
this._mToonMaterialSet.add(material);
}
}
_parseRenderOrder(extension) {
var _a;
const enabledZWrite = extension.transparentWithZWrite;
return (enabledZWrite ? 0 : 19) + ((_a = extension.renderQueueOffsetNumber) != null ? _a : 0);
}
};
_MToonMaterialLoaderPlugin.EXTENSION_NAME = "VRMC_materials_mtoon";
var MToonMaterialLoaderPlugin = _MToonMaterialLoaderPlugin;
export {
MToonMaterial,
MToonMaterialDebugMode,
MToonMaterialLoaderPlugin,
MToonMaterialOutlineWidthMode
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL01Ub29uTWF0ZXJpYWxMb2FkZXJQbHVnaW4udHMiLCAiLi4vc3JjL0dMVEZNVG9vbk1hdGVyaWFsUGFyYW1zQXNzaWduSGVscGVyLnRzIiwgIi4uL3NyYy91dGlscy9zZXRUZXh0dXJlQ29sb3JTcGFjZS50cyIsICIuLi9zcmMvTVRvb25NYXRlcmlhbC50cyIsICIuLi9zcmMvc2hhZGVycy9tdG9vbi52ZXJ0IiwgIi4uL3NyYy9zaGFkZXJzL210b29uLmZyYWciLCAiLi4vc3JjL01Ub29uTWF0ZXJpYWxEZWJ1Z01vZGUudHMiLCAiLi4vc3JjL01Ub29uTWF0ZXJpYWxPdXRsaW5lV2lkdGhNb2RlLnRzIiwgIi4uL3NyYy91dGlscy9nZXRUZXh0dXJlQ29sb3JTcGFjZS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0ICogYXMgVEhSRUUgZnJvbSAndGhyZWUnO1xuaW1wb3J0ICogYXMgVjFNVG9vblNjaGVtYSBmcm9tICdAcGl4aXYvdHlwZXMtdnJtYy1tYXRlcmlhbHMtbXRvb24tMS4wJztcbmltcG9ydCB0eXBlIHsgR0xURiwgR0xURkxvYWRlciwgR0xURkxvYWRlclBsdWdpbiwgR0xURlBhcnNlciB9IGZyb20gJ3RocmVlL2V4YW1wbGVzL2pzbS9sb2FkZXJzL0dMVEZMb2FkZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBNVG9vbk1hdGVyaWFsUGFyYW1ldGVycyB9IGZyb20gJy4vTVRvb25NYXRlcmlhbFBhcmFtZXRlcnMnO1xuaW1wb3J0IHR5cGUgeyBNVG9vbk1hdGVyaWFsT3V0bGluZVdpZHRoTW9kZSB9IGZyb20gJy4vTVRvb25NYXRlcmlhbE91dGxpbmVXaWR0aE1vZGUnO1xuaW1wb3J0IHsgR0xURk1Ub29uTWF0ZXJpYWxQYXJhbXNBc3NpZ25IZWxwZXIgfSBmcm9tICcuL0dMVEZNVG9vbk1hdGVyaWFsUGFyYW1zQXNzaWduSGVscGVyJztcbmltcG9ydCB0eXBlIHsgTVRvb25NYXRlcmlhbExvYWRlclBsdWdpbk9wdGlvbnMgfSBmcm9tICcuL01Ub29uTWF0ZXJpYWxMb2FkZXJQbHVnaW5PcHRpb25zJztcbmltcG9ydCB0eXBlIHsgTVRvb25NYXRlcmlhbERlYnVnTW9kZSB9IGZyb20gJy4vTVRvb25NYXRlcmlhbERlYnVnTW9kZSc7XG5pbXBvcnQgeyBHTFRGIGFzIEdMVEZTY2hlbWEgfSBmcm9tICdAZ2x0Zi10cmFuc2Zvcm0vY29yZSc7XG5pbXBvcnQgeyBNVG9vbk1hdGVyaWFsIH0gZnJvbSAnLi9NVG9vbk1hdGVyaWFsJztcbmltcG9ydCB0eXBlIHsgTVRvb25Ob2RlTWF0ZXJpYWwgfSBmcm9tICcuL25vZGVzL01Ub29uTm9kZU1hdGVyaWFsJztcblxuLyoqXG4gKiBQb3NzaWJsZSBzcGVjIHZlcnNpb25zIGl0IHJlY29nbml6ZXMuXG4gKi9cbmNvbnN0IFBPU1NJQkxFX1NQRUNfVkVSU0lPTlMgPSBuZXcgU2V0KFsnMS4wJywgJzEuMC1iZXRhJ10pO1xuXG4vKipcbiAqIEEgbG9hZGVyIHBsdWdpbiBvZiB7QGxpbmsgR0xURkxvYWRlcn0gZm9yIHRoZSBleHRlbnNpb24gYFZSTUNfbWF0ZXJpYWxzX210b29uYC5cbiAqXG4gKiBUaGlzIHBsdWdpbiBpcyBmb3IgdXNlcyB3aXRoIFdlYkdMUmVuZGVyZXIgYnkgZGVmYXVsdC5cbiAqIFRvIHVzZSBNVG9vbiBpbiBXZWJHUFVSZW5kZXJlciwgc2V0IHtAbGluayBtYXRlcmlhbFR5cGV9IHRvIHtAbGluayBNVG9vbk5vZGVNYXRlcmlhbH0uXG4gKlxuICogQGV4YW1wbGUgdG8gdXNlIHdpdGggV2ViR1BVUmVuZGVyZXJcbiAqIGBgYGpzXG4gKiBpbXBvcnQgeyBNVG9vbk1hdGVyaWFsTG9hZGVyUGx1Z2luIH0gZnJvbSAnQHBpeGl2L3RocmVlLXZybS1tYXRlcmlhbHMtbXRvb24nO1xuICogaW1wb3J0IHsgTVRvb25Ob2RlTWF0ZXJpYWwgfSBmcm9tICdAcGl4aXYvdGhyZWUtdnJtLW1hdGVyaWFscy1tdG9vbi9ub2Rlcyc7XG4gKlxuICogLy8gLi4uXG4gKlxuICogLy8gUmVnaXN0ZXIgYSBNVG9vbk1hdGVyaWFsTG9hZGVyUGx1Z2luIHdpdGggTVRvb25Ob2RlTWF0ZXJpYWxcbiAqIGxvYWRlci5yZWdpc3RlcigocGFyc2VyKSA9PiB7XG4gKlxuICogICAvLyBjcmVhdGUgYSBXZWJHUFUgY29tcGF0aWJsZSBNVG9vbk1hdGVyaWFsTG9hZGVyUGx1Z2luXG4gKiAgIHJldHVybiBuZXcgTVRvb25NYXRlcmlhbExvYWRlclBsdWdpbihwYXJzZXIsIHtcbiAqXG4gKiAgICAgLy8gc2V0IHRoZSBtYXRlcmlhbCB0eXBlIHRvIE1Ub29uTm9kZU1hdGVyaWFsXG4gKiAgICAgbWF0ZXJpYWxUeXBlOiBNVG9vbk5vZGVNYXRlcmlhbCxcbiAqXG4gKiAgIH0pO1xuICpcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBNVG9vbk1hdGVyaWFsTG9hZGVyUGx1Z2luIGltcGxlbWVudHMgR0xURkxvYWRlclBsdWdpbiB7XG4gIHB1YmxpYyBzdGF0aWMgRVhURU5TSU9OX05BTUUgPSAnVlJNQ19tYXRlcmlhbHNfbXRvb24nO1xuXG4gIC8qKlxuICAgKiBUaGUgdHlwZSBvZiB0aGUgbWF0ZXJpYWwgdGhhdCB0aGlzIHBsdWdpbiB3aWxsIGdlbmVyYXRlLlxuICAgKlxuICAgKiBJZiB5b3UgYXJlIHVzaW5nIHRoaXMgcGx1Z2luIHdpdGggV2ViR1BVLCBzZXQgdGhpcyB0byB7QGxpbmsgTVRvb25Ob2RlTWF0ZXJpYWx9LlxuICAgKlxuICAgKiBAZGVmYXVsdCBNVG9vbk1hdGVyaWFsXG4gICAqL1xuICBwdWJsaWMgbWF0ZXJpYWxUeXBlOiB0eXBlb2YgVEhSRUUuTWF0ZXJpYWw7XG5cbiAgLyoqXG4gICAqIFRoaXMgdmFsdWUgd2lsbCBiZSBhZGRlZCB0byBgcmVuZGVyT3JkZXJgIG9mIGV2ZXJ5IG1lc2hlcyB3aG8gaGF2ZSBNYXRlcmlhbHNNVG9vbi5cbiAgICogVGhlIGZpbmFsIHJlbmRlck9yZGVyIHdpbGwgYmUgc3VtIG9mIHRoaXMgYHJlbmRlck9yZGVyT2Zmc2V0YCBhbmQgYHJlbmRlclF1ZXVlT2Zmc2V0TnVtYmVyYCBmb3IgZWFjaCBtYXRlcmlhbHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IDBcbiAgICovXG4gIHB1YmxpYyByZW5kZXJPcmRlck9mZnNldDogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGVyZSBpcyBhIGxpbmUgb2YgdGhlIHNoYWRlciBjYWxsZWQgXCJjb21tZW50IG91dCBpZiB5b3Ugd2FudCB0byBQQlIgYWJzb2x1dGVseVwiIGluIFZSTTAuMCBNVG9vbi5cbiAgICogV2hlbiB0aGlzIGlzIHRydWUsIHRoZSBtYXRlcmlhbCBlbmFibGVzIHRoZSBsaW5lIHRvIG1ha2UgaXQgY29tcGF0aWJsZSB3aXRoIHRoZSBsZWdhY3kgc