1import { 2 CSS2DObject, 3 CSS2DRenderer, 4 Canvas, 5 GLTFExporter, 6 TrackballControls, 7 createT, 8 createXR, 9 useFrame, 10 useThree 11} from "./chunk-6JQSYMRV.js"; 12import { 13 REVISION as REVISION2 14} from "./chunk-YWNSTGG6.js"; 15import { 16 CameraProvider, 17 ViewerProvider, 18 WorkerProvider, 19 createStore, 20 reconcile, 21 saveFileAs, 22 saveTextFileAs, 23 unwrap, 24 useCamera, 25 useViewer, 26 useWorkerClient 27} from "./chunk-737R77QV.js"; 28import { 29 $TRACK, 30 ACESFilmicToneMapping, 31 AddEquation, 32 AddOperation, 33 AdditiveBlending, 34 AgXToneMapping, 35 AlphaFormat, 36 AlwaysCompare, 37 AlwaysDepth, 38 AlwaysStencilFunc, 39 AmbientLight, 40 ArrayCamera, 41 BackSide, 42 BasicShadowMap, 43 BoxGeometry, 44 BufferAttribute, 45 BufferGeometry, 46 ByteType, 47 CineonToneMapping, 48 ClampToEdgeWrapping, 49 Color, 50 ColorManagement, 51 Compatibility, 52 CubeCamera, 53 CubeDepthTexture, 54 CubeReflectionMapping, 55 CubeRefractionMapping, 56 CubeTexture, 57 CubeUVReflectionMapping, 58 CullFaceBack, 59 CullFaceFront, 60 CullFaceNone, 61 CustomBlending, 62 CylinderGeometry, 63 DEV, 64 DataArrayTexture, 65 DataTexture, 66 DecrementStencilOp, 67 DecrementWrapStencilOp, 68 DepthFormat, 69 DepthStencilFormat, 70 DepthTexture, 71 DirectionalLight, 72 DoubleSide, 73 DstAlphaFactor, 74 DstColorFactor, 75 Dynamic, 76 DynamicDrawUsage, 77 EqualCompare, 78 EqualDepth, 79 EqualStencilFunc, 80 EquirectangularReflectionMapping, 81 EquirectangularRefractionMapping, 82 Euler, 83 EventDispatcher, 84 Float16BufferAttribute, 85 Float32BufferAttribute, 86 FloatType, 87 For, 88 FramebufferTexture, 89 FrontSide, 90 Frustum, 91 FrustumArray, 92 GreaterCompare, 93 GreaterDepth, 94 GreaterEqualCompare, 95 GreaterEqualDepth, 96 GreaterEqualStencilFunc, 97 GreaterStencilFunc, 98 Group, 99 HalfFloatType, 100 HemisphereLight, 101 IncrementStencilOp, 102 IncrementWrapStencilOp, 103 InstancedBufferAttribute, 104 InstancedInterleavedBuffer, 105 InstancedMesh, 106 IntType, 107 InterleavedBuffer, 108 InterleavedBufferAttribute, 109 InvertStencilOp, 110 KeepStencilOp, 111 LessCompare, 112 LessDepth, 113 LessEqualCompare, 114 LessEqualDepth, 115 LessEqualStencilFunc, 116 LessStencilFunc, 117 LightProbe, 118 LineBasicMaterial, 119 LineDashedMaterial, 120 LineSegments, 121 LinearFilter, 122 LinearMipMapLinearFilter, 123 LinearMipmapLinearFilter, 124 LinearMipmapNearestFilter, 125 LinearSRGBColorSpace, 126 LinearToneMapping, 127 LinearTransfer, 128 Material, 129 MaterialBlending, 130 MathUtils, 131 Matrix2, 132 Matrix3, 133 Matrix4, 134 MaxEquation, 135 Mesh, 136 MeshBasicMaterial, 137 MeshLambertMaterial, 138 MeshMatcapMaterial, 139 MeshNormalMaterial, 140 MeshPhongMaterial, 141 MeshPhysicalMaterial, 142 MeshStandardMaterial, 143 MeshToonMaterial, 144 MinEquation, 145 MirroredRepeatWrapping, 146 MixOperation, 147 MultiplyBlending, 148 MultiplyOperation, 149 NearestFilter, 150 NearestMipmapLinearFilter, 151 NearestMipmapNearestFilter, 152 NeutralToneMapping, 153 NeverCompare, 154 NeverDepth, 155 NeverStencilFunc, 156 NoBlending, 157 NoColorSpace, 158 NoNormalPacking, 159 NoToneMapping, 160 NormalBlending, 161 NormalGAPacking, 162 NormalRGPacking, 163 NotEqualCompare, 164 NotEqualDepth, 165 NotEqualStencilFunc, 166 Object3D, 167 ObjectSpaceNormalMap, 168 OneFactor, 169 OneMinusDstAlphaFactor, 170 OneMinusDstColorFactor, 171 OneMinusSrcAlphaFactor, 172 OneMinusSrcColorFactor, 173 OrthographicCamera, 174 PCFShadowMap, 175 PCFSoftShadowMap, 176 PerspectiveCamera, 177 Plane, 178 PlaneGeometry, 179 PointLight, 180 PointsMaterial, 181 Portal, 182 Quaternion, 183 R11_EAC_Format, 184 RAD2DEG, 185 RED_GREEN_RGTC2_Format, 186 RED_RGTC1_Format, 187 REVISION, 188 RG11_EAC_Format, 189 RGBAFormat, 190 RGBAIntegerFormat, 191 RGBA_ASTC_10x10_Format, 192 RGBA_ASTC_10x5_Format, 193 RGBA_ASTC_10x6_Format, 194 RGBA_ASTC_10x8_Format, 195 RGBA_ASTC_12x10_Format, 196 RGBA_ASTC_12x12_Format, 197 RGBA_ASTC_4x4_Format, 198 RGBA_ASTC_5x4_Format, 199 RGBA_ASTC_5x5_Format, 200 RGBA_ASTC_6x5_Format, 201 RGBA_ASTC_6x6_Format, 202 RGBA_ASTC_8x5_Format, 203 RGBA_ASTC_8x6_Format, 204 RGBA_ASTC_8x8_Format, 205 RGBA_BPTC_Format, 206 RGBA_ETC2_EAC_Format, 207 RGBA_PVRTC_2BPPV1_Format, 208 RGBA_PVRTC_4BPPV1_Format, 209 RGBA_S3TC_DXT1_Format, 210 RGBA_S3TC_DXT3_Format, 211 RGBA_S3TC_DXT5_Format, 212 RGBFormat, 213 RGBIntegerFormat, 214 RGB_ETC1_Format, 215 RGB_ETC2_Format, 216 RGB_PVRTC_2BPPV1_Format, 217 RGB_PVRTC_4BPPV1_Format, 218 RGB_S3TC_DXT1_Format, 219 RGFormat, 220 RGIntegerFormat, 221 RectAreaLight, 222 RedFormat, 223 RedIntegerFormat, 224 ReinhardToneMapping, 225 RenderTarget, 226 RepeatWrapping, 227 ReplaceStencilOp, 228 ReverseSubtractEquation, 229 ReversedDepthFuncs, 230 SIGNED_R11_EAC_Format, 231 SIGNED_RED_GREEN_RGTC2_Format,
232 SIGNED_RED_RGTC1_Format, 233 SIGNED_RG11_EAC_Format, 234 SRGBColorSpace, 235 SRGBTransfer, 236 Scene, 237 ShadowMaterial, 238 ShortType, 239 Show, 240 Sphere, 241 SphereGeometry, 242 SpotLight, 243 SpriteMaterial, 244 SrcAlphaFactor, 245 SrcAlphaSaturateFactor, 246 SrcColorFactor, 247 StaticDrawUsage, 248 SubtractEquation, 249 SubtractiveBlending, 250 Suspense, 251 TangentSpaceNormalMap, 252 Texture, 253 TimestampQuery, 254 UVMapping, 255 Uint16BufferAttribute, 256 Uint32BufferAttribute, 257 UnsignedByteType, 258 UnsignedInt101111Type, 259 UnsignedInt248Type, 260 UnsignedInt5999Type, 261 UnsignedIntType, 262 UnsignedShort4444Type, 263 UnsignedShort5551Type, 264 UnsignedShortType, 265 VSMShadowMap, 266 Vector2, 267 Vector3, 268 Vector4, 269 WebGLCoordinateSystem, 270 WebGLRenderer, 271 WebGPUCoordinateSystem, 272 WebXRController, 273 ZeroFactor, 274 ZeroStencilOp, 275 addEventListener, 276 batch, 277 children, 278 createCanvasElement, 279 createComponent, 280 createComputed, 281 createContext, 282 createEffect, 283 createMemo, 284 createRenderEffect, 285 createResource, 286 createRoot, 287 createSignal, 288 createUniqueId, 289 delegateEvents, 290 error, 291 getByteLength, 292 getListener, 293 getOwner, 294 insert, 295 isServer, 296 isTypedArray, 297 lazy, 298 log, 299 memo, 300 mergeProps, 301 on, 302 onCleanup, 303 onMount, 304 render, 305 setAttribute, 306 sharedConfig, 307 splitProps, 308 style, 309 template, 310 untrack, 311 use, 312 useContext, 313 warn, 314 warnOnce, 315 yieldToMain 316} from "./chunk-47C2ISC4.js"; 317import { 318 encodeEntities, 319 selectSnapshot 320} from "./chunk-J3RXXGCJ.js"; 321
322// src/viewer/urlviewer.css.js 323var urlViewerCSS = ` 324 325svg { 326 height: 100%; 327} 328 329.vzome-label { 330 color: var(--vzome-label-color); 331 background-color: var(--vzome-label-background); 332 font-size: var(--vzome-label-size); 333 font-style: var(--vzome-label-style); 334 font-weight: var(--vzome-label-weight); 335} 336 337.scene__select { 338 width: 200px; 339 border-radius: 6px; 340 padding: 0 10px 0 16px; 341 font-size: 16px; 342 line-height: 1; 343 height: 40px; 344 outline: none; 345 background-color: white; 346 border: 1px solid hsl(240 6% 90%); 347 color: hsl(240 4% 16%); 348 transition: border-color 250ms, color 250ms; 349 cursor: pointer; 350} 351.scene__select:hover { 352 border-color: hsl(240 5% 65%); 353} 354.scene__select:focus-visible { 355 outline: 2px solid hsl(200 98% 39%); 356 outline-offset: 2px; 357} 358 359.settings__overlay, 360.progress__overlay { 361 position: fixed; 362 inset: 0; 363 z-index: 50; 364 background-color: rgb(0 0 0 / 0.2); 365 // animation: overlayHide 250ms ease 100ms forwards; 366} 367.settings__overlay[data-expanded], 368.progress__overlay[data-expanded] { 369 // animation: overlayShow 250ms ease; 370} 371.settings__positioner, 372.progress__positioner { 373 position: fixed; 374 inset: 0; 375 z-index: 50; 376 display: flex; 377 align-items: center; 378 justify-content: center; 379} 380.settings__content, 381.progress__content { 382 z-index: 50; 383 max-width: min(calc(100vw - 16px), 500px); 384 border: 1px solid hsl(240 5% 84%); 385 border-radius: 6px; 386 padding: 16px; 387 background-color: white; 388 box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 389 // animation: progress__contentHide 300ms ease-in forwards; 390} 391.settings__content[data-expanded], 392.progress__content[data-expanded] { 393 // animation: contentShow_scale 300ms ease-out; 394} 395 396 397.progress { 398 display: flex; 399 flex-direction: column; 400 gap: 2px; 401 width: 300px; 402} 403.progress__label-container { 404 display: flex; 405 justify-content: space-between; 406} 407.progress__label, 408.progress__value-label { 409 color: hsl(240 4% 16%); 410 font-size: 14px; 411} 412.progress__track { 413 height: 10px; 414 background-color: hsl(240 6% 90%); 415} 416.progress__fill { 417 background-color: hsl(200 98% 39%); 418 height: 100%; 419 width: var(--kb-progress-fill-width); 420 transition: width 250ms linear; 421} 422.progress__fill[data-progress="complete"] { 423 background-color: #16a34a; 424} 425 426 427.alert-dialog__trigger { 428 appearance: none; 429 display: inline-flex; 430 justify-content: center; 431 align-items: center; 432 height: 40px; 433 width: auto; 434 outline: none; 435 border-radius: 6px; 436 padding: 0 16px; 437 background-color: hsl(200 98% 39%); 438 color: white; 439 font-size: 16px; 440 line-height: 0; 441 transition: 250ms background-color; 442} 443.alert-dialog__trigger:hover { 444 background-color: hsl(201 96% 32%); 445} 446.alert-dialog__trigger:focus-visible { 447 outline: 2px solid hsl(200 98% 39%); 448 outline-offset: 2px; 449} 450.alert-dialog__trigger:active { 451 background-color: hsl(201 90% 27%); 452} 453.alert-dialog__overlay { 454 position: absolute; 455 inset: 0; 456 z-index: 50; 457 background-color: rgb(0 0 0 / 0.2); 458 animation: overlayHide 250ms ease 100ms forwards; 459} 460.alert-dialog__overlay[data-expanded] { 461 animation: overlayShow 250ms ease; 462} 463.alert-dialog__positioner { 464 position: absolute; 465 inset: 0; 466 z-index: 50; 467 display: flex; 468 align-items: center; 469 justify-content: center; 470} 471.alert-dialog__content { 472 z-index: 50; 473 max-width: min(calc(100vw - 16px), 500px); 474 border: 1px solid hsl(240 5% 84%); 475 border-radius: 6px; 476 padding: 16px; 477 background-color: darkred; 478 box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 479 animation: contentHide 300ms ease-in forwards; 480} 481.alert-dialog__content[data-expanded] { 482 animation: alert__contentShow 300ms ease-out; 483} 484.alert-dialog__header { 485 display: flex; 486 align-items: baseline; 487 justify-content: space-between; 488 margin-bottom: 12px; 489} 490.alert-dialog__close-button { 491 display: inline-flex; 492 height: 16px; 493 width: 16px; 494 align-items: center; 495 border: none; 496 padding: unset; 497} 498.alert-dialog__title { 499 font-size: 20px; 500 font-weight: 500; 501 color: white; 502 margin-block: 0px; 503} 504.alert-dialog__description { 505 font-size: 16px; 506 color: white; 507 margin-block: 0px; 508 margin-bottom: 4px; 509} 510 511 512.settings-button { 513 appearance: none; 514 outline: none; 515 background-color: rgba(122, 122, 122, 0.3); 516 color: rgba(90,90,90, 1); 517 fill: currentColor; 518 transition: 250ms background-color; 519 position: absolute; 520 top: 0.5em; 521 right: 0.5em; 522 border-style: none; 523 width: 5em; 524 border-radius: 1.3rem; 525 padding-block: 0.4rem; 526 padding-inline: 0.7rem; 527} 528.settings-button:hover { 529 background-color: rgba(122, 122, 122, 0.7); 530} 531 532.settingsdialog__trigger { 533 appearance: none; 534 display: inline-flex; 535 justify-content: center; 536 align-items: center; 537 height: 40px; 538 width: auto; 539 outline: none; 540 border-radius: 6px; 541 padding: 0 16px; 542 background-color: hsl(200 98% 39%); 543 color: white; 544 font-size: 16px; 545 line-height: 0; 546 transition: 250ms background-color; 547} 548.settingsdialog__trigger:hover { 549 background-color: hsl(201 96% 32%); 550} 551.settingsdialog__trigger:focus-visible { 552 outline: 2px solid hsl(200 98% 39%); 553 outline-offset: 2px; 554} 555.settingsdialog__trigger:active { 556 background-color: hsl(201 90% 27%); 557} 558.settingsdialog__overlay { 559 position: fixed; 560 inset: 0; 561 z-index: 50; 562 background-color: rgb(0 0 0 / 0.2); 563 animation: settings__overlayHide 250ms ease 100ms forwards; 564} 565.settingsdialog__overlay[data-expanded] { 566 animation: settings__overlayShow 250ms ease; 567} 568.settingsdialog__positioner { 569 position: absolute; 570 inset: 0; 571 z-index: 50; 572 display: flex; 573 align-items: center; 574 justify-content: center; 575} 576.settingsdialog__content { 577 z-index: 50; 578 max-width: min(calc(100vw - 16px), 500px); 579 border: 1px solid hsl(240 5% 84%); 580 border-radius: 6px; 581 padding: 16px; 582 background-color: white; 583 box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 584 animation: contentHide_scale 300ms ease-in forwards; 585} 586.settingsdialog__content[data-expanded] { 587 animation: contentShow_scale 300ms ease-out; 588} 589 590.settingsdialog__body { 591 display: flex; 592 padding: 1rem; 593 gap: 2rem; 594} 595 596.settingsdialog__header { 597 display: flex; 598 align-items: baseline; 599 justify-content: space-between; 600 margin-bottom: 12px; 601} 602.settingsdialog__close-button { 603 height: 16px; 604 width: 16px; 605 color: hsl(240 5% 34%); 606} 607.settingsdialog__title { 608 font-size: 20px; 609 font-weight: 500; 610 color: hsl(240 6% 10%); 611} 612.settingsdialog__description { 613 font-size: 16px; 614 color: hsl(240 5% 26%); 615} 616@keyframes settings__overlayShow { 617 from { 618 opacity: 0; 619 } 620 to { 621 opacity: 1; 622 } 623} 624@keyframes settings__overlayHide { 625 from { 626 opacity: 1; 627 } 628 to { 629 opacity: 0; 630 } 631} 632 633.corner__icon__button { 634 appearance: none; 635 display: inline-flex; 636 justify-content: center; 637 outline: none; 638 background-color: rgba(122, 122, 122, 0.3); 639 color: rgba(90,90,90, 1); 640 fill: currentColor; 641 font-size: 12px; 642 line-height: 0; 643 transition: 250ms background-color; 644 position: absolute; 645 border-style: none; 646 border-radius: 50%; 647 height: 4rem; 648 width: 4rem; 649 align-items: center; 650 padding: 0.7rem; 651} 652.corner__icon__button:hover { 653 background-color: rgba(122, 122, 122, 0.7); 654} 655.corner__icon__button:focus-visible { 656 outline: 2px solid hsl(200 98% 39%); 657 outline-offset: 2px; 658} 659.corner__icon__button:active { 660 background-color: rgba(0, 0, 0, 0.24); 661} 662 663 664.fullscreen { 665 bottom: 0.5em; 666 right: 0.5em; 667} 668 669.iconbutton__content { 670 z-index: 50; 671 max-width: min(calc(100vw - 16px), 380px); 672 border: 1px solid hsl(240 5% 84%); 673 border-radius: 6px; 674 padding: 8px; 675 background-color: hsl(240 4% 16%); 676 color: white; 677 font-size: 14px; 678 box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 679 transform-origin: var(--kb-tooltip-content-transform-origin); 680 animation: contentHide_scale 250ms ease-in forwards; 681} 682.iconbutton__content[data-expanded] { 683 animation: contentShow_scale 250ms ease-out; 684} 685 686 687.exports__trigger { 688 bottom: 0.5em; 689 left: 0.5em; 690} 691.exports__content { 692 min-width: 220px; 693 padding: 8px; 694 background-color: white; 695 border-radius: 6px; 696 border: 1px solid hsl(240 6% 90%); 697 box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); 698 outline: none; 699 transform-origin: var(--kb-menu-content-transform-origin); 700 animation: contentHide_scale 250ms ease-in forwards; 701} 702.exports__content[data-expanded] { 703 animation: contentShow_scale 250ms ease-out; 704} 705.exports__item { 706 font-size: 16px; 707 line-height: 1; 708 color: hsl(240 4% 16%); 709 border-radius: 4px; 710 display: flex; 711 align-items: center; 712 height: 32px; 713 padding: 0 8px 0 24px; 714 position: relative; 715 user-select: none; 716 outline: none; 717} 718.exports__item[data-disabled] { 719 color: hsl(240 5% 65%); 720 opacity: 0.5; 721 pointer-events: none; 722} 723.exports__item[data-highlighted] { 724 outline: none; 725 background-color: hsl(200 98% 39%); 726 color: white; 727} 728 729@keyframes contentShow_scale { 730 from { 731 opacity: 0; 732 transform: scale(0.96); 733 } 734 to { 735 opacity: 1; 736 transform: scale(1); 737 } 738} 739@keyframes contentHide_scale { 740 from { 741 opacity: 1; 742 transform: scale(1); 743 } 744 to { 745 opacity: 0; 746 transform: scale(0.96); 747 } 748} 749 750 751@keyframes overlayShow { 752 from { 753 opacity: 0; 754 } 755 to { 756 opacity: 1; 757 } 758} 759@keyframes overlayHide { 760 from { 761 opacity: 1; 762 } 763 to { 764 opacity: 0; 765 } 766} 767 768.switch { 769 display: inline-flex; 770 align-items: center; 771} 772.switch__control { 773 display: inline-flex; 774 align-items: center; 775 height: 19px; 776 width: 33px; 777 border: 1px solid hsl(200 98% 39%); 778 border-radius: 12px; 779 padding: 0 2px; 780 background-color: hsl(200deg 38.91% 75%); 781 transition: 250ms background-color; 782} 783.switch__input:focus-visible + .switch__control { 784 outline: 2px solid hsl(200 98% 39%); 785 outline-offset: 2px; 786} 787.switch__control[data-checked] { 788 border-color: hsl(200 98% 39%); 789 background-color: hsl(200 98% 39%); 790} 791.switch__thumb { 792 height: 17px; 793 width: 17px; 794 border-radius: 10px; 795 background-color: white; 796 transition: 250ms transform; 797} 798.switch__thumb[data-checked] { 799 transform: translateX(calc(100% - 1px)); 800} 801.switch__label { 802 margin-right: 6px; 803 color: hsl(240 6% 10%); 804 font-size: 14px; 805 user-select: none; 806} 807`; 808
809// src/viewer/context/scene.jsx 810var SceneContext = createContext({ 811 scene: () => { 812 console.log("NO SceneProvider"); 813 }, 814 setSelectionHighlighter: () => { 815 }, 816 highlightSelection: () => { 817 } 818}); 819var SceneProvider = (props) => { 820 const { 821 labels: showLabels 822 } = props.config || {}; 823 const [scene, setScene] = createStore({}); 824 const [labels, setLabels] = createSignal(showLabels); 825 const addShape = (shape, id = shape.id) => { 826 if (!id) { 827 console.warn("Ignoring a shape with no id", shape); 828 return false; 829 } 830 if (!scene.shapes) { 831 setScene("shapes", {}); 832 } 833 if (!scene?.shapes[id]) { 834 setScene("shapes", id, { 835 ...shape, 836 id 837 }); 838 return true; 839 } 840 return false; 841 }; 842 const updateShapes = (shapes) => { 843 for (const [id, shape] of Object.entries(shapes)) { 844 if (!addShape(shape, id)) { 845 if (!scene?.shapes?.[id]) continue; 846 setScene("shapes", id, "instances", shape.instances); 847 } 848 } 849 for (const id of Object.keys(scene?.shapes || {})) { 850 if (!(id in shapes)) setScene("shapes", id, "instances", []); 851 } 852 }; 853 const resetScene = () => setScene(reconcile({})); 854 let selectionHighlighter = null; 855 const setSelectionHighlighter = (fn) => { 856 selectionHighlighter = fn; 857 }; 858 const highlightSelection = (shapeId, id, selected) => selectionHighlighter?.(shapeId, id, selected); 859 const apiObject = { 860 scene, 861 setScene, 862 labels, 863 updateShapes, 864 addShape, 865 resetScene, 866 useViewer, 867 setSelectionHighlighter, 868 highlightSelection 869 }; 870 return createComponent(SceneContext.Provider, { 871 value: apiObject, 872 get children() { 873 return props.children; 874 } 875 }); 876}; 877var useScene = () => { 878 return useContext(SceneContext); 879}; 880var SceneIndexingContext = createContext({ 881 showIndexedScene: () => { 882 console.log("NO SceneIndexingProvider"); 883 } 884}); 885var useSceneIndexing = () => { 886 return useContext(SceneIndexingContext); 887}; 888var SceneIndexingProvider = (props) => { 889 const { 890 updateShapes, 891 setScene 892 } = useScene(); 893 const { 894 postRequest 895 } = useWorkerClient(); 896 const { 897 tweenCamera 898 } = useCamera(); 899 const { 900 scenes 901 } = useViewer(); 902 const [lastSceneIndex, setLastSceneIndex] = createSignal(null); 903 const showIndexedScene = (sceneIndex, config) => { 904 if (scenes.length === 0) return; 905 if (sceneIndex >= scenes.length) sceneIndex = 0; 906 postRequest(selectSnapshot(scenes[sceneIndex].snapshot)).then(({ 907 payload: { 908 scene 909 } 910 }) => { 911 setLastSceneIndex(sceneIndex); 912 setScene("embedding", reconcile(scene.embedding)); 913 setScene("polygons", scene.polygons); 914 if (scene.orientations) setScene("orientations", scene.orientations); 915 const { 916 camera 917 } = config || { 918 camera: true 919 }; 920 setTimeout(() => { 921 (camera ? tweenCamera(scenes[sceneIndex].camera) : Promise.resolve()).then(() => updateShapes(scene.shapes)); 922 }); 923 }); 924 }; 925 createEffect(() => { 926 if (props.index !== void 0) { 927 console.log(`SceneIndexingProvider effect showing ${props.index}`); 928 showIndexedScene(props.index); 929 } 930 }); 931 return createComponent(SceneIndexingContext.Provider, { 932 value: { 933 showIndexedScene, 934 lastSceneIndex, 935 setLastSceneIndex 936 }, 937 get children() { 938 return props.children; 939 } 940 }); 941}; 942var SceneTitlesContext = createContext({ 943 showTitledScene: () => { 944 console.log("NO SceneTitlesProvider"); 945 } 946}); 947var useSceneTitles = () => { 948 return useContext(SceneTitlesContext); 949}; 950var unnamedScene = (scene, index) => !scene.title?.trim() || index === 0 && "default scene" === scene.title; 951var getSceneTitleIndex = (scenes, title) => { 952 if (!title) return 0; 953 title = encodeEntities(title); 954 let index; 955 if (title.startsWith("#")) { 956 const indexStr = title.substring(1); 957 index = parseInt(indexStr); 958 if (isNaN(index) || index < 0 || index > scenes.length) { 959 console.log(`WARNING: ${index} is not a scene index`); 960 index = 0; 961 } 962 } else { 963 index = scenes.map((s) => s.title?.trim()).indexOf(title); 964 if (index < 0) { 965 console.log(`WARNING: no scene titled "${title}"`); 966 index = 0; 967 } 968 } 969 return index; 970};
971var SceneTitlesProvider = (props) => { 972 const { 973 scenes 974 } = useViewer(); 975 const { 976 showIndexedScene 977 } = useSceneIndexing(); 978 const namedScenes = () => scenes.filter((scene, index) => !unnamedScene(scene, index)).map((scene) => scene.title); 979 const sceneTitles = () => props.show === "given" ? [] : props.show === "titled" ? namedScenes() : scenes.map((scene, index) => scene.title?.trim() || (index === 0 ? "default scene" : `#${index}`)); 980 const [sceneTitle, setSceneTitle] = createSignal(props.show === "given" ? props.title : sceneTitles()[0]); 981 if (props.show !== "given") { 982 createEffect(() => { 983 if (sceneTitle() === void 0 && scenes.length > 0) { 984 setSceneTitle(sceneTitles()[0]); 985 } 986 }); 987 } 988 const showTitledScene = (name, config) => { 989 const index = getSceneTitleIndex(scenes, name); 990 if (index < scenes.length) { 991 showIndexedScene(index, config); 992 } 993 }; 994 return createComponent(SceneTitlesContext.Provider, { 995 value: { 996 showTitledScene, 997 sceneTitle, 998 setSceneTitle, 999 sceneTitles 1000 }, 1001 get children() { 1002 return props.children; 1003 } 1004 }); 1005}; 1006var SceneChangeListener = () => { 1007 const { 1008 scene, 1009 updateShapes, 1010 addShape, 1011 setScene, 1012 highlightSelection 1013 } = useScene(); 1014 const { 1015 subscribeFor 1016 } = useWorkerClient(); 1017 const storeSceneSymmetryId = () => scene.symmetryId; 1018 subscribeFor("SYMMETRY_CHANGED", ({ 1019 orientations, 1020 fieldName, 1021 symmetryName, 1022 embedding 1023 }) => { 1024 const nextSymmetryId = fieldName && symmetryName ? `${fieldName}:${symmetryName}` : void 0; 1025 batch(() => { 1026 const symmetryChanged = nextSymmetryId === void 0 || nextSymmetryId !== scene.symmetryId; 1027 if (symmetryChanged) setScene("shapes", reconcile({})); 1028 if (nextSymmetryId) setScene("symmetryId", nextSymmetryId); 1029 setScene("orientations", orientations); 1030 if (embedding) setScene("embedding", reconcile(embedding)); 1031 }); 1032 }); 1033 subscribeFor("SCENE_RENDERED", ({ 1034 scene: scene2 1035 }) => { 1036 if (scene2.symmetryId && storeSceneSymmetryId() && scene2.symmetryId !== storeSceneSymmetryId()) return; 1037 setScene("embedding", reconcile(scene2.embedding)); 1038 setScene("polygons", scene2.polygons); 1039 if (scene2.orientations) setScene("orientations", scene2.orientations); 1040 updateShapes(scene2.shapes); 1041 }); 1042 subscribeFor("SHAPE_DEFINED", (shape) => { 1043 addShape({ 1044 ...shape, 1045 instances: [] 1046 }); 1047 }); 1048 subscribeFor("INSTANCE_ADDED", (instance3) => { 1049 const { 1050 shapeId, 1051 orientation 1052 } = instance3; 1053 const shape = scene.shapes[shapeId]; 1054 const rotation = unwrap(scene.orientations[orientation < 0 ? 0 : orientation]); 1055 setScene("shapes", shape.id, "instances", [...shape.instances, { 1056 ...instance3, 1057 rotation 1058 }]); 1059 }); 1060 subscribeFor("INSTANCE_REMOVED", ({ 1061 shapeId, 1062 id 1063 }) => { 1064 const shape = scene.shapes[shapeId]; 1065 const instances = shape.instances.filter((instance3) => instance3.id != id); 1066 setScene("shapes", shape.id, "instances", instances); 1067 }); 1068 subscribeFor("SELECTION_TOGGLED", ({ 1069 shapeId, 1070 id, 1071 selected 1072 }) => { 1073 highlightSelection(shapeId, id, selected); 1074 const shape = scene.shapes[shapeId]; 1075 const index = shape?.instances.findIndex((inst) => inst.id === id); 1076 if (index === void 0 || index < 0) return; 1077 setScene("shapes", shapeId, "instances", index, "selected", selected); 1078 }); 1079 return null; 1080}; 1081
1082// src/viewer/context/interaction.jsx 1083var InteractionToolContext = createContext([]); 1084var grabTool = { 1085 allowTrackball: true, 1086 // THIS is the reason this component exists 1087 cursor: "grab", 1088 onClick: () => { 1089 }, 1090 bkgdClick: () => { 1091 }, 1092 onDragStart: () => { 1093 }, 1094 onDrag: () => { 1095 }, 1096 onDragEnd: () => { 1097 }, 1098 onTrackballEnd: () => { 1099 } 1100}; 1101var MAX_CLICK_DURATION = 500; 1102var MAX_CLICK_DISTANCE = 2; 1103var InteractionToolProvider = (props) => { 1104 const [tool, setTool] = createSignal(props.defaultTool || grabTool); 1105 let lastPointerDown = null; 1106 let dragStartEmitted = false; 1107 const wrappedTool = { 1108 allowTrackball: () => tool()?.allowTrackball, 1109 cursor: () => tool()?.cursor, 1110 onClick: (id, position, type, selected) => tool()?.onClick(id, position, type, selected), 1111 bkgdClick: () => tool()?.bkgdClick(), 1112 onWheel: (dY) => tool()?.onWheel && tool().onWheel(dY), 1113 onDragStart: (e, id, position, type, selected) => { 1114 lastPointerDown = e; 1115 dragStartEmitted = false; 1116 }, 1117 onDrag: (e, id, position, type, selected) => { 1118 if (lastPointerDown) { 1119 const deltaX = e.x - lastPointerDown.x; 1120 const deltaY = e.y - lastPointerDown.y; 1121 if (deltaX > MAX_CLICK_DISTANCE || deltaY > MAX_CLICK_DISTANCE) { 1122 if (!dragStartEmitted) { 1123 tool().onDragStart(lastPointerDown, id, position, type, selected); 1124 dragStartEmitted = true; 1125 } 1126 const handler = tool && tool()?.onDrag; 1127 if (handler) { 1128 handler(e, id, position, type, selected); 1129 } 1130 } 1131 } 1132 }, 1133 onDragEnd: (e, id, position, type, selected, label3) => { 1134 if (dragStartEmitted) { 1135 const handler = tool && tool()?.onDragEnd; 1136 if (handler) { 1137 handler(e, id, position, type, selected, label3); 1138 } 1139 dragStartEmitted = false; 1140 } else { 1141 const handler = tool && tool()?.onClick; 1142 const deltaT = e.timeStamp - lastPointerDown?.timeStamp; 1143 if (handler && deltaT < MAX_CLICK_DURATION) { 1144 handler(id, position, type, selected, label3); 1145 } 1146 } 1147 lastPointerDown = null; 1148 }, 1149 onTrackballEnd: () => { 1150 const handler = tool && tool()?.onTrackballEnd; 1151 if (handler) { 1152 handler(); 1153 } 1154 }, 1155 onContextMenu: (id, position, type, selected, label3) => tool()?.onContextMenu && tool().onContextMenu(id, position, type, selected, label3) 1156 }; 1157 return createComponent(InteractionToolContext.Provider, { 1158 value: [wrappedTool, setTool], 1159 get children() { 1160 return props.children; 1161 } 1162 }); 1163}; 1164var useInteractionTool = () => { 1165 return useContext(InteractionToolContext); 1166}; 1167
1168// src/viewer/context/export.jsx 1169var GltfExportContext = createContext({ 1170 setExporter: () => { 1171 }, 1172 exporter: () => { 1173 } 1174}); 1175var GltfExportProvider = (props) => { 1176 const [exporter, setExporter] = createSignal({}); 1177 return createComponent(GltfExportContext.Provider, { 1178 value: { 1179 exporter, 1180 setExporter 1181 }, 1182 get children() { 1183 return props.children; 1184 } 1185 }); 1186}; 1187var useGltfExporter = () => { 1188 return useContext(GltfExportContext); 1189}; 1190var ImageCaptureContext = createContext({ 1191 setCapturer: () => { 1192 }, 1193 capturer: () => { 1194 } 1195}); 1196var ImageCaptureProvider = (props) => { 1197 const [capturer, setCapturer] = createSignal({}); 1198 const captureImage = (format, params) => { 1199 return new Promise((resolve, reject) => { 1200 try { 1201 capturer().capture(format, resolve); 1202 } catch (error2) { 1203 reject(error2); 1204 } 1205 }); 1206 }; 1207 return createComponent(ImageCaptureContext.Provider, { 1208 value: { 1209 setCapturer, 1210 captureImage 1211 }, 1212 get children() { 1213 return props.children; 1214 } 1215 }); 1216}; 1217var useImageCapture = () => { 1218 return useContext(ImageCaptureContext); 1219}; 1220
vendor: 1,595,181 bytes, lines 1221-44227
1221// node_modules/three/build/three.webgpu.js 1222var refreshUniforms = [ 1223 "alphaMap", 1224 "alphaTest", 1225 "anisotropy", 1226 "anisotropyMap", 1227 "anisotropyRotation", 1228 "aoMap", 1229 "aoMapIntensity", 1230 "attenuationColor", 1231 "attenuationDistance", 1232 "bumpMap", 1233 "clearcoat", 1234 "clearcoatMap", 1235 "clearcoatNormalMap", 1236 "clearcoatNormalScale", 1237 "clearcoatRoughness", 1238 "color", 1239 "dispersion", 1240 "displacementMap", 1241 "emissive", 1242 "emissiveIntensity", 1243 "emissiveMap", 1244 "envMap", 1245 "envMapIntensity", 1246 "gradientMap", 1247 "ior", 1248 "iridescence", 1249 "iridescenceIOR", 1250 "iridescenceMap", 1251 "iridescenceThicknessMap", 1252 "lightMap", 1253 "lightMapIntensity", 1254 "map", 1255 "matcap", 1256 "metalness", 1257 "metalnessMap", 1258 "normalMap", 1259 "normalScale", 1260 "opacity", 1261 "roughness", 1262 "roughnessMap", 1263 "sheen", 1264 "sheenColor", 1265 "sheenColorMap", 1266 "sheenRoughnessMap", 1267 "shininess", 1268 "specular", 1269 "specularColor", 1270 "specularColorMap", 1271 "specularIntensity", 1272 "specularIntensityMap", 1273 "specularMap", 1274 "thickness", 1275 "transmission", 1276 "transmissionMap" 1277]; 1278var _lightsCache = /* @__PURE__ */ new WeakMap(); 1279var _materialCache = /* @__PURE__ */ new WeakMap(); 1280var _geometryCache = /* @__PURE__ */ new WeakMap(); 1281var NodeMaterialObserver = class { 1282 /** 1283 * Constructs a new node material observer. 1284 * 1285 * @param {NodeBuilder} builder - The node builder. 1286 */ 1287 constructor(builder) { 1288 this.renderObjects = /* @__PURE__ */ new WeakMap(); 1289 this.hasNode = this.containsNode(builder); 1290 this.hasAnimation = builder.object.isSkinnedMesh === true; 1291 this.refreshUniforms = refreshUniforms; 1292 this.renderId = 0; 1293 } 1294 /** 1295 * Returns `true` if the given render object is verified for the first time of this observer. 1296 * 1297 * @param {RenderObject} renderObject - The render object. 1298 * @return {boolean} Whether the given render object is verified for the first time of this observer. 1299 */ 1300 firstInitialization(renderObject) { 1301 const hasInitialized = this.renderObjects.has(renderObject); 1302 if (hasInitialized === false) { 1303 this.getRenderObjectData(renderObject); 1304 return true; 1305 } 1306 return false; 1307 } 1308 /** 1309 * Returns `true` if the current rendering produces motion vectors. 1310 * 1311 * @param {Renderer} renderer - The renderer. 1312 * @return {boolean} Whether the current rendering produces motion vectors or not. 1313 */ 1314 needsVelocity(renderer) { 1315 const mrt3 = renderer.getMRT(); 1316 return mrt3 !== null && mrt3.has("velocity"); 1317 } 1318 /** 1319 * Returns monitoring data for the given render object. 1320 * 1321 * @param {RenderObject} renderObject - The render object. 1322 * @return {Object} The monitoring data. 1323 */ 1324 getRenderObjectData(renderObject) { 1325 let data = this.renderObjects.get(renderObject); 1326 if (data === void 0) { 1327 const { geometry, object } = renderObject; 1328 data = { 1329 geometryId: geometry.id, 1330 worldMatrix: object.matrixWorld.clone() 1331 }; 1332 if (object.center) { 1333 data.center = object.center.clone(); 1334 } 1335 if (object.morphTargetInfluences) { 1336 data.morphTargetInfluences = object.morphTargetInfluences.slice(); 1337 } 1338 if (renderObject.bundle !== null) { 1339 data.version = renderObject.bundle.version; 1340 } 1341 if (renderObject.material.transmission > 0) { 1342 const { width, height } = renderObject.context; 1343 data.bufferWidth = width; 1344 data.bufferHeight = height; 1345 } 1346 data.lights = this.getLightsData(renderObject.lightsNode.getLights()); 1347 this.renderObjects.set(renderObject, data); 1348 } 1349 return data; 1350 } 1351 /** 1352 * Returns an attribute data structure holding the attributes versions for 1353 * monitoring. 1354 * 1355 * @param {Object} attributes - The geometry attributes. 1356 * @return {Object} An object for monitoring the versions of attributes. 1357 */ 1358 getAttributesData(attributes) { 1359 const attributesData = {}; 1360 for (const name in attributes) { 1361 const attribute3 = attributes[name]; 1362 attributesData[name] = { 1363 id: attribute3.id, 1364 version: attribute3.version 1365 }; 1366 } 1367 return attributesData; 1368 } 1369 /** 1370 * Returns `true` if the node builder's material uses 1371 * node properties. 1372 * 1373 * @param {NodeBuilder} builder - The current node builder. 1374 * @return {boolean} Whether the node builder's material uses node properties or not. 1375 */ 1376 containsNode(builder) { 1377 const material = builder.material; 1378 for (const property3 in material) { 1379 if (material[property3] && material[property3].isNode) 1380 return true; 1381 } 1382 if (builder.context.modelViewMatrix || builder.context.modelNormalViewMatrix || builder.context.getAO || builder.context.getShadow) 1383 return true; 1384 return false; 1385 } 1386 /** 1387 * Returns a geometry data structure holding the geometry property values for 1388 * monitoring. 1389 * 1390 * @param {BufferGeometry} geometry - The geometry. 1391 * @return {Object} An object for monitoring geometry properties. 1392 */ 1393 getGeometryData(geometry) { 1394 let data = _geometryCache.get(geometry); 1395 if (data === void 0) { 1396 data = { 1397 _renderId: -1, 1398 _equal: false, 1399 attributes: this.getAttributesData(geometry.attributes), 1400 indexId: geometry.index ? geometry.index.id : null, 1401 indexVersion: geometry.index ? geometry.index.version : null, 1402 drawRange: { start: geometry.drawRange.start, count: geometry.drawRange.count } 1403 }; 1404 _geometryCache.set(geometry, data); 1405 } 1406 return data; 1407 } 1408 /** 1409 * Returns a material data structure holding the material property values for 1410 * monitoring. 1411 * 1412 * @param {Material} material - The material. 1413 * @return {Object} An object for monitoring material properties. 1414 */ 1415 getMaterialData(material) { 1416 let data = _materialCache.get(material); 1417 if (data === void 0) { 1418 data = { _renderId: -1, _equal: false }; 1419 for (const property3 of this.refreshUniforms) { 1420 const value = material[property3]; 1421 if (value === null || value === void 0) continue; 1422 if (typeof value === "object" && value.clone !== void 0) { 1423 if (value.isTexture === true) { 1424 data[property3] = { id: value.id, version: value.version }; 1425 } else { 1426 data[property3] = value.clone(); 1427 } 1428 } else { 1429 data[property3] = value; 1430 } 1431 } 1432 _materialCache.set(material, data); 1433 } 1434 return data; 1435 } 1436 /** 1437 * Returns `true` if the given render object has not changed its state. 1438 * 1439 * @param {RenderObject} renderObject - The render object. 1440 * @param {Array<Light>} lightsData - The current material lights. 1441 * @param {number} renderId - The current render ID. 1442 * @return {boolean} Whether the given render object has changed its state or not. 1443 */ 1444 equals(renderObject, lightsData, renderId) { 1445 const { object, material, geometry } = renderObject; 1446 const renderObjectData = this.getRenderObjectData(renderObject); 1447 if (renderObjectData.worldMatrix.equals(object.matrixWorld) !== true) { 1448 renderObjectData.worldMatrix.copy(object.matrixWorld); 1449 return false; 1450 } 1451 const materialData = this.getMaterialData(renderObject.material); 1452 if (materialData._renderId !== renderId) { 1453 materialData._renderId = renderId; 1454 for (const property3 in materialData) { 1455 const value = materialData[property3]; 1456 const mtlValue = material[property3]; 1457 if (property3 === "_renderId") continue; 1458 if (property3 === "_equal") continue; 1459 if (value.equals !== void 0) { 1460 if (value.equals(mtlValue) === false) { 1461 value.copy(mtlValue); 1462 materialData._equal = false; 1463 return false; 1464 } 1465 } else if (mtlValue.isTexture === true) { 1466 if (value.id !== mtlValue.id || value.version !== mtlValue.version) { 1467 value.id = mtlValue.id; 1468 value.version = mtlValue.version; 1469 materialData._equal = false; 1470 return false; 1471 } 1472 } else if (value !== mtlValue) { 1473 materialData[property3] = mtlValue; 1474 materialData._equal = false; 1475 return false; 1476 } 1477 } 1478 if (materialData.transmission > 0) { 1479 const { width, height } = renderObject.context; 1480 if (renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height) { 1481 renderObjectData.bufferWidth = width; 1482 renderObjectData.bufferHeight = height; 1483 materialData._equal = false; 1484 return false; 1485 } 1486 } 1487 materialData._equal = true; 1488 } else { 1489 if (materialData._equal === false) return false; 1490 } 1491 if (renderObjectData.geometryId !== geometry.id) { 1492 renderObjectData.geometryId = geometry.id; 1493 return false; 1494 } 1495 const geometryData = this.getGeometryData(renderObject.geometry); 1496 if (geometryData._renderId !== renderId) { 1497 geometryData._renderId = renderId; 1498 const attributes = geometry.attributes; 1499 const storedAttributes = geometryData.attributes; 1500 let currentAttributeCount = 0; 1501 let storedAttributeCount = 0; 1502 for (const _ in attributes) currentAttributeCount++; 1503 for (const name in storedAttributes) { 1504 storedAttributeCount++; 1505 const storedAttributeData = storedAttributes[name]; 1506 const attribute3 = attributes[name]; 1507 if (attribute3 === void 0) { 1508 delete storedAttributes[name]; 1509 geometryData._equal = false; 1510 return false; 1511 } 1512 if (storedAttributeData.id !== attribute3.id || storedAttributeData.version !== attribute3.version) { 1513 storedAttributeData.id = attribute3.id; 1514 storedAttributeData.version = attribute3.version; 1515 geometryData._equal = false; 1516 return false; 1517 } 1518 } 1519 if (storedAttributeCount !== currentAttributeCount) { 1520 geometryData.attributes = this.getAttributesData(attributes); 1521 geometryData._equal = false; 1522 return false; 1523 } 1524 const index = geometry.index; 1525 const storedIndexId = geometryData.indexId; 1526 const storedIndexVersion = geometryData.indexVersion; 1527 const currentIndexId = index ? index.id : null; 1528 const currentIndexVersion = index ? index.version : null; 1529 if (storedIndexId !== currentIndexId || storedIndexVersion !== currentIndexVersion) { 1530 geometryData.indexId = currentIndexId; 1531 geometryData.indexVersion = currentIndexVersion; 1532 geometryData._equal = false; 1533 return false; 1534 } 1535 if (geometryData.drawRange.start !== geometry.drawRange.start || geometryData.drawRange.count !== geometry.drawRange.count) { 1536 geometryData.drawRange.start = geometry.drawRange.start; 1537 geometryData.drawRange.count = geometry.drawRange.count; 1538 geometryData._equal = false; 1539 return false; 1540 } 1541 geometryData._equal = true; 1542 } else { 1543 if (geometryData._equal === false) return false; 1544 } 1545 if (renderObjectData.morphTargetInfluences) { 1546 let morphChanged = false; 1547 for (let i = 0; i < renderObjectData.morphTargetInfluences.length; i++) { 1548 if (renderObjectData.morphTargetInfluences[i] !== object.morphTargetInfluences[i]) { 1549 renderObjectData.morphTargetInfluences[i] = object.morphTargetInfluences[i]; 1550 morphChanged = true; 1551 } 1552 } 1553 if (morphChanged) return false; 1554 } 1555 if (renderObjectData.lights) { 1556 for (let i = 0; i < lightsData.length; i++) { 1557 if (renderObjectData.lights[i].map !== lightsData[i].map) { 1558 return false; 1559 } 1560 } 1561 } 1562 if (renderObjectData.center) { 1563 if (renderObjectData.center.equals(object.center) === false) { 1564 renderObjectData.center.copy(object.center); 1565 return true; 1566 } 1567 } 1568 if (renderObject.bundle !== null) { 1569 renderObjectData.version = renderObject.bundle.version; 1570 } 1571 return true; 1572 } 1573 /** 1574 * Returns the lights data for the given material lights. 1575 * 1576 * @param {Array<Light>} materialLights - The material lights. 1577 * @return {Array<Object>} The lights data for the given material lights. 1578 */ 1579 getLightsData(materialLights) { 1580 const lights3 = []; 1581 for (const light of materialLights) { 1582 if (light.isSpotLight === true && light.map !== null) { 1583 lights3.push({ map: light.map.version }); 1584 } 1585 } 1586 return lights3; 1587 } 1588 /** 1589 * Returns the lights for the given lights node and render ID. 1590 * 1591 * @param {LightsNode} lightsNode - The lights node. 1592 * @param {number} renderId - The render ID. 1593 * @return {Array<Object>} The lights for the given lights node and render ID. 1594 */ 1595 getLights(lightsNode, renderId) { 1596 if (_lightsCache.has(lightsNode)) { 1597 const cached = _lightsCache.get(lightsNode); 1598 if (cached.renderId === renderId) { 1599 return cached.lightsData; 1600 } 1601 } 1602 const lightsData = this.getLightsData(lightsNode.getLights()); 1603 _lightsCache.set(lightsNode, { renderId, lightsData }); 1604 return lightsData; 1605 } 1606 /** 1607 * Checks if the given render object requires a refresh. 1608 * 1609 * @param {RenderObject} renderObject - The render object. 1610 * @param {NodeFrame} nodeFrame - The current node frame. 1611 * @return {boolean} Whether the given render object requires a refresh or not. 1612 */ 1613 needsRefresh(renderObject, nodeFrame) { 1614 if (this.hasNode || this.hasAnimation || this.firstInitialization(renderObject) || this.needsVelocity(nodeFrame.renderer)) 1615 return true; 1616 const { renderId } = nodeFrame; 1617 if (this.renderId !== renderId) { 1618 this.renderId = renderId; 1619 return true; 1620 } 1621 const isStatic = renderObject.object.static === true; 1622 const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData(renderObject).version === renderObject.bundle.version; 1623 if (isStatic || isBundle) 1624 return false; 1625 const lightsData = this.getLights(renderObject.lightsNode, renderId); 1626 const notEqual3 = this.equals(renderObject, lightsData, renderId) !== true; 1627 return notEqual3; 1628 } 1629}; 1630var IGNORED_FILES = [ 1631 /^StackTrace\.js$/, 1632 /^TSLCore\.js$/, 1633 /^.*Node\.js$/, 1634 /^three\.webgpu.*\.js$/ 1635]; 1636function getFilteredStack(stack3) { 1637 const regex = /(?:at\s+(.+?)\s+\()?(?:(.+?)@)?([^@\s()]+):(\d+):(\d+)/; 1638 return stack3.split("\n").map((line) => { 1639 const match = line.match(regex); 1640 if (!match) return null; 1641 const fn = match[1] || match[2] || ""; 1642 const file = match[3].split("?")[0]; 1643 const lineNum = parseInt(match[4], 10); 1644 const column = parseInt(match[5], 10); 1645 const fileName = file.split("/").pop(); 1646 return { 1647 fn, 1648 file: fileName, 1649 line: lineNum, 1650 column 1651 }; 1652 }).filter((frame) => { 1653 return frame && !IGNORED_FILES.some((regex2) => regex2.test(frame.file)); 1654 }); 1655} 1656var StackTrace = class { 1657 /** 1658 * Creates a StackTrace instance by capturing and filtering the current stack trace. 1659 * 1660 * @param {Error|string|null} stackMessage - An optional stack trace to use instead of capturing a new one. 1661 */ 1662 constructor(stackMessage = null) { 1663 this.isStackTrace = true; 1664 this.stack = getFilteredStack(stackMessage ? stackMessage : new Error().stack); 1665 } 1666 /** 1667 * Returns a formatted location string of the top stack frame. 1668 * 1669 * @returns {string} The formatted stack trace message. 1670 */ 1671 getLocation() { 1672 if (this.stack.length === 0) { 1673 return "[Unknown location]"; 1674 } 1675 const mainStack = this.stack[0]; 1676 const fn = mainStack.fn; 1677 const fnName = fn ? `"${fn}()" at ` : ""; 1678 return `${fnName}"${mainStack.file}:${mainStack.line}"`; 1679 } 1680 /** 1681 * Returns the full error message including the stack trace. 1682 * 1683 * @param {string} message - The error message. 1684 * @returns {string} The full error message with stack trace. 1685 */ 1686 getError(message) { 1687 if (this.stack.length === 0) { 1688 return message; 1689 } 1690 const stackString = this.stack.map((frame) => { 1691 const location = `${frame.file}:${frame.line}:${frame.column}`; 1692 if (frame.fn) { 1693 return ` at ${frame.fn} (${location})`; 1694 } 1695 return ` at ${location}`; 1696 }).join("\n"); 1697 return `${message} 1698${stackString}`; 1699 } 1700}; 1701function cyrb53(value, seed = 0) { 1702 let h12 = 3735928559 ^ seed, h2 = 1103547991 ^ seed; 1703 if (Array.isArray(value)) { 1704 for (let i = 0, val; i < value.length; i++) { 1705 val = value[i]; 1706 h12 = Math.imul(h12 ^ val, 2654435761); 1707 h2 = Math.imul(h2 ^ val, 1597334677); 1708 } 1709 } else { 1710 for (let i = 0, ch; i < value.length; i++) { 1711 ch = value.charCodeAt(i); 1712 h12 = Math.imul(h12 ^ ch, 2654435761); 1713 h2 = Math.imul(h2 ^ ch, 1597334677); 1714 } 1715 } 1716 h12 = Math.imul(h12 ^ h12 >>> 16, 2246822507); 1717 h12 ^= Math.imul(h2 ^ h2 >>> 13, 3266489909); 1718 h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507); 1719 h2 ^= Math.imul(h12 ^ h12 >>> 13, 3266489909); 1720 return 4294967296 * (2097151 & h2) + (h12 >>> 0); 1721} 1722var hashString = (str) => cyrb53(str); 1723var hashArray = (array3) => cyrb53(array3); 1724var hash$1 = (...params) => cyrb53(params); 1725var typeFromLength = /* @__PURE__ */ new Map([ 1726 [1, "float"], 1727 [2, "vec2"], 1728 [3, "vec3"], 1729 [4, "vec4"], 1730 [9, "mat3"], 1731 [16, "mat4"] 1732]); 1733var dataFromObject = /* @__PURE__ */ new WeakMap(); 1734function getTypeFromLength(length3) { 1735 return typeFromLength.get(length3); 1736} 1737function getTypedArrayFromType(type) { 1738 if (/[iu]?vec\d/.test(type)) { 1739 if (type.startsWith("ivec")) return Int32Array; 1740 if (type.startsWith("uvec")) return Uint32Array; 1741 return Float32Array; 1742 } 1743 if (/mat\d/.test(type)) return Float32Array; 1744 if (/float/.test(type)) return Float32Array; 1745 if (/uint/.test(type)) return Uint32Array; 1746 if (/int/.test(type)) return Int32Array; 1747 throw new Error(`THREE.NodeUtils: Unsupported type: ${type}`); 1748} 1749function getLengthFromType(type) { 1750 if (/float|int|uint/.test(type)) return 1; 1751 if (/vec2/.test(type)) return 2; 1752 if (/vec3/.test(type)) return 3; 1753 if (/vec4/.test(type)) return 4; 1754 if (/mat2/.test(type)) return 4; 1755 if (/mat3/.test(type)) return 9; 1756 if (/mat4/.test(type)) return 16; 1757 error(`TSL: Unsupported type: ${type}`, new StackTrace()); 1758} 1759function getMemoryLengthFromType(type) { 1760 if (/float|int|uint/.test(type)) return 1; 1761 if (/vec2/.test(type)) return 2; 1762 if (/vec3/.test(type)) return 3; 1763 if (/vec4/.test(type)) return 4; 1764 if (/mat2/.test(type)) return 4; 1765 if (/mat3/.test(type)) return 12; 1766 if (/mat4/.test(type)) return 16; 1767 error(`TSL: Unsupported type: ${type}`, new StackTrace()); 1768} 1769function getAlignmentFromType(type) { 1770 if (/float|int|uint/.test(type)) return 4; 1771 if (/vec2/.test(type)) return 8; 1772 if (/vec3/.test(type)) return 16; 1773 if (/vec4/.test(type)) return 16; 1774 if (/mat2/.test(type)) return 8; 1775 if (/mat3/.test(type)) return 16; 1776 if (/mat4/.test(type)) return 16; 1777 error(`TSL: Unsupported type: ${type}`, new StackTrace()); 1778} 1779function getValueType(value) { 1780 if (value === void 0 || value === null) return null; 1781 const typeOf = typeof value; 1782 if (value.isNode === true) { 1783 return "node"; 1784 } else if (typeOf === "number") { 1785 return "float"; 1786 } else if (typeOf === "boolean") { 1787 return "bool"; 1788 } else if (typeOf === "string") { 1789 return "string"; 1790 } else if (typeOf === "function") { 1791 return "shader"; 1792 } else if (value.isVector2 === true) { 1793 return "vec2"; 1794 } else if (value.isVector3 === true) { 1795 return "vec3"; 1796 } else if (value.isVector4 === true) { 1797 return "vec4"; 1798 } else if (value.isMatrix2 === true) { 1799 return "mat2"; 1800 } else if (value.isMatrix3 === true) { 1801 return "mat3"; 1802 } else if (value.isMatrix4 === true) { 1803 return "mat4"; 1804 } else if (value.isColor === true) { 1805 return "color"; 1806 } else if (value instanceof ArrayBuffer) { 1807 return "ArrayBuffer"; 1808 } 1809 return null; 1810} 1811function getValueFromType(type, ...params) { 1812 const last4 = type ? type.slice(-4) : void 0; 1813 if (params.length === 1) { 1814 if (last4 === "vec2") params = [params[0], params[0]]; 1815 else if (last4 === "vec3") params = [params[0], params[0], params[0]]; 1816 else if (last4 === "vec4") params = [params[0], params[0], params[0], params[0]]; 1817 } 1818 if (type === "color") { 1819 return new Color(...params); 1820 } else if (last4 === "vec2") { 1821 return new Vector2(...params); 1822 } else if (last4 === "vec3") { 1823 return new Vector3(...params); 1824 } else if (last4 === "vec4") { 1825 return new Vector4(...params); 1826 } else if (last4 === "mat2") { 1827 return new Matrix2(...params); 1828 } else if (last4 === "mat3") { 1829 return new Matrix3(...params); 1830 } else if (last4 === "mat4") { 1831 return new Matrix4(...params); 1832 } else if (type === "bool") { 1833 return params[0] || false; 1834 } else if (type === "float" || type === "int" || type === "uint") { 1835 return params[0] || 0; 1836 } else if (type === "string") { 1837 return params[0] || ""; 1838 } else if (type === "ArrayBuffer") { 1839 return base64ToArrayBuffer(params[0]); 1840 } 1841 return null; 1842} 1843function getDataFromObject(object) { 1844 let data = dataFromObject.get(object); 1845 if (data === void 0) { 1846 data = {}; 1847 dataFromObject.set(object, data); 1848 } 1849 return data; 1850} 1851function arrayBufferToBase64(arrayBuffer3) { 1852 let chars = ""; 1853 const array3 = new Uint8Array(arrayBuffer3); 1854 for (let i = 0; i < array3.length; i++) { 1855 chars += String.fromCharCode(array3[i]); 1856 } 1857 return btoa(chars); 1858} 1859function base64ToArrayBuffer(base64) { 1860 return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)).buffer; 1861} 1862var NodeShaderStage = { 1863 VERTEX: "vertex", 1864 FRAGMENT: "fragment" 1865}; 1866var NodeUpdateType = { 1867 NONE: "none", 1868 FRAME: "frame", 1869 RENDER: "render", 1870 OBJECT: "object" 1871}; 1872var NodeType = { 1873 BOOLEAN: "bool", 1874 INTEGER: "int", 1875 FLOAT: "float", 1876 VECTOR2: "vec2", 1877 VECTOR3: "vec3", 1878 VECTOR4: "vec4", 1879 MATRIX2: "mat2", 1880 MATRIX3: "mat3", 1881 MATRIX4: "mat4" 1882}; 1883var NodeAccess = { 1884 READ_ONLY: "readOnly", 1885 WRITE_ONLY: "writeOnly", 1886 READ_WRITE: "readWrite" 1887}; 1888var defaultShaderStages = ["fragment", "vertex"]; 1889var defaultBuildStages = ["setup", "analyze", "generate"]; 1890var shaderStages = [...defaultShaderStages, "compute"]; 1891var vectorComponents = ["x", "y", "z", "w"]; 1892var _parentBuildStage = { 1893 analyze: "setup", 1894 generate: "analyze" 1895}; 1896var _nodeId = 0; 1897var Node2 = class _Node extends EventDispatcher { 1898 static get type() { 1899 return "Node"; 1900 } 1901 /** 1902 * Constructs a new node. 1903 * 1904 * @param {?string} nodeType - The node type. 1905 */ 1906 constructor(nodeType = null) { 1907 super(); 1908 this.nodeType = nodeType; 1909 this.updateType = NodeUpdateType.NONE; 1910 this.updateBeforeType = NodeUpdateType.NONE; 1911 this.updateAfterType = NodeUpdateType.NONE; 1912 this.version = 0; 1913 this.name = ""; 1914 this.global = false; 1915 this.parents = false; 1916 this.isNode = true; 1917 this._beforeNodes = null; 1918 this._cacheKey = null; 1919 this._uuid = null; 1920 this._cacheKeyVersion = 0; 1921 this.id = _nodeId++; 1922 this.stackTrace = null; 1923 if (_Node.captureStackTrace === true) { 1924 this.stackTrace = new StackTrace(); 1925 } 1926 } 1927 /** 1928 * Set this property to `true` when the node should be regenerated. 1929 * 1930 * @type {boolean} 1931 * @default false 1932 * @param {boolean} value 1933 */ 1934 set needsUpdate(value) { 1935 if (value === true) { 1936 this.version++; 1937 } 1938 } 1939 /** 1940 * The UUID of the node. 1941 * 1942 * @type {string} 1943 * @readonly 1944 */ 1945 get uuid() { 1946 if (this._uuid === null) { 1947 this._uuid = MathUtils.generateUUID(); 1948 } 1949 return this._uuid; 1950 } 1951 /** 1952 * The type of the class. The value is usually the constructor name. 1953 * 1954 * @type {string} 1955 * @readonly 1956 */ 1957 get type() { 1958 return this.constructor.type; 1959 } 1960 /** 1961 * Convenient method for defining {@link Node#update}. 1962 * 1963 * @param {Function} callback - The update method. 1964 * @param {string} updateType - The update type. 1965 * @return {Node} A reference to this node. 1966 */ 1967 onUpdate(callback, updateType) { 1968 this.updateType = updateType; 1969 this.update = callback.bind(this); 1970 return this; 1971 } 1972 /** 1973 * Convenient method for defining {@link Node#update}. Similar to {@link Node#onUpdate}, but 1974 * this method automatically sets the update type to `FRAME`. 1975 * 1976 * @param {Function} callback - The update method. 1977 * @return {Node} A reference to this node. 1978 */ 1979 onFrameUpdate(callback) { 1980 return this.onUpdate(callback, NodeUpdateType.FRAME); 1981 } 1982 /** 1983 * Convenient method for defining {@link Node#update}. Similar to {@link Node#onUpdate}, but 1984 * this method automatically sets the update type to `RENDER`. 1985 * 1986 * @param {Function} callback - The update method. 1987 * @return {Node} A reference to this node. 1988 */ 1989 onRenderUpdate(callback) { 1990 return this.onUpdate(callback, NodeUpdateType.RENDER); 1991 } 1992 /** 1993 * Convenient method for defining {@link Node#update}. Similar to {@link Node#onUpdate}, but 1994 * this method automatically sets the update type to `OBJECT`. 1995 * 1996 * @param {Function} callback - The update method. 1997 * @return {Node} A reference to this node. 1998 */ 1999 onObjectUpdate(callback) { 2000 return this.onUpdate(callback, NodeUpdateType.OBJECT); 2001 } 2002 /** 2003 * Convenient method for defining {@link Node#updateReference}. 2004 * 2005 * @param {Function} callback - The update method. 2006 * @return {Node} A reference to this node. 2007 */ 2008 onReference(callback) { 2009 this.updateReference = callback.bind(this); 2010 return this; 2011 } 2012 /** 2013 * Nodes might refer to other objects like materials. This method allows to dynamically update the reference 2014 * to such objects based on a given state (e.g. the current node frame or builder). 2015 * 2016 * @param {any} state - This method can be invocated in different contexts so `state` can refer to any object type. 2017 * @return {any} The updated reference. 2018 */ 2019 updateReference() { 2020 return this; 2021 } 2022 /** 2023 * By default this method returns the value of the {@link Node#global} flag. This method 2024 * can be overwritten in derived classes if an analytical way is required to determine the 2025 * global cache referring to the current shader-stage. 2026 * 2027 * @param {NodeBuilder} builder - The current node builder. 2028 * @return {boolean} Whether this node is global or not. 2029 */ 2030 isGlobal() { 2031 return this.global; 2032 } 2033 /** 2034 * Generator function that can be used to iterate over the child nodes. 2035 * 2036 * @generator 2037 * @yields {Node} A child node. 2038 */ 2039 *getChildren() { 2040 for (const { childNode } of this._getChildren()) { 2041 yield childNode; 2042 } 2043 } 2044 /** 2045 * Calling this method dispatches the `dispose` event. This event can be used 2046 * to register event listeners for clean up tasks. 2047 */ 2048 dispose() { 2049 this.dispatchEvent({ type: "dispose" }); 2050 } 2051 /** 2052 * Callback for {@link Node#traverse}. 2053 * 2054 * @callback traverseCallback 2055 * @param {Node} node - The current node. 2056 */ 2057 /** 2058 * Can be used to traverse through the node's hierarchy. 2059 * 2060 * @param {traverseCallback} callback - A callback that is executed per node. 2061 */ 2062 traverse(callback) { 2063 callback(this); 2064 for (const childNode of this.getChildren()) { 2065 childNode.traverse(callback); 2066 } 2067 } 2068 /** 2069 * Returns the child nodes of this node. 2070 * 2071 * @private 2072 * @param {Set<Node>} [ignores=new Set()] - A set of nodes to ignore during the search to avoid circular references. 2073 * @returns {Array<Object>} An array of objects describing the child nodes. 2074 */ 2075 _getChildren(ignores = /* @__PURE__ */ new Set()) { 2076 const children2 = []; 2077 ignores.add(this); 2078 for (const property3 of Object.getOwnPropertyNames(this)) { 2079 const object = this[property3]; 2080 if (property3.startsWith("_") === true || ignores.has(object)) continue; 2081 if (Array.isArray(object) === true) { 2082 for (let i = 0; i < object.length; i++) { 2083 const child = object[i]; 2084 if (child && child.isNode === true) { 2085 children2.push({ property: property3, index: i, childNode: child }); 2086 } 2087 } 2088 } else if (object && object.isNode === true) { 2089 children2.push({ property: property3, childNode: object }); 2090 } else if (object && Object.getPrototypeOf(object) === Object.prototype) { 2091 for (const subProperty in object) { 2092 if (subProperty.startsWith("_") === true) continue; 2093 const child = object[subProperty]; 2094 if (child && child.isNode === true) { 2095 children2.push({ property: property3, index: subProperty, childNode: child }); 2096 } 2097 } 2098 } 2099 } 2100 return children2; 2101 } 2102 /** 2103 * Returns the cache key for this node. 2104 * 2105 * @param {boolean} [force=false] - When set to `true`, a recomputation of the cache key is forced. 2106 * @param {Set<Node>} [ignores=null] - A set of nodes to ignore during the computation of the cache key. 2107 * @return {number} The cache key of the node. 2108 */ 2109 getCacheKey(force = false, ignores = null) { 2110 force = force || this.version !== this._cacheKeyVersion; 2111 if (force === true || this._cacheKey === null) { 2112 if (ignores === null) ignores = /* @__PURE__ */ new Set(); 2113 const values = []; 2114 for (const { property: property3, childNode } of this._getChildren(ignores)) { 2115 values.push(hashString(property3.slice(0, -4)), childNode.getCacheKey(force, ignores)); 2116 } 2117 this._cacheKey = hash$1(hashArray(values), this.customCacheKey()); 2118 this._cacheKeyVersion = this.version; 2119 } 2120 return this._cacheKey; 2121 } 2122 /** 2123 * Generate a custom cache key for this node. 2124 * 2125 * @return {number} The cache key of the node. 2126 */ 2127 customCacheKey() { 2128 return this.id; 2129 } 2130 /** 2131 * Returns the references to this node which is by default `this`. 2132 * 2133 * @return {Node} A reference to this node. 2134 */ 2135 getScope() { 2136 return this; 2137 } 2138 /** 2139 * Returns the hash of the node which is used to identify the node. By default it's 2140 * the {@link Node#uuid} however derived node classes might have to overwrite this method 2141 * depending on their implementation. 2142 * 2143 * @param {NodeBuilder} builder - The current node builder. 2144 * @return {string} The hash. 2145 */ 2146 getHash() { 2147 return String(this.id); 2148 } 2149 /** 2150 * Returns the update type of {@link Node#update}. 2151 * 2152 * @return {NodeUpdateType} The update type. 2153 */ 2154 getUpdateType() { 2155 return this.updateType; 2156 } 2157 /** 2158 * Returns the update type of {@link Node#updateBefore}. 2159 * 2160 * @return {NodeUpdateType} The update type. 2161 */ 2162 getUpdateBeforeType() { 2163 return this.updateBeforeType; 2164 } 2165 /** 2166 * Returns the update type of {@link Node#updateAfter}. 2167 * 2168 * @return {NodeUpdateType} The update type. 2169 */ 2170 getUpdateAfterType() { 2171 return this.updateAfterType; 2172 } 2173 /** 2174 * Certain types are composed of multiple elements. For example a `vec3` 2175 * is composed of three `float` values. This method returns the type of 2176 * these elements. 2177 * 2178 * @param {NodeBuilder} builder - The current node builder. 2179 * @return {string} The type of the node. 2180 */ 2181 getElementType(builder) { 2182 const type = this.getNodeType(builder); 2183 const elementType = builder.getElementType(type); 2184 return elementType; 2185 } 2186 /** 2187 * Returns the node member type for the given name. 2188 * 2189 * @param {NodeBuilder} builder - The current node builder. 2190 * @param {string} name - The name of the member. 2191 * @return {string} The type of the node. 2192 */ 2193 getMemberType() { 2194 return "void"; 2195 } 2196 /** 2197 * Returns the node's type. 2198 * 2199 * @param {NodeBuilder} builder - The current node builder. 2200 * @param {string} [output=null] - The output of the node. 2201 * @return {string} The type of the node. 2202 */ 2203 getNodeType(builder, output3 = null) { 2204 const nodeData = builder.getDataFromNode(this); 2205 let type; 2206 if (output3 !== null) { 2207 nodeData.typeFromOutput = nodeData.typeFromOutput || {}; 2208 type = nodeData.typeFromOutput[output3]; 2209 if (type === void 0) { 2210 type = this.generateNodeType(builder, output3); 2211 nodeData.typeFromOutput[output3] = type; 2212 } 2213 } else { 2214 type = nodeData.type; 2215 if (type === void 0) { 2216 type = this.generateNodeType(builder); 2217 nodeData.type = type; 2218 } 2219 } 2220 return type; 2221 } 2222 /** 2223 * Returns the node's type. 2224 * 2225 * @param {NodeBuilder} builder - The current node builder. 2226 * @param {string} [output=null] - The output of the node. 2227 * @return {string} The type of the node. 2228 */ 2229 generateNodeType(builder, output3 = null) { 2230 const nodeProperties = builder.getNodeProperties(this); 2231 if (nodeProperties.outputNode) { 2232 return nodeProperties.outputNode.getNodeType(builder, output3); 2233 } 2234 return this.nodeType; 2235 } 2236 /** 2237 * This method is used during the build process of a node and ensures 2238 * equal nodes are not built multiple times but just once. For example if 2239 * `attribute( 'uv' )` is used multiple times by the user, the build 2240 * process makes sure to process just the first node. 2241 * 2242 * @param {NodeBuilder} builder - The current node builder. 2243 * @return {Node} The shared node if possible. Otherwise `this` is returned. 2244 */ 2245 getShared(builder) { 2246 const hash3 = this.getHash(builder); 2247 const nodeFromHash = builder.getNodeFromHash(hash3); 2248 return nodeFromHash || this; 2249 } 2250 /** 2251 * Returns the number of elements in the node array. 2252 * 2253 * @param {NodeBuilder} builder - The current node builder. 2254 * @return {?number} The number of elements in the node array. 2255 */ 2256 getArrayCount() { 2257 return null; 2258 } 2259 /** 2260 * Represents the setup stage which is the first step of the build process, see {@link Node#build} method. 2261 * This method is often overwritten in derived modules to prepare the node which is used as a node's output/result. 2262 * If an output node is prepared, then it must be returned in the `return` statement of the derived module's setup function. 2263 * 2264 * @param {NodeBuilder} builder - The current node builder. 2265 * @return {?Node} The output node. 2266 */ 2267 setup(builder) { 2268 const nodeProperties = builder.getNodeProperties(this); 2269 let index = 0; 2270 for (const childNode of this.getChildren()) { 2271 nodeProperties["node" + index++] = childNode; 2272 } 2273 return nodeProperties.outputNode || null; 2274 } 2275 /** 2276 * Represents the analyze stage which is the second step of the build process, see {@link Node#build} method. 2277 * This stage analyzes the node hierarchy and ensures descendent nodes are built. 2278 * 2279 * @param {NodeBuilder} builder - The current node builder. 2280 * @param {?Node} output - The target output node. 2281 */ 2282 analyze(builder, output3 = null) { 2283 const usageCount = builder.increaseUsage(this); 2284 if (this.parents === true) { 2285 const nodeData = builder.getDataFromNode(this, "any"); 2286 nodeData.stages = nodeData.stages || {}; 2287 nodeData.stages[builder.shaderStage] = nodeData.stages[builder.shaderStage] || []; 2288 nodeData.stages[builder.shaderStage].push(output3); 2289 } 2290 if (usageCount === 1) { 2291 const nodeProperties = builder.getNodeProperties(this); 2292 for (const childNode of Object.values(nodeProperties)) { 2293 if (childNode && childNode.isNode === true) { 2294 childNode.build(builder, this); 2295 } 2296 } 2297 } 2298 } 2299 /** 2300 * Represents the generate stage which is the third step of the build process, see {@link Node#build} method. 2301 * This state builds the output node and returns the resulting shader string. 2302 * 2303 * @param {NodeBuilder} builder - The current node builder. 2304 * @param {?string} [output] - Can be used to define the output type. 2305 * @return {?string} The generated shader string. 2306 */ 2307 generate(builder, output3) { 2308 const { outputNode } = builder.getNodeProperties(this); 2309 if (outputNode && outputNode.isNode === true) { 2310 return outputNode.build(builder, output3); 2311 } 2312 } 2313 /** 2314 * The method can be implemented to update the node's internal state before it is used to render an object. 2315 * The {@link Node#updateBeforeType} property defines how often the update is executed. 2316 * 2317 * @abstract 2318 * @param {NodeFrame} frame - A reference to the current node frame. 2319 * @return {?boolean} An optional bool that indicates whether the implementation actually performed an update or not (e.g. due to caching). 2320 */ 2321 updateBefore() { 2322 warn("Abstract function."); 2323 } 2324 /** 2325 * The method can be implemented to update the node's internal state after it was used to render an object. 2326 * The {@link Node#updateAfterType} property defines how often the update is executed. 2327 * 2328 * @abstract 2329 * @param {NodeFrame} frame - A reference to the current node frame. 2330 * @return {?boolean} An optional bool that indicates whether the implementation actually performed an update or not (e.g. due to caching). 2331 */ 2332 updateAfter() { 2333 warn("Abstract function."); 2334 } 2335 /** 2336 * The method can be implemented to update the node's internal state when it is used to render an object. 2337 * The {@link Node#updateType} property defines how often the update is executed. 2338 * 2339 * @abstract 2340 * @param {NodeFrame} frame - A reference to the current node frame. 2341 * @return {?boolean} An optional bool that indicates whether the implementation actually performed an update or not (e.g. due to caching). 2342 */ 2343 update() { 2344 warn("Abstract function."); 2345 } 2346 before(node) { 2347 if (this._beforeNodes === null) this._beforeNodes = []; 2348 this._beforeNodes.push(node); 2349 return this; 2350 } 2351 /** 2352 * This method performs the build of a node. The behavior and return value depend on the current build stage: 2353 * - **setup**: Prepares the node and its children for the build process. This process can also create new nodes. Returns the node itself or a variant. 2354 * - **analyze**: Analyzes the node hierarchy for optimizations in the code generation stage. Returns `null`. 2355 * - **generate**: Generates the shader code for the node. Returns the generated shader string. 2356 * 2357 * @param {NodeBuilder} builder - The current node builder. 2358 * @param {?(string|Node)} [output=null] - Can be used to define the output type. 2359 * @return {?(Node|string)} The result of the build process, depending on the build stage. 2360 */ 2361 build(builder, output3 = null) { 2362 const refNode = this.getShared(builder); 2363 if (this !== refNode) { 2364 return refNode.build(builder, output3); 2365 } 2366 if (this._beforeNodes !== null) { 2367 const currentBeforeNodes = this._beforeNodes; 2368 this._beforeNodes = null; 2369 for (const beforeNode of currentBeforeNodes) { 2370 beforeNode.build(builder, output3); 2371 } 2372 this._beforeNodes = currentBeforeNodes; 2373 } 2374 const nodeData = builder.getDataFromNode(this); 2375 nodeData.buildStages = nodeData.buildStages || {}; 2376 nodeData.buildStages[builder.buildStage] = true; 2377 const parentBuildStage = _parentBuildStage[builder.buildStage]; 2378 if (parentBuildStage && nodeData.buildStages[parentBuildStage] !== true) { 2379 const previousBuildStage = builder.getBuildStage(); 2380 builder.setBuildStage(parentBuildStage); 2381 this.build(builder); 2382 builder.setBuildStage(previousBuildStage); 2383 } 2384 builder.addChain(this); 2385 let result = null; 2386 const buildStage = builder.getBuildStage(); 2387 if (buildStage === "setup") { 2388 builder.addNode(this); 2389 this.updateReference(builder); 2390 const properties = builder.getNodeProperties(this); 2391 if (properties.initialized !== true) { 2392 properties.initialized = true; 2393 properties.outputNode = this.setup(builder) || properties.outputNode || null; 2394 for (const childNode of Object.values(properties)) { 2395 if (childNode && childNode.isNode === true) { 2396 if (childNode.parents === true) { 2397 const childProperties = builder.getNodeProperties(childNode); 2398 childProperties.parents = childProperties.parents || []; 2399 childProperties.parents.push(this); 2400 } 2401 childNode.build(builder); 2402 } 2403 } 2404 builder.addSequentialNode(this); 2405 } 2406 result = properties.outputNode; 2407 } else if (buildStage === "analyze") { 2408 this.analyze(builder, output3); 2409 } else if (buildStage === "generate") { 2410 const isGenerateOnce = this.generate.length < 2; 2411 if (isGenerateOnce) { 2412 const type = this.getNodeType(builder); 2413 const nodeData2 = builder.getDataFromNode(this); 2414 result = nodeData2.snippet; 2415 if (result === void 0) { 2416 if (nodeData2.generated === void 0) { 2417 nodeData2.generated = true; 2418 result = this.generate(builder) || ""; 2419 nodeData2.snippet = result; 2420 } else { 2421 warn("Node: Recursion detected.", this); 2422 result = "/* Recursion detected. */"; 2423 } 2424 } else if (nodeData2.flowCodes !== void 0 && builder.context.nodeBlock !== void 0) { 2425 builder.addFlowCodeHierarchy(this, builder.context.nodeBlock); 2426 } 2427 result = builder.format(result, type, output3); 2428 } else { 2429 result = this.generate(builder, output3) || ""; 2430 } 2431 if (result === "" && output3 !== null && output3 !== "void" && output3 !== "OutputType") { 2432 error(`TSL: Invalid generated code, expected a "${output3}".`); 2433 result = builder.generateConst(output3); 2434 } 2435 } 2436 builder.removeChain(this); 2437 return result; 2438 } 2439 /** 2440 * Returns the child nodes as a JSON object. 2441 * 2442 * @return {Generator<Object>} An iterable list of serialized child objects as JSON. 2443 */ 2444 getSerializeChildren() { 2445 return this._getChildren(); 2446 } 2447 /** 2448 * Serializes the node to JSON. 2449 * 2450 * @param {Object} json - The output JSON object. 2451 */ 2452 serialize(json) { 2453 const nodeChildren = this.getSerializeChildren(); 2454 const inputNodes = {}; 2455 for (const { property: property3, index, childNode } of nodeChildren) { 2456 if (index !== void 0) { 2457 if (inputNodes[property3] === void 0) { 2458 inputNodes[property3] = Number.isInteger(index) ? [] : {}; 2459 } 2460 inputNodes[property3][index] = childNode.toJSON(json.meta).uuid; 2461 } else { 2462 inputNodes[property3] = childNode.toJSON(json.meta).uuid; 2463 } 2464 } 2465 if (Object.keys(inputNodes).length > 0) { 2466 json.inputNodes = inputNodes; 2467 } 2468 } 2469 /** 2470 * Deserializes the node from the given JSON. 2471 * 2472 * @param {Object} json - The JSON object. 2473 */ 2474 deserialize(json) { 2475 if (json.inputNodes !== void 0) { 2476 const nodes = json.meta.nodes; 2477 for (const property3 in json.inputNodes) { 2478 if (Array.isArray(json.inputNodes[property3])) { 2479 const inputArray = []; 2480 for (const uuid of json.inputNodes[property3]) { 2481 inputArray.push(nodes[uuid]); 2482 } 2483 this[property3] = inputArray; 2484 } else if (typeof json.inputNodes[property3] === "object") { 2485 const inputObject = {}; 2486 for (const subProperty in json.inputNodes[property3]) { 2487 const uuid = json.inputNodes[property3][subProperty]; 2488 inputObject[subProperty] = nodes[uuid]; 2489 } 2490 this[property3] = inputObject; 2491 } else { 2492 const uuid = json.inputNodes[property3]; 2493 this[property3] = nodes[uuid]; 2494 } 2495 } 2496 } 2497 } 2498 /** 2499 * Serializes the node into the three.js JSON Object/Scene format. 2500 * 2501 * @param {?Object} meta - An optional JSON object that already holds serialized data from other scene objects. 2502 * @return {Object} The serialized node. 2503 */ 2504 toJSON(meta) { 2505 const { uuid, type } = this; 2506 const isRoot = meta === void 0 || typeof meta === "string"; 2507 if (isRoot) { 2508 meta = { 2509 textures: {}, 2510 images: {}, 2511 nodes: {} 2512 }; 2513 } 2514 let data = meta.nodes[uuid]; 2515 if (data === void 0) { 2516 data = { 2517 uuid, 2518 type, 2519 meta, 2520 metadata: { 2521 version: 4.7, 2522 type: "Node", 2523 generator: "Node.toJSON" 2524 } 2525 }; 2526 if (isRoot !== true) meta.nodes[data.uuid] = data; 2527 this.serialize(data); 2528 delete data.meta; 2529 } 2530 function extractFromCache(cache4) { 2531 const values = []; 2532 for (const key in cache4) { 2533 const data2 = cache4[key]; 2534 delete data2.metadata; 2535 values.push(data2); 2536 } 2537 return values; 2538 } 2539 if (isRoot) { 2540 const textures = extractFromCache(meta.textures); 2541 const images = extractFromCache(meta.images); 2542 const nodes = extractFromCache(meta.nodes); 2543 if (textures.length > 0) data.textures = textures; 2544 if (images.length > 0) data.images = images; 2545 if (nodes.length > 0) data.nodes = nodes; 2546 } 2547 return data; 2548 } 2549}; 2550Node2.captureStackTrace = false; 2551var ArrayElementNode = class extends Node2 { 2552 // @TODO: If extending from TempNode it breaks webgpu_compute 2553 static get type() { 2554 return "ArrayElementNode"; 2555 } 2556 /** 2557 * Constructs an array element node. 2558 * 2559 * @param {Node} node - The array-like node. 2560 * @param {Node} indexNode - The index node that defines the element access. 2561 */ 2562 constructor(node, indexNode) { 2563 super(); 2564 this.node = node; 2565 this.indexNode = indexNode; 2566 this.isArrayElementNode = true; 2567 } 2568 /** 2569 * This method is overwritten since the node type is inferred from the array-like node. 2570 * 2571 * @param {NodeBuilder} builder - The current node builder. 2572 * @return {string} The node type. 2573 */ 2574 generateNodeType(builder) { 2575 return this.node.getElementType(builder); 2576 } 2577 /** 2578 * This method is overwritten since the member type is inferred from the array-like node. 2579 * 2580 * @param {NodeBuilder} builder - The current node builder. 2581 * @param {string} name - The member name. 2582 * @return {string} The member type. 2583 */ 2584 getMemberType(builder, name) { 2585 return this.node.getMemberType(builder, name); 2586 } 2587 generate(builder) { 2588 const indexType = this.indexNode.getNodeType(builder); 2589 const nodeSnippet = this.node.build(builder); 2590 const indexSnippet = this.indexNode.build(builder, !builder.isVector(indexType) && builder.isInteger(indexType) ? indexType : "uint"); 2591 return `${nodeSnippet}[ ${indexSnippet} ]`; 2592 } 2593}; 2594var ConvertNode = class extends Node2 { 2595 static get type() { 2596 return "ConvertNode"; 2597 } 2598 /** 2599 * Constructs a new convert node. 2600 * 2601 * @param {Node} node - The node which type should be converted. 2602 * @param {string} convertTo - The target node type. Multiple types can be defined by separating them with a `|` sign. 2603 */ 2604 constructor(node, convertTo) { 2605 super(); 2606 this.node = node; 2607 this.convertTo = convertTo; 2608 } 2609 /** 2610 * This method is overwritten since the implementation tries to infer the best 2611 * matching type from the {@link ConvertNode#convertTo} property. 2612 * 2613 * @param {NodeBuilder} builder - The current node builder. 2614 * @return {string} The node type. 2615 */ 2616 generateNodeType(builder) { 2617 const requestType = this.node.getNodeType(builder); 2618 let convertTo = null; 2619 for (const overloadingType of this.convertTo.split("|")) { 2620 if (convertTo === null || builder.getTypeLength(requestType) === builder.getTypeLength(overloadingType)) { 2621 convertTo = overloadingType; 2622 } 2623 } 2624 return convertTo; 2625 } 2626 serialize(data) { 2627 super.serialize(data); 2628 data.convertTo = this.convertTo; 2629 } 2630 deserialize(data) { 2631 super.deserialize(data); 2632 this.convertTo = data.convertTo; 2633 } 2634 generate(builder, output3) { 2635 const node = this.node; 2636 const type = this.getNodeType(builder); 2637 const snippet = node.build(builder, type); 2638 return builder.format(snippet, type, output3); 2639 } 2640}; 2641var TempNode = class extends Node2 { 2642 static get type() { 2643 return "TempNode"; 2644 } 2645 /** 2646 * Constructs a temp node. 2647 * 2648 * @param {?string} nodeType - The node type. 2649 */ 2650 constructor(nodeType = null) { 2651 super(nodeType); 2652 this.isTempNode = true; 2653 } 2654 /** 2655 * Whether this node is used more than once in context of other nodes. 2656 * 2657 * @param {NodeBuilder} builder - The node builder. 2658 * @return {boolean} A flag that indicates if there is more than one dependency to other nodes. 2659 */ 2660 hasDependencies(builder) { 2661 return builder.getDataFromNode(this).usageCount > 1; 2662 } 2663 build(builder, output3) { 2664 const buildStage = builder.getBuildStage(); 2665 if (buildStage === "generate") { 2666 const type = builder.getVectorType(this.getNodeType(builder, output3)); 2667 const nodeData = builder.getDataFromNode(this); 2668 if (nodeData.propertyName !== void 0) { 2669 return builder.format(nodeData.propertyName, type, output3); 2670 } else if (type !== "void" && output3 !== "void" && this.hasDependencies(builder)) { 2671 const snippet = super.build(builder, type); 2672 const nodeVar = builder.getVarFromNode(this, null, type); 2673 const propertyName = builder.getPropertyName(nodeVar); 2674 builder.addLineFlowCode(`${propertyName} = ${snippet}`, this); 2675 nodeData.snippet = snippet; 2676 nodeData.propertyName = propertyName; 2677 return builder.format(nodeData.propertyName, type, output3); 2678 } 2679 } 2680 return super.build(builder, output3); 2681 } 2682}; 2683var JoinNode = class extends TempNode { 2684 static get type() { 2685 return "JoinNode"; 2686 } 2687 /** 2688 * Constructs a new join node. 2689 * 2690 * @param {Array<Node>} nodes - An array of nodes that should be joined. 2691 * @param {?string} [nodeType=null] - The node type. 2692 */ 2693 constructor(nodes = [], nodeType = null) { 2694 super(nodeType); 2695 this.nodes = nodes; 2696 } 2697 /** 2698 * This method is overwritten since the node type must be inferred from the 2699 * joined data length if not explicitly defined. 2700 * 2701 * @param {NodeBuilder} builder - The current node builder. 2702 * @return {string} The node type. 2703 */ 2704 generateNodeType(builder) { 2705 if (this.nodeType !== null) { 2706 return builder.getVectorType(this.nodeType); 2707 } 2708 return builder.getTypeFromLength(this.nodes.reduce((count, cur) => count + builder.getTypeLength(cur.getNodeType(builder)), 0)); 2709 } 2710 generate(builder, output3) { 2711 const type = this.getNodeType(builder); 2712 const maxLength = builder.getTypeLength(type); 2713 const nodes = this.nodes; 2714 const primitiveType = builder.getComponentType(type); 2715 const snippetValues = []; 2716 let length3 = 0; 2717 for (const input of nodes) { 2718 if (length3 >= maxLength) { 2719 error(`TSL: Length of parameters exceeds maximum length of function '${type}()' type.`, this.stackTrace); 2720 break; 2721 } 2722 let inputType = input.getNodeType(builder); 2723 let inputTypeLength = builder.getTypeLength(inputType); 2724 let inputSnippet; 2725 if (length3 + inputTypeLength > maxLength) { 2726 error(`TSL: Length of '${type}()' data exceeds maximum length of output type.`, this.stackTrace); 2727 inputTypeLength = maxLength - length3; 2728 inputType = builder.getTypeFromLength(inputTypeLength); 2729 } 2730 length3 += inputTypeLength; 2731 inputSnippet = input.build(builder, inputType); 2732 const inputPrimitiveType = builder.getComponentType(inputType); 2733 if (inputPrimitiveType !== primitiveType) { 2734 const targetType = builder.getTypeFromLength(inputTypeLength, primitiveType); 2735 inputSnippet = builder.format(inputSnippet, inputType, targetType); 2736 } 2737 snippetValues.push(inputSnippet); 2738 } 2739 const snippet = `${builder.getType(type)}( ${snippetValues.join(", ")} )`; 2740 return builder.format(snippet, type, output3); 2741 } 2742}; 2743var _stringVectorComponents = vectorComponents.join(""); 2744var SplitNode = class extends Node2 { 2745 static get type() { 2746 return "SplitNode"; 2747 } 2748 /** 2749 * Constructs a new split node. 2750 * 2751 * @param {Node} node - The node that should be accessed. 2752 * @param {string} [components='x'] - The components that should be accessed. 2753 */ 2754 constructor(node, components = "x") { 2755 super(); 2756 this.node = node; 2757 this.components = components; 2758 this.isSplitNode = true; 2759 } 2760 /** 2761 * Returns the vector length which is computed based on the requested components. 2762 * 2763 * @return {number} The vector length. 2764 */ 2765 getVectorLength() { 2766 let vectorLength = this.components.length; 2767 for (const c of this.components) { 2768 vectorLength = Math.max(vectorComponents.indexOf(c) + 1, vectorLength); 2769 } 2770 return vectorLength; 2771 } 2772 /** 2773 * Returns the component type of the node's type. 2774 * 2775 * @param {NodeBuilder} builder - The current node builder. 2776 * @return {string} The component type. 2777 */ 2778 getComponentType(builder) { 2779 return builder.getComponentType(this.node.getNodeType(builder)); 2780 } 2781 /** 2782 * This method is overwritten since the node type is inferred from requested components. 2783 * 2784 * @param {NodeBuilder} builder - The current node builder. 2785 * @return {string} The node type. 2786 */ 2787 generateNodeType(builder) { 2788 return builder.getTypeFromLength(this.components.length, this.getComponentType(builder)); 2789 } 2790 /** 2791 * Returns the scope of the node. 2792 * 2793 * @return {Node} The scope of the node. 2794 */ 2795 getScope() { 2796 return this.node.getScope(); 2797 } 2798 generate(builder, output3) { 2799 const node = this.node; 2800 const nodeTypeLength = builder.getTypeLength(node.getNodeType(builder)); 2801 let snippet = null; 2802 if (nodeTypeLength > 1) { 2803 let type = null; 2804 const componentsLength = this.getVectorLength(); 2805 if (componentsLength >= nodeTypeLength) { 2806 type = builder.getTypeFromLength(this.getVectorLength(), this.getComponentType(builder)); 2807 } 2808 const nodeSnippet = node.build(builder, type); 2809 if (this.components.length === nodeTypeLength && this.components === _stringVectorComponents.slice(0, this.components.length)) { 2810 snippet = builder.format(nodeSnippet, type, output3); 2811 } else { 2812 snippet = builder.format(`${nodeSnippet}.${this.components}`, this.getNodeType(builder), output3); 2813 } 2814 } else { 2815 snippet = node.build(builder, output3); 2816 } 2817 return snippet; 2818 } 2819 serialize(data) { 2820 super.serialize(data); 2821 data.components = this.components; 2822 } 2823 deserialize(data) { 2824 super.deserialize(data); 2825 this.components = data.components; 2826 } 2827}; 2828var SetNode = class extends TempNode { 2829 static get type() { 2830 return "SetNode"; 2831 } 2832 /** 2833 * Constructs a new set node. 2834 * 2835 * @param {Node} sourceNode - The node that should be updated. 2836 * @param {string} components - The components that should be updated. 2837 * @param {Node} targetNode - The value node. 2838 */ 2839 constructor(sourceNode, components, targetNode) { 2840 super(); 2841 this.sourceNode = sourceNode; 2842 this.components = components; 2843 this.targetNode = targetNode; 2844 } 2845 /** 2846 * This method is overwritten since the node type is inferred from {@link SetNode#sourceNode}. 2847 * 2848 * @param {NodeBuilder} builder - The current node builder. 2849 * @return {string} The node type. 2850 */ 2851 generateNodeType(builder) { 2852 return this.sourceNode.getNodeType(builder); 2853 } 2854 generate(builder) { 2855 const { sourceNode, components, targetNode } = this; 2856 const sourceType = this.getNodeType(builder); 2857 const componentType = builder.getComponentType(targetNode.getNodeType(builder)); 2858 const targetType = builder.getTypeFromLength(components.length, componentType); 2859 const targetSnippet = targetNode.build(builder, targetType); 2860 const sourceSnippet = sourceNode.build(builder, sourceType); 2861 const length3 = builder.getTypeLength(sourceType); 2862 const snippetValues = []; 2863 for (let i = 0; i < length3; i++) { 2864 const component = vectorComponents[i]; 2865 if (component === components[0]) { 2866 snippetValues.push(targetSnippet); 2867 i += components.length - 1; 2868 } else { 2869 snippetValues.push(sourceSnippet + "." + component); 2870 } 2871 } 2872 return `${builder.getType(sourceType)}( ${snippetValues.join(", ")} )`; 2873 } 2874}; 2875var FlipNode = class extends TempNode { 2876 static get type() { 2877 return "FlipNode"; 2878 } 2879 /** 2880 * Constructs a new flip node. 2881 * 2882 * @param {Node} sourceNode - The node which component(s) should be flipped. 2883 * @param {string} components - The components that should be flipped e.g. `'x'` or `'xy'`. 2884 */ 2885 constructor(sourceNode, components) { 2886 super(); 2887 this.sourceNode = sourceNode; 2888 this.components = components; 2889 } 2890 /** 2891 * This method is overwritten since the node type is inferred from the source node. 2892 * 2893 * @param {NodeBuilder} builder - The current node builder. 2894 * @return {string} The node type. 2895 */ 2896 generateNodeType(builder) { 2897 return this.sourceNode.getNodeType(builder); 2898 } 2899 generate(builder) { 2900 const { components, sourceNode } = this; 2901 const sourceType = this.getNodeType(builder); 2902 const sourceSnippet = sourceNode.build(builder); 2903 const sourceCache = builder.getVarFromNode(this); 2904 const sourceProperty = builder.getPropertyName(sourceCache); 2905 builder.addLineFlowCode(sourceProperty + " = " + sourceSnippet, this); 2906 const length3 = builder.getTypeLength(sourceType); 2907 const snippetValues = []; 2908 let componentIndex = 0; 2909 for (let i = 0; i < length3; i++) { 2910 const component = vectorComponents[i]; 2911 if (component === components[componentIndex]) { 2912 snippetValues.push("1.0 - " + (sourceProperty + "." + component)); 2913 componentIndex++; 2914 } else { 2915 snippetValues.push(sourceProperty + "." + component); 2916 } 2917 } 2918 return `${builder.getType(sourceType)}( ${snippetValues.join(", ")} )`; 2919 } 2920}; 2921var InputNode = class extends Node2 { 2922 static get type() { 2923 return "InputNode"; 2924 } 2925 /** 2926 * Constructs a new input node. 2927 * 2928 * @param {any} value - The value of this node. This can be any JS primitive, functions, array buffers or even three.js objects (vector, matrices, colors). 2929 * @param {?string} nodeType - The node type. If no explicit type is defined, the node tries to derive the type from its value. 2930 */ 2931 constructor(value, nodeType = null) { 2932 super(nodeType); 2933 this.isInputNode = true; 2934 this.value = value; 2935 this.precision = null; 2936 } 2937 generateNodeType() { 2938 if (this.nodeType === null) { 2939 return getValueType(this.value); 2940 } 2941 return this.nodeType; 2942 } 2943 /** 2944 * Returns the input type of the node which is by default the node type. Derived modules 2945 * might overwrite this method and use a fixed type or compute one analytically. 2946 * 2947 * A typical example for different input and node types are textures. The input type of a 2948 * normal RGBA texture is `texture` whereas its node type is `vec4`. 2949 * 2950 * @param {NodeBuilder} builder - The current node builder. 2951 * @return {string} The input type. 2952 */ 2953 getInputType(builder) { 2954 return this.getNodeType(builder); 2955 } 2956 /** 2957 * Sets the precision to the given value. The method can be 2958 * overwritten in derived classes if the final precision must be computed 2959 * analytically. 2960 * 2961 * @param {('low'|'medium'|'high')} precision - The precision of the input value in the shader. 2962 * @return {InputNode} A reference to this node. 2963 */ 2964 setPrecision(precision) { 2965 this.precision = precision; 2966 return this; 2967 } 2968 serialize(data) { 2969 super.serialize(data); 2970 data.value = this.value; 2971 if (this.value && this.value.toArray) data.value = this.value.toArray(); 2972 data.valueType = getValueType(this.value); 2973 data.nodeType = this.nodeType; 2974 if (data.valueType === "ArrayBuffer") data.value = arrayBufferToBase64(data.value); 2975 data.precision = this.precision; 2976 } 2977 deserialize(data) { 2978 super.deserialize(data); 2979 this.nodeType = data.nodeType; 2980 this.value = Array.isArray(data.value) ? getValueFromType(data.valueType, ...data.value) : data.value; 2981 this.precision = data.precision || null; 2982 if (this.value && this.value.fromArray) this.value = this.value.fromArray(data.value); 2983 } 2984 generate() { 2985 warn("Abstract function."); 2986 } 2987}; 2988var _regNum = /float|u?int/; 2989var ConstNode = class extends InputNode { 2990 static get type() { 2991 return "ConstNode"; 2992 } 2993 /** 2994 * Constructs a new input node. 2995 * 2996 * @param {any} value - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color). 2997 * @param {?string} nodeType - The node type. If no explicit type is defined, the node tries to derive the type from its value. 2998 */ 2999 constructor(value, nodeType = null) { 3000 super(value, nodeType); 3001 this.isConstNode = true; 3002 } 3003 /** 3004 * Generates the shader string of the value with the current node builder. 3005 * 3006 * @param {NodeBuilder} builder - The current node builder. 3007 * @return {string} The generated value as a shader string. 3008 */ 3009 generateConst(builder) { 3010 return builder.generateConst(this.getNodeType(builder), this.value); 3011 } 3012 generate(builder, output3) { 3013 const type = this.getNodeType(builder); 3014 if (_regNum.test(type) && _regNum.test(output3)) { 3015 return builder.generateConst(output3, this.value); 3016 } 3017 return builder.format(this.generateConst(builder), type, output3); 3018 } 3019}; 3020var MemberNode = class extends Node2 { 3021 static get type() { 3022 return "MemberNode"; 3023 } 3024 /** 3025 * Constructs a member node. 3026 * 3027 * @param {Node} structNode - The struct node. 3028 * @param {string} property - The property name. 3029 */ 3030 constructor(structNode, property3) { 3031 super(); 3032 this.structNode = structNode; 3033 this.property = property3; 3034 this.isMemberNode = true; 3035 } 3036 hasMember(builder) { 3037 if (this.structNode.isMemberNode) { 3038 if (this.structNode.hasMember(builder) === false) { 3039 return false; 3040 } 3041 } 3042 return this.structNode.getMemberType(builder, this.property) !== "void"; 3043 } 3044 generateNodeType(builder) { 3045 if (this.hasMember(builder) === false) { 3046 return "float"; 3047 } 3048 return this.structNode.getMemberType(builder, this.property); 3049 } 3050 getMemberType(builder, name) { 3051 if (this.hasMember(builder) === false) { 3052 return "float"; 3053 } 3054 const type = this.getNodeType(builder); 3055 const struct3 = builder.getStructTypeNode(type); 3056 return struct3.getMemberType(builder, name); 3057 } 3058 generate(builder) { 3059 if (this.hasMember(builder) === false) { 3060 warn(`TSL: Member "${this.property}" does not exist in struct.`, this.stackTrace); 3061 const type = this.getNodeType(builder); 3062 return builder.generateConst(type); 3063 } 3064 const propertyName = this.structNode.build(builder); 3065 return propertyName + "." + this.property; 3066 } 3067}; 3068var currentStack = null; 3069var NodeElements = /* @__PURE__ */ new Map(); 3070function addMethodChaining(name, nodeElement) { 3071 if (NodeElements.has(name)) { 3072 warn(`TSL: Redefinition of method chaining '${name}'.`); 3073 return; 3074 } 3075 if (typeof nodeElement !== "function") throw new Error(`THREE.TSL: Node element ${name} is not a function`); 3076 NodeElements.set(name, nodeElement); 3077 if (name !== "assign") { 3078 Node2.prototype[name] = function(...params) { 3079 return this.isStackNode ? this.addToStack(nodeElement(...params)) : nodeElement(this, ...params); 3080 }; 3081 Node2.prototype[name + "Assign"] = function(...params) { 3082 return this.isStackNode ? this.assign(params[0], nodeElement(...params)) : this.assign(nodeElement(this, ...params)); 3083 }; 3084 } 3085} 3086var parseSwizzle = (props) => props.replace(/r|s/g, "x").replace(/g|t/g, "y").replace(/b|p/g, "z").replace(/a|q/g, "w"); 3087var parseSwizzleAndSort = (props) => parseSwizzle(props).split("").sort().join(""); 3088Node2.prototype.assign = function(...params) { 3089 if (this.isStackNode !== true) { 3090 if (currentStack !== null) { 3091 currentStack.assign(this, ...params); 3092 } else { 3093 error("TSL: No stack defined for assign operation. Make sure the assign is inside a Fn().", new StackTrace()); 3094 } 3095 return this; 3096 } else { 3097 const nodeElement = NodeElements.get("assign"); 3098 return this.addToStack(nodeElement(...params)); 3099 } 3100}; 3101Node2.prototype.toVarIntent = function() { 3102 return this; 3103}; 3104Node2.prototype.get = function(value) { 3105 return new MemberNode(this, value); 3106}; 3107var proto = {}; 3108function setProtoSwizzle(property3, altA, altB) { 3109 proto[property3] = proto[altA] = proto[altB] = { 3110 get() { 3111 this._cache = this._cache || {}; 3112 let split3 = this._cache[property3]; 3113 if (split3 === void 0) { 3114 split3 = new SplitNode(this, property3); 3115 this._cache[property3] = split3; 3116 } 3117 return split3; 3118 }, 3119 set(value) { 3120 this[property3].assign(nodeObject(value)); 3121 } 3122 }; 3123 const propUpper = property3.toUpperCase(); 3124 const altAUpper = altA.toUpperCase(); 3125 const altBUpper = altB.toUpperCase(); 3126 Node2.prototype["set" + propUpper] = Node2.prototype["set" + altAUpper] = Node2.prototype["set" + altBUpper] = function(value) { 3127 const swizzle = parseSwizzleAndSort(property3); 3128 return new SetNode(this, swizzle, nodeObject(value)); 3129 }; 3130 Node2.prototype["flip" + propUpper] = Node2.prototype["flip" + altAUpper] = Node2.prototype["flip" + altBUpper] = function() { 3131 const swizzle = parseSwizzleAndSort(property3); 3132 return new FlipNode(this, swizzle); 3133 }; 3134} 3135var swizzleA = ["x", "y", "z", "w"]; 3136var swizzleB = ["r", "g", "b", "a"]; 3137var swizzleC = ["s", "t", "p", "q"]; 3138for (let a = 0; a < 4; a++) { 3139 let prop = swizzleA[a]; 3140 let altA = swizzleB[a]; 3141 let altB = swizzleC[a]; 3142 setProtoSwizzle(prop, altA, altB); 3143 for (let b = 0; b < 4; b++) { 3144 prop = swizzleA[a] + swizzleA[b]; 3145 altA = swizzleB[a] + swizzleB[b]; 3146 altB = swizzleC[a] + swizzleC[b]; 3147 setProtoSwizzle(prop, altA, altB); 3148 for (let c = 0; c < 4; c++) { 3149 prop = swizzleA[a] + swizzleA[b] + swizzleA[c]; 3150 altA = swizzleB[a] + swizzleB[b] + swizzleB[c]; 3151 altB = swizzleC[a] + swizzleC[b] + swizzleC[c]; 3152 setProtoSwizzle(prop, altA, altB); 3153 for (let d = 0; d < 4; d++) { 3154 prop = swizzleA[a] + swizzleA[b] + swizzleA[c] + swizzleA[d]; 3155 altA = swizzleB[a] + swizzleB[b] + swizzleB[c] + swizzleB[d]; 3156 altB = swizzleC[a] + swizzleC[b] + swizzleC[c] + swizzleC[d]; 3157 setProtoSwizzle(prop, altA, altB); 3158 } 3159 } 3160 } 3161} 3162for (let i = 0; i < 32; i++) { 3163 proto[i] = { 3164 get() { 3165 this._cache = this._cache || {}; 3166 let element3 = this._cache[i]; 3167 if (element3 === void 0) { 3168 element3 = new ArrayElementNode(this, new ConstNode(i, "uint")); 3169 this._cache[i] = element3; 3170 } 3171 return element3; 3172 }, 3173 set(value) { 3174 this[i].assign(nodeObject(value)); 3175 } 3176 }; 3177} 3178Object.defineProperties(Node2.prototype, proto); 3179var nodeBuilderFunctionsCacheMap = /* @__PURE__ */ new WeakMap(); 3180var ShaderNodeObject = function(obj, altType = null) { 3181 const type = getValueType(obj); 3182 if (type === "node") { 3183 return obj; 3184 } else if (altType === null && (type === "float" || type === "boolean") || type && type !== "shader" && type !== "string") { 3185 return nodeObject(getConstNode(obj, altType)); 3186 } else if (type === "shader") { 3187 return obj.isFn ? obj : Fn(obj); 3188 } 3189 return obj; 3190}; 3191var ShaderNodeObjects = function(objects, altType = null) { 3192 for (const name in objects) { 3193 objects[name] = nodeObject(objects[name], altType); 3194 } 3195 return objects; 3196}; 3197var ShaderNodeArray = function(array3, altType = null) { 3198 const len = array3.length; 3199 for (let i = 0; i < len; i++) { 3200 array3[i] = nodeObject(array3[i], altType); 3201 } 3202 return array3; 3203}; 3204var ShaderNodeProxy = function(NodeClass, scope = null, factor = null, settings = null) { 3205 function assignNode(node) { 3206 if (settings !== null) { 3207 node = nodeObject(Object.assign(node, settings)); 3208 if (settings.intent === true) { 3209 node = node.toVarIntent(); 3210 } 3211 } else { 3212 node = nodeObject(node); 3213 } 3214 return node; 3215 } 3216 let fn, name = scope, minParams, maxParams; 3217 function verifyParamsLimit(params) { 3218 let tslName; 3219 if (name) tslName = /[a-z]/i.test(name) ? name + "()" : name; 3220 else tslName = NodeClass.type; 3221 if (minParams !== void 0 && params.length < minParams) { 3222 error(`TSL: "${tslName}" parameter length is less than minimum required.`, new StackTrace()); 3223 return params.concat(new Array(minParams - params.length).fill(0)); 3224 } else if (maxParams !== void 0 && params.length > maxParams) { 3225 error(`TSL: "${tslName}" parameter length exceeds limit.`, new StackTrace()); 3226 return params.slice(0, maxParams); 3227 } 3228 return params; 3229 } 3230 if (scope === null) { 3231 fn = (...params) => { 3232 return assignNode(new NodeClass(...nodeArray(verifyParamsLimit(params)))); 3233 }; 3234 } else if (factor !== null) { 3235 factor = nodeObject(factor); 3236 fn = (...params) => { 3237 return assignNode(new NodeClass(scope, ...nodeArray(verifyParamsLimit(params)), factor)); 3238 }; 3239 } else { 3240 fn = (...params) => { 3241 return assignNode(new NodeClass(scope, ...nodeArray(verifyParamsLimit(params)))); 3242 }; 3243 } 3244 fn.setParameterLength = (...params) => { 3245 if (params.length === 1) minParams = maxParams = params[0]; 3246 else if (params.length === 2) [minParams, maxParams] = params; 3247 return fn; 3248 }; 3249 fn.setName = (value) => { 3250 name = value; 3251 return fn; 3252 }; 3253 return fn; 3254}; 3255var ShaderNodeImmutable = function(NodeClass, ...params) { 3256 return new NodeClass(...nodeArray(params)); 3257}; 3258var ShaderCallNodeInternal = class extends Node2 { 3259 constructor(shaderNode, rawInputs) { 3260 super(); 3261 this.shaderNode = shaderNode; 3262 this.rawInputs = rawInputs; 3263 this.isShaderCallNodeInternal = true; 3264 } 3265 generateNodeType(builder) { 3266 return this.shaderNode.nodeType || this.getOutputNode(builder).getNodeType(builder); 3267 } 3268 getElementType(builder) { 3269 return this.getOutputNode(builder).getElementType(builder); 3270 } 3271 getMemberType(builder, name) { 3272 return this.getOutputNode(builder).getMemberType(builder, name); 3273 } 3274 call(builder) { 3275 const { shaderNode, rawInputs } = this; 3276 const properties = builder.getNodeProperties(shaderNode); 3277 const subBuild3 = builder.getClosestSubBuild(shaderNode.subBuilds) || ""; 3278 const subBuildProperty = subBuild3 || "default"; 3279 if (properties[subBuildProperty]) { 3280 return properties[subBuildProperty]; 3281 } 3282 const previousSubBuildFn = builder.subBuildFn; 3283 const previousFnCall = builder.fnCall; 3284 builder.subBuildFn = subBuild3; 3285 builder.fnCall = this; 3286 let result = null; 3287 if (shaderNode.layout) { 3288 let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get(builder.constructor); 3289 if (functionNodesCacheMap === void 0) { 3290 functionNodesCacheMap = /* @__PURE__ */ new WeakMap(); 3291 nodeBuilderFunctionsCacheMap.set(builder.constructor, functionNodesCacheMap); 3292 } 3293 let functionNode = functionNodesCacheMap.get(shaderNode); 3294 if (functionNode === void 0) { 3295 functionNode = nodeObject(builder.buildFunctionNode(shaderNode)); 3296 functionNodesCacheMap.set(shaderNode, functionNode); 3297 } 3298 builder.addInclude(functionNode); 3299 const inputs = rawInputs ? getLayoutParameters(rawInputs) : null; 3300 result = nodeObject(functionNode.call(inputs)); 3301 } else { 3302 const secureNodeBuilder = new Proxy(builder, { 3303 get: (target, property3, receiver) => { 3304 let value; 3305 if (Symbol.iterator === property3) { 3306 value = function* () { 3307 yield void 0; 3308 }; 3309 } else { 3310 value = Reflect.get(target, property3, receiver); 3311 } 3312 return value; 3313 } 3314 }); 3315 const inputs = rawInputs ? getProxyParameters(rawInputs) : null; 3316 const hasParameters = Array.isArray(rawInputs) ? rawInputs.length > 0 : rawInputs !== null; 3317 const jsFunc = shaderNode.jsFunc; 3318 const outputNode = hasParameters || jsFunc.length > 1 ? jsFunc(inputs, secureNodeBuilder) : jsFunc(secureNodeBuilder); 3319 result = nodeObject(outputNode); 3320 } 3321 builder.subBuildFn = previousSubBuildFn; 3322 builder.fnCall = previousFnCall; 3323 if (shaderNode.once) { 3324 properties[subBuildProperty] = result; 3325 } 3326 return result; 3327 } 3328 setupOutput(builder) { 3329 builder.addStack(); 3330 builder.stack.outputNode = this.call(builder); 3331 return builder.removeStack(); 3332 } 3333 getOutputNode(builder) { 3334 const properties = builder.getNodeProperties(this); 3335 const subBuildOutput = builder.getSubBuildOutput(this); 3336 properties[subBuildOutput] = properties[subBuildOutput] || this.setupOutput(builder); 3337 properties[subBuildOutput].subBuild = builder.getClosestSubBuild(this); 3338 return properties[subBuildOutput]; 3339 } 3340 build(builder, output3 = null) { 3341 let result = null; 3342 const buildStage = builder.getBuildStage(); 3343 const properties = builder.getNodeProperties(this); 3344 const subBuildOutput = builder.getSubBuildOutput(this); 3345 const outputNode = this.getOutputNode(builder); 3346 const previousFnCall = builder.fnCall; 3347 builder.fnCall = this; 3348 if (buildStage === "setup") { 3349 const subBuildInitialized = builder.getSubBuildProperty("initialized", this); 3350 if (properties[subBuildInitialized] !== true) { 3351 properties[subBuildInitialized] = true; 3352 properties[subBuildOutput] = this.getOutputNode(builder); 3353 properties[subBuildOutput].build(builder); 3354 if (this.shaderNode.subBuilds) { 3355 for (const node of builder.chaining) { 3356 const nodeData = builder.getDataFromNode(node, "any"); 3357 nodeData.subBuilds = nodeData.subBuilds || /* @__PURE__ */ new Set(); 3358 for (const subBuild3 of this.shaderNode.subBuilds) { 3359 nodeData.subBuilds.add(subBuild3); 3360 } 3361 } 3362 } 3363 } 3364 result = properties[subBuildOutput]; 3365 } else if (buildStage === "analyze") { 3366 outputNode.build(builder, output3); 3367 } else if (buildStage === "generate") { 3368 result = outputNode.build(builder, output3) || ""; 3369 } 3370 builder.fnCall = previousFnCall; 3371 return result; 3372 } 3373}; 3374function getLayoutParameters(params) { 3375 let output3; 3376 nodeObjects(params); 3377 const isArrayAsParameter = params[0] && (params[0].isNode || Object.getPrototypeOf(params[0]) !== Object.prototype); 3378 if (isArrayAsParameter) { 3379 output3 = [...params]; 3380 } else { 3381 output3 = params[0]; 3382 } 3383 return output3; 3384} 3385function getProxyParameters(params) { 3386 let index = 0; 3387 nodeObjects(params); 3388 return new Proxy(params, { 3389 get: (target, property3, receiver) => { 3390 let value; 3391 if (property3 === "length") { 3392 value = params.length; 3393 return value; 3394 } 3395 if (Symbol.iterator === property3) { 3396 value = function* () { 3397 for (const inputNode of params) { 3398 yield nodeObject(inputNode); 3399 } 3400 }; 3401 } else { 3402 if (params.length > 0) { 3403 if (Object.getPrototypeOf(params[0]) === Object.prototype) { 3404 const objectTarget = params[0]; 3405 if (objectTarget[property3] === void 0) { 3406 value = objectTarget[index++]; 3407 } else { 3408 value = Reflect.get(objectTarget, property3, receiver); 3409 } 3410 } else if (params[0] instanceof Node2) { 3411 if (params[property3] === void 0) { 3412 value = params[index++]; 3413 } else { 3414 value = Reflect.get(params, property3, receiver); 3415 } 3416 } 3417 } else { 3418 value = Reflect.get(target, property3, receiver); 3419 } 3420 value = nodeObject(value); 3421 } 3422 return value; 3423 } 3424 }); 3425} 3426var ShaderNodeInternal = class extends Node2 { 3427 constructor(jsFunc, nodeType) { 3428 super(nodeType); 3429 this.jsFunc = jsFunc; 3430 this.layout = null; 3431 this.global = true; 3432 this.once = false; 3433 } 3434 setLayout(layout) { 3435 this.layout = layout; 3436 return this; 3437 } 3438 getLayout() { 3439 return this.layout; 3440 } 3441 call(rawInputs = null) { 3442 return new ShaderCallNodeInternal(this, rawInputs); 3443 } 3444 setup() { 3445 return this.call(); 3446 } 3447}; 3448var bools = [false, true]; 3449var uints = [0, 1, 2, 3]; 3450var ints = [-1, -2]; 3451var floats = [0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / (Math.PI * 2), Math.PI / 2]; 3452var boolsCacheMap = /* @__PURE__ */ new Map(); 3453for (const bool3 of bools) boolsCacheMap.set(bool3, new ConstNode(bool3)); 3454var uintsCacheMap = /* @__PURE__ */ new Map(); 3455for (const uint3 of uints) uintsCacheMap.set(uint3, new ConstNode(uint3, "uint")); 3456var intsCacheMap = new Map([...uintsCacheMap].map((el) => new ConstNode(el.value, "int"))); 3457for (const int3 of ints) intsCacheMap.set(int3, new ConstNode(int3, "int")); 3458var floatsCacheMap = new Map([...intsCacheMap].map((el) => new ConstNode(el.value))); 3459for (const float3 of floats) floatsCacheMap.set(float3, new ConstNode(float3)); 3460for (const float3 of floats) floatsCacheMap.set(-float3, new ConstNode(-float3)); 3461var cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; 3462var constNodesCacheMap = new Map([...boolsCacheMap, ...floatsCacheMap]); 3463var getConstNode = (value, type) => { 3464 if (constNodesCacheMap.has(value)) { 3465 return constNodesCacheMap.get(value); 3466 } else if (value.isNode === true) { 3467 return value; 3468 } else { 3469 return new ConstNode(value, type); 3470 } 3471}; 3472var ConvertType = function(type, cacheMap = null) { 3473 return (...params) => { 3474 for (const param of params) { 3475 if (param === void 0) { 3476 error(`TSL: Invalid parameter for the type "${type}".`, new StackTrace()); 3477 return new ConstNode(0, type); 3478 } 3479 } 3480 if (params.length === 0 || !["bool", "float", "int", "uint"].includes(type) && params.every((param) => { 3481 const paramType = typeof param; 3482 return paramType !== "object" && paramType !== "function"; 3483 })) { 3484 params = [getValueFromType(type, ...params)]; 3485 } 3486 if (params.length === 1 && cacheMap !== null && cacheMap.has(params[0])) { 3487 return nodeObjectIntent(cacheMap.get(params[0])); 3488 } 3489 if (params.length === 1) { 3490 const node = getConstNode(params[0], type); 3491 if (node.nodeType === type) return nodeObjectIntent(node); 3492 return nodeObjectIntent(new ConvertNode(node, type)); 3493 } 3494 const nodes = params.map((param) => getConstNode(param)); 3495 return nodeObjectIntent(new JoinNode(nodes, type)); 3496 }; 3497}; 3498function defined(value) { 3499 if (value && value.isNode) { 3500 value.traverse((node) => { 3501 if (node.isConstNode) { 3502 value = node.value; 3503 } 3504 }); 3505 } 3506 return Boolean(value); 3507} 3508var getConstNodeType = (value) => value !== void 0 && value !== null ? value.nodeType || value.convertTo || (typeof value === "string" ? value : null) : null; 3509function ShaderNode(jsFunc, nodeType) { 3510 return new ShaderNodeInternal(jsFunc, nodeType); 3511} 3512var nodeObject = (val, altType = null) => ( 3513 /* new */ 3514 ShaderNodeObject(val, altType) 3515); 3516var nodeObjectIntent = (val, altType = null) => ( 3517 /* new */ 3518 nodeObject(val, altType).toVarIntent() 3519); 3520var nodeObjects = (val, altType = null) => new ShaderNodeObjects(val, altType); 3521var nodeArray = (val, altType = null) => new ShaderNodeArray(val, altType); 3522var nodeProxy = (NodeClass, scope = null, factor = null, settings = null) => new ShaderNodeProxy(NodeClass, scope, factor, settings); 3523var nodeImmutable = (NodeClass, ...params) => new ShaderNodeImmutable(NodeClass, ...params); 3524var nodeProxyIntent = (NodeClass, scope = null, factor = null, settings = {}) => new ShaderNodeProxy(NodeClass, scope, factor, { ...settings, intent: true }); 3525var fnId = 0; 3526var FnNode = class extends Node2 { 3527 constructor(jsFunc, layout = null) { 3528 super(); 3529 let nodeType = null; 3530 if (layout !== null) { 3531 if (typeof layout === "object") { 3532 nodeType = layout.return; 3533 } else { 3534 if (typeof layout === "string") { 3535 nodeType = layout; 3536 } else { 3537 error("TSL: Invalid layout type.", new StackTrace()); 3538 } 3539 layout = null; 3540 } 3541 } 3542 this.shaderNode = new ShaderNode(jsFunc, nodeType); 3543 if (layout !== null) { 3544 this.setLayout(layout); 3545 } 3546 this.isFn = true; 3547 } 3548 setLayout(layout) { 3549 const nodeType = this.shaderNode.nodeType; 3550 if (typeof layout.inputs !== "object") { 3551 const fullLayout = { 3552 name: "fn" + fnId++, 3553 type: nodeType, 3554 inputs: [] 3555 }; 3556 for (const name in layout) { 3557 if (name === "return") continue; 3558 fullLayout.inputs.push({ 3559 name, 3560 type: layout[name] 3561 }); 3562 } 3563 layout = fullLayout; 3564 } 3565 this.shaderNode.setLayout(layout); 3566 return this; 3567 } 3568 generateNodeType(builder) { 3569 return this.shaderNode.getNodeType(builder) || "float"; 3570 } 3571 call(...params) { 3572 const fnCall = this.shaderNode.call(params); 3573 if (this.shaderNode.nodeType === "void") fnCall.toStack(); 3574 return fnCall.toVarIntent(); 3575 } 3576 once(subBuilds = null) { 3577 this.shaderNode.once = true; 3578 this.shaderNode.subBuilds = subBuilds; 3579 return this; 3580 } 3581 generate(builder) { 3582 const type = this.getNodeType(builder); 3583 error('TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".', this.stackTrace); 3584 return builder.generateConst(type); 3585 } 3586}; 3587function Fn(jsFunc, layout = null) { 3588 const instance3 = new FnNode(jsFunc, layout); 3589 return new Proxy(() => { 3590 }, { 3591 apply(target, thisArg, params) { 3592 return instance3.call(...params); 3593 }, 3594 get(target, prop, receiver) { 3595 return Reflect.get(instance3, prop, receiver); 3596 }, 3597 set(target, prop, value, receiver) { 3598 return Reflect.set(instance3, prop, value, receiver); 3599 } 3600 }); 3601} 3602var setCurrentStack = (stack3) => { 3603 currentStack = stack3; 3604}; 3605var getCurrentStack = () => currentStack; 3606var If = (...params) => currentStack.If(...params); 3607var Switch = (...params) => currentStack.Switch(...params); 3608function Stack(node) { 3609 if (currentStack) currentStack.addToStack(node); 3610 return node; 3611} 3612addMethodChaining("toStack", Stack); 3613var color = new ConvertType("color"); 3614var float = new ConvertType("float", cacheMaps.float); 3615var int = new ConvertType("int", cacheMaps.ints); 3616var uint = new ConvertType("uint", cacheMaps.uint); 3617var bool = new ConvertType("bool", cacheMaps.bool); 3618var vec2 = new ConvertType("vec2"); 3619var ivec2 = new ConvertType("ivec2"); 3620var uvec2 = new ConvertType("uvec2"); 3621var bvec2 = new ConvertType("bvec2"); 3622var vec3 = new ConvertType("vec3"); 3623var ivec3 = new ConvertType("ivec3"); 3624var uvec3 = new ConvertType("uvec3"); 3625var bvec3 = new ConvertType("bvec3"); 3626var vec4 = new ConvertType("vec4"); 3627var ivec4 = new ConvertType("ivec4"); 3628var uvec4 = new ConvertType("uvec4"); 3629var bvec4 = new ConvertType("bvec4"); 3630var mat2 = new ConvertType("mat2"); 3631var mat3 = new ConvertType("mat3"); 3632var mat4 = new ConvertType("mat4"); 3633var string = (value = "") => new ConstNode(value, "string"); 3634var arrayBuffer = (value) => new ConstNode(value, "ArrayBuffer"); 3635addMethodChaining("toColor", color); 3636addMethodChaining("toFloat", float); 3637addMethodChaining("toInt", int); 3638addMethodChaining("toUint", uint); 3639addMethodChaining("toBool", bool); 3640addMethodChaining("toVec2", vec2); 3641addMethodChaining("toIVec2", ivec2); 3642addMethodChaining("toUVec2", uvec2); 3643addMethodChaining("toBVec2", bvec2); 3644addMethodChaining("toVec3", vec3); 3645addMethodChaining("toIVec3", ivec3); 3646addMethodChaining("toUVec3", uvec3); 3647addMethodChaining("toBVec3", bvec3); 3648addMethodChaining("toVec4", vec4); 3649addMethodChaining("toIVec4", ivec4); 3650addMethodChaining("toUVec4", uvec4); 3651addMethodChaining("toBVec4", bvec4); 3652addMethodChaining("toMat2", mat2); 3653addMethodChaining("toMat3", mat3); 3654addMethodChaining("toMat4", mat4); 3655var element = /* @__PURE__ */ nodeProxy(ArrayElementNode).setParameterLength(2); 3656var convert = (node, types) => new ConvertNode(nodeObject(node), types); 3657var split = (node, channels) => new SplitNode(nodeObject(node), channels); 3658addMethodChaining("element", element); 3659addMethodChaining("convert", convert); 3660var append = (node) => { 3661 warn("TSL: append() has been renamed to Stack().", new StackTrace()); 3662 return Stack(node); 3663}; 3664addMethodChaining("append", (node) => { 3665 warn("TSL: .append() has been renamed to .toStack().", new StackTrace()); 3666 return Stack(node); 3667}); 3668var PropertyNode = class extends Node2 { 3669 static get type() { 3670 return "PropertyNode"; 3671 } 3672 /** 3673 * Constructs a new property node. 3674 * 3675 * @param {string} nodeType - The type of the node. 3676 * @param {?string} [name=null] - The name of the property in the shader. 3677 * @param {boolean} [varying=false] - Whether this property is a varying or not. 3678 */ 3679 constructor(nodeType, name = null, varying3 = false) { 3680 super(nodeType); 3681 this.name = name; 3682 this.varying = varying3; 3683 this.isPropertyNode = true; 3684 this.global = true; 3685 } 3686 customCacheKey() { 3687 return hashString(this.type + ":" + (this.name || "") + ":" + (this.varying ? "1" : "0")); 3688 } 3689 getHash(builder) { 3690 return this.name || super.getHash(builder); 3691 } 3692 generate(builder) { 3693 let nodeVar; 3694 if (this.varying === true) { 3695 nodeVar = builder.getVaryingFromNode(this, this.name); 3696 nodeVar.needsInterpolation = true; 3697 } else { 3698 nodeVar = builder.getVarFromNode(this, this.name); 3699 } 3700 return builder.getPropertyName(nodeVar); 3701 } 3702}; 3703var property = (type, name) => new PropertyNode(type, name); 3704var varyingProperty = (type, name) => new PropertyNode(type, name, true); 3705var diffuseColor = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec4", "DiffuseColor"); 3706var diffuseContribution = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec3", "DiffuseContribution"); 3707var emissive = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec3", "EmissiveColor"); 3708var roughness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Roughness"); 3709var metalness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Metalness"); 3710var clearcoat = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Clearcoat"); 3711var clearcoatRoughness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "ClearcoatRoughness"); 3712var sheen = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec3", "Sheen"); 3713var sheenRoughness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "SheenRoughness"); 3714var iridescence = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Iridescence"); 3715var iridescenceIOR = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "IridescenceIOR"); 3716var iridescenceThickness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "IridescenceThickness"); 3717var alphaT = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "AlphaT"); 3718var anisotropy = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Anisotropy"); 3719var anisotropyT = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec3", "AnisotropyT"); 3720var anisotropyB = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec3", "AnisotropyB"); 3721var specularColor = /* @__PURE__ */ nodeImmutable(PropertyNode, "color", "SpecularColor"); 3722var specularColorBlended = /* @__PURE__ */ nodeImmutable(PropertyNode, "color", "SpecularColorBlended"); 3723var specularF90 = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "SpecularF90"); 3724var shininess = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Shininess"); 3725var output = /* @__PURE__ */ nodeImmutable(PropertyNode, "vec4", "Output"); 3726var dashSize = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "dashSize"); 3727var gapSize = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "gapSize"); 3728var pointWidth = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "pointWidth"); 3729var ior = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "IOR"); 3730var transmission = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Transmission"); 3731var thickness = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Thickness"); 3732var attenuationDistance = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "AttenuationDistance"); 3733var attenuationColor = /* @__PURE__ */ nodeImmutable(PropertyNode, "color", "AttenuationColor"); 3734var dispersion = /* @__PURE__ */ nodeImmutable(PropertyNode, "float", "Dispersion"); 3735var UniformGroupNode = class extends Node2 { 3736 static get type() { 3737 return "UniformGroupNode"; 3738 } 3739 /** 3740 * Constructs a new uniform group node. 3741 * 3742 * @param {string} name - The name of the uniform group node. 3743 * @param {boolean} [shared=false] - Whether this uniform group node is shared or not. 3744 * @param {number} [order=1] - Influences the internal sorting. 3745 * @param {string|null} [updateType=null] - The update type of the uniform group node. 3746 */ 3747 constructor(name, shared = false, order = 1, updateType = null) { 3748 super("string"); 3749 this.name = name; 3750 this.shared = shared; 3751 this.order = order; 3752 this.updateType = updateType; 3753 this.isUniformGroup = true; 3754 } 3755 /** 3756 * Marks the uniform group node as needing an update. 3757 * This will trigger the necessary updates in the rendering process. 3758 */ 3759 update() { 3760 this.needsUpdate = true; 3761 } 3762 /** 3763 * Serializes the uniform group node to a JSON object. 3764 * 3765 * @param {Object} data - The object to store the serialized data. 3766 */ 3767 serialize(data) { 3768 super.serialize(data); 3769 data.name = this.name; 3770 data.version = this.version; 3771 data.shared = this.shared; 3772 } 3773 /** 3774 * Deserializes the uniform group node from a JSON object. 3775 * 3776 * @param {Object} data - The object containing the serialized data. 3777 */ 3778 deserialize(data) { 3779 super.deserialize(data); 3780 this.name = data.name; 3781 this.version = data.version; 3782 this.shared = data.shared; 3783 } 3784}; 3785var uniformGroup = (name, order = 1, updateType = null) => new UniformGroupNode(name, false, order, updateType); 3786var sharedUniformGroup = (name, order = 0, updateType = null) => new UniformGroupNode(name, true, order, updateType); 3787var frameGroup = /* @__PURE__ */ sharedUniformGroup("frame", 0, NodeUpdateType.FRAME); 3788var renderGroup = /* @__PURE__ */ sharedUniformGroup("render", 0, NodeUpdateType.RENDER); 3789var objectGroup = /* @__PURE__ */ uniformGroup("object", 1, NodeUpdateType.OBJECT); 3790var UniformNode = class extends InputNode { 3791 static get type() { 3792 return "UniformNode"; 3793 } 3794 /** 3795 * Constructs a new uniform node. 3796 * 3797 * @param {any} value - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color, texture). 3798 * @param {?string} nodeType - The node type. If no explicit type is defined, the node tries to derive the type from its value. 3799 */ 3800 constructor(value, nodeType = null) { 3801 super(value, nodeType); 3802 this.isUniformNode = true; 3803 this.name = ""; 3804 this.groupNode = objectGroup; 3805 } 3806 /** 3807 * Sets the {@link UniformNode#name} property. 3808 * 3809 * @param {string} name - The name of the uniform. 3810 * @return {UniformNode} A reference to this node. 3811 */ 3812 setName(name) { 3813 this.name = name; 3814 return this; 3815 } 3816 /** 3817 * Sets the {@link UniformNode#name} property. 3818 * 3819 * @deprecated 3820 * @param {string} name - The name of the uniform. 3821 * @return {UniformNode} A reference to this node. 3822 */ 3823 label(name) { 3824 warn('TSL: "label()" has been deprecated. Use "setName()" instead.', new StackTrace()); 3825 return this.setName(name); 3826 } 3827 /** 3828 * Sets the {@link UniformNode#groupNode} property. 3829 * 3830 * @param {UniformGroupNode} group - The uniform group. 3831 * @return {UniformNode} A reference to this node. 3832 */ 3833 setGroup(group) { 3834 this.groupNode = group; 3835 return this; 3836 } 3837 /** 3838 * Returns the {@link UniformNode#groupNode}. 3839 * 3840 * @return {UniformGroupNode} The uniform group. 3841 */ 3842 getGroup() { 3843 return this.groupNode; 3844 } 3845 /** 3846 * By default, this method returns the result of {@link Node#getHash} but derived 3847 * classes might overwrite this method with a different implementation. 3848 * 3849 * @param {NodeBuilder} builder - The current node builder. 3850 * @return {string} The uniform hash. 3851 */ 3852 getUniformHash(builder) { 3853 return this.getHash(builder); 3854 } 3855 onUpdate(callback, updateType) { 3856 callback = callback.bind(this); 3857 return super.onUpdate((frame) => { 3858 const value = callback(frame, this); 3859 if (value !== void 0) { 3860 this.value = value; 3861 } 3862 }, updateType); 3863 } 3864 getInputType(builder) { 3865 let type = super.getInputType(builder); 3866 if (type === "bool") { 3867 type = "uint"; 3868 } 3869 return type; 3870 } 3871 generate(builder, output3) { 3872 const type = this.getNodeType(builder); 3873 const hash3 = this.getUniformHash(builder); 3874 let sharedNode = builder.getNodeFromHash(hash3); 3875 if (sharedNode === void 0) { 3876 builder.setHashNode(this, hash3); 3877 sharedNode = this; 3878 } 3879 const sharedNodeType = sharedNode.getInputType(builder); 3880 const nodeUniform = builder.getUniformFromNode(sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.nodeName); 3881 const uniformName = builder.getPropertyName(nodeUniform); 3882 if (builder.context.nodeName !== void 0) delete builder.context.nodeName; 3883 let snippet = uniformName; 3884 if (type === "bool") { 3885 const nodeData = builder.getDataFromNode(this); 3886 let propertyName = nodeData.propertyName; 3887 if (propertyName === void 0) { 3888 const nodeVar = builder.getVarFromNode(this, null, "bool"); 3889 propertyName = builder.getPropertyName(nodeVar); 3890 nodeData.propertyName = propertyName; 3891 snippet = builder.format(uniformName, sharedNodeType, type); 3892 builder.addLineFlowCode(`${propertyName} = ${snippet}`, this); 3893 } 3894 snippet = propertyName; 3895 } 3896 return builder.format(snippet, type, output3); 3897 } 3898}; 3899var uniform = (value, type) => { 3900 const nodeType = getConstNodeType(type || value); 3901 if (nodeType === value) { 3902 value = getValueFromType(nodeType); 3903 } 3904 if (value && value.isNode === true) { 3905 let v = value.value; 3906 value.traverse((n) => { 3907 if (n.isConstNode === true) { 3908 v = n.value; 3909 } 3910 }); 3911 value = v; 3912 } 3913 return new UniformNode(value, nodeType); 3914}; 3915var ArrayNode = class extends TempNode { 3916 static get type() { 3917 return "ArrayNode"; 3918 } 3919 /** 3920 * Constructs a new array node. 3921 * 3922 * @param {?string} nodeType - The data type of the elements. 3923 * @param {number} count - Size of the array. 3924 * @param {?Array<Node>} [values=null] - Array default values. 3925 */ 3926 constructor(nodeType, count, values = null) { 3927 super(nodeType); 3928 this.count = count; 3929 this.values = values; 3930 this.isArrayNode = true; 3931 } 3932 /** 3933 * Returns the number of elements in the node array. 3934 * 3935 * @param {NodeBuilder} builder - The current node builder. 3936 * @return {number} The number of elements in the node array. 3937 */ 3938 getArrayCount() { 3939 return this.count; 3940 } 3941 /** 3942 * Returns the node's type. 3943 * 3944 * @param {NodeBuilder} builder - The current node builder. 3945 * @return {string} The type of the node. 3946 */ 3947 generateNodeType(builder) { 3948 if (this.nodeType === null) { 3949 return this.values[0].getNodeType(builder); 3950 } 3951 return this.nodeType; 3952 } 3953 /** 3954 * Returns the node's type. 3955 * 3956 * @param {NodeBuilder} builder - The current node builder. 3957 * @return {string} The type of the node. 3958 */ 3959 getElementType(builder) { 3960 return this.getNodeType(builder); 3961 } 3962 /** 3963 * Returns the type of a member variable. 3964 * 3965 * @param {NodeBuilder} builder - The current node builder. 3966 * @param {string} name - The name of the member variable. 3967 * @return {string} The type of the member variable. 3968 */ 3969 getMemberType(builder, name) { 3970 if (this.nodeType === null) { 3971 return this.values[0].getMemberType(builder, name); 3972 } 3973 return super.getMemberType(builder, name); 3974 } 3975 /** 3976 * This method builds the output node and returns the resulting array as a shader string. 3977 * 3978 * @param {NodeBuilder} builder - The current node builder. 3979 * @return {string} The generated shader string. 3980 */ 3981 generate(builder) { 3982 const type = this.getNodeType(builder); 3983 return builder.generateArray(type, this.count, this.values); 3984 } 3985}; 3986var array = (...params) => { 3987 let node; 3988 if (params.length === 1) { 3989 const values = params[0]; 3990 node = new ArrayNode(null, values.length, values); 3991 } else { 3992 const nodeType = params[0]; 3993 const count = params[1]; 3994 node = new ArrayNode(nodeType, count); 3995 } 3996 return nodeObject(node); 3997}; 3998addMethodChaining("toArray", (node, count) => array(Array(count).fill(node))); 3999var AssignNode = class extends TempNode { 4000 static get type() { 4001 return "AssignNode"; 4002 } 4003 /** 4004 * Constructs a new assign node. 4005 * 4006 * @param {Node} targetNode - The target node. 4007 * @param {Node} sourceNode - The source type. 4008 */ 4009 constructor(targetNode, sourceNode) { 4010 super(); 4011 this.targetNode = targetNode; 4012 this.sourceNode = sourceNode; 4013 this.isAssignNode = true; 4014 } 4015 /** 4016 * Whether this node is used more than once in context of other nodes. This method 4017 * is overwritten since it always returns `false` (assigns are unique). 4018 * 4019 * @return {boolean} A flag that indicates if there is more than one dependency to other nodes. Always `false`. 4020 */ 4021 hasDependencies() { 4022 return false; 4023 } 4024 generateNodeType(builder, output3) { 4025 return output3 !== "void" ? this.targetNode.getNodeType(builder) : "void"; 4026 } 4027 /** 4028 * Whether a split is required when assigning source to target. This can happen when the component length of 4029 * target and source data type does not match. 4030 * 4031 * @param {NodeBuilder} builder - The current node builder. 4032 * @return {boolean} Whether a split is required when assigning source to target. 4033 */ 4034 needsSplitAssign(builder) { 4035 const { targetNode } = this; 4036 if (builder.isAvailable("swizzleAssign") === false && targetNode.isSplitNode && targetNode.components.length > 1) { 4037 const targetLength = builder.getTypeLength(targetNode.node.getNodeType(builder)); 4038 const assignDifferentVector = vectorComponents.join("").slice(0, targetLength) !== targetNode.components; 4039 return assignDifferentVector; 4040 } 4041 return false; 4042 } 4043 setup(builder) { 4044 const { targetNode, sourceNode } = this; 4045 const scope = targetNode.getScope(); 4046 const scopeData = builder.getDataFromNode(scope); 4047 scopeData.assign = true; 4048 const properties = builder.getNodeProperties(this); 4049 properties.sourceNode = sourceNode; 4050 properties.targetNode = targetNode.context({ assign: true }); 4051 } 4052 generate(builder, output3) { 4053 const { targetNode, sourceNode } = builder.getNodeProperties(this); 4054 const needsSplitAssign = this.needsSplitAssign(builder); 4055 const target = targetNode.build(builder); 4056 const targetType = targetNode.getNodeType(builder); 4057 const source = sourceNode.build(builder, targetType); 4058 const sourceType = sourceNode.getNodeType(builder); 4059 const nodeData = builder.getDataFromNode(this); 4060 let snippet; 4061 if (nodeData.initialized === true) { 4062 if (output3 !== "void") { 4063 snippet = target; 4064 } 4065 } else if (needsSplitAssign) { 4066 const sourceVar = builder.getVarFromNode(this, null, targetType); 4067 const sourceProperty = builder.getPropertyName(sourceVar); 4068 builder.addLineFlowCode(`${sourceProperty} = ${source}`, this); 4069 const splitNode = targetNode.node; 4070 const splitTargetNode = splitNode.node.context({ assign: true }); 4071 const targetRoot = splitTargetNode.build(builder); 4072 for (let i = 0; i < splitNode.components.length; i++) { 4073 const component = splitNode.components[i]; 4074 builder.addLineFlowCode(`${targetRoot}.${component} = ${sourceProperty}[ ${i} ]`, this); 4075 } 4076 if (output3 !== "void") { 4077 snippet = target; 4078 } 4079 } else { 4080 snippet = `${target} = ${source}`; 4081 if (output3 === "void" || sourceType === "void") { 4082 builder.addLineFlowCode(snippet, this); 4083 if (output3 !== "void") { 4084 snippet = target; 4085 } 4086 } 4087 } 4088 nodeData.initialized = true; 4089 return builder.format(snippet, targetType, output3); 4090 } 4091}; 4092var assign = /* @__PURE__ */ nodeProxy(AssignNode).setParameterLength(2); 4093addMethodChaining("assign", assign); 4094var FunctionCallNode = class extends TempNode { 4095 static get type() { 4096 return "FunctionCallNode"; 4097 } 4098 /** 4099 * Constructs a new function call node. 4100 * 4101 * @param {?FunctionNode} functionNode - The function node. 4102 * @param {Object<string, Node>} [parameters={}] - The parameters for the function call. 4103 */ 4104 constructor(functionNode = null, parameters = {}) { 4105 super(); 4106 this.functionNode = functionNode; 4107 this.parameters = parameters; 4108 } 4109 /** 4110 * Sets the parameters of the function call node. 4111 * 4112 * @param {Object<string, Node>} parameters - The parameters to set. 4113 * @return {FunctionCallNode} A reference to this node. 4114 */ 4115 setParameters(parameters) { 4116 this.parameters = parameters; 4117 return this; 4118 } 4119 /** 4120 * Returns the parameters of the function call node. 4121 * 4122 * @return {Object<string, Node>} The parameters of this node. 4123 */ 4124 getParameters() { 4125 return this.parameters; 4126 } 4127 /** 4128 * Returns the type of this function call node. 4129 * 4130 * @param {NodeBuilder} builder - The current node builder. 4131 * @returns {string} The type of this node. 4132 */ 4133 generateNodeType(builder) { 4134 return this.functionNode.getNodeType(builder); 4135 } 4136 /** 4137 * Returns the function node of this function call node. 4138 * 4139 * @param {NodeBuilder} builder - The current node builder. 4140 * @param {string} [name] - The name of the member. 4141 * @returns {string} The type of the member. 4142 */ 4143 getMemberType(builder, name) { 4144 return this.functionNode.getMemberType(builder, name); 4145 } 4146 generate(builder) { 4147 const params = []; 4148 const functionNode = this.functionNode; 4149 const inputs = functionNode.getInputs(builder); 4150 const parameters = this.parameters; 4151 const generateInput = (node, inputNode) => { 4152 const type = inputNode.type; 4153 const pointer = type === "pointer"; 4154 let output3; 4155 if (pointer) output3 = "&" + node.build(builder); 4156 else output3 = node.build(builder, type); 4157 return output3; 4158 }; 4159 if (Array.isArray(parameters)) { 4160 if (parameters.length > inputs.length) { 4161 error("TSL: The number of provided parameters exceeds the expected number of inputs in 'Fn()'."); 4162 parameters.length = inputs.length; 4163 } else if (parameters.length < inputs.length) { 4164 error("TSL: The number of provided parameters is less than the expected number of inputs in 'Fn()'."); 4165 while (parameters.length < inputs.length) { 4166 parameters.push(float(0)); 4167 } 4168 } 4169 for (let i = 0; i < parameters.length; i++) { 4170 params.push(generateInput(parameters[i], inputs[i])); 4171 } 4172 } else { 4173 for (const inputNode of inputs) { 4174 const node = parameters[inputNode.name]; 4175 if (node !== void 0) { 4176 params.push(generateInput(node, inputNode)); 4177 } else { 4178 error(`TSL: Input '${inputNode.name}' not found in 'Fn()'.`); 4179 params.push(generateInput(float(0), inputNode)); 4180 } 4181 } 4182 } 4183 const functionName = functionNode.build(builder, "property"); 4184 return `${functionName}( ${params.join(", ")} )`; 4185 } 4186}; 4187var call = (func, ...params) => { 4188 params = params.length > 1 || params[0] && params[0].isNode === true ? nodeArray(params) : nodeObjects(params[0]); 4189 return new FunctionCallNode(nodeObject(func), params); 4190}; 4191addMethodChaining("call", call); 4192var _vectorOperators = { 4193 "==": "equal", 4194 "!=": "notEqual", 4195 "<": "lessThan", 4196 ">": "greaterThan", 4197 "<=": "lessThanEqual", 4198 ">=": "greaterThanEqual", 4199 "%": "mod" 4200}; 4201var OperatorNode = class _OperatorNode extends TempNode { 4202 static get type() { 4203 return "OperatorNode"; 4204 } 4205 /** 4206 * Constructs a new operator node. 4207 * 4208 * @param {string} op - The operator. 4209 * @param {Node} aNode - The first input. 4210 * @param {Node} bNode - The second input. 4211 * @param {...Node} params - Additional input parameters. 4212 */ 4213 constructor(op, aNode, bNode, ...params) { 4214 super(); 4215 if (params.length > 0) { 4216 let finalOp = new _OperatorNode(op, aNode, bNode); 4217 for (let i = 0; i < params.length - 1; i++) { 4218 finalOp = new _OperatorNode(op, finalOp, params[i]); 4219 } 4220 aNode = finalOp; 4221 bNode = params[params.length - 1]; 4222 } 4223 this.op = op; 4224 this.aNode = aNode; 4225 this.bNode = bNode; 4226 this.isOperatorNode = true; 4227 } 4228 /** 4229 * Returns the operator method name. 4230 * 4231 * @param {NodeBuilder} builder - The current node builder. 4232 * @param {string} output - The output type. 4233 * @returns {string} The operator method name. 4234 */ 4235 getOperatorMethod(builder, output3) { 4236 return builder.getMethod(_vectorOperators[this.op], output3); 4237 } 4238 /** 4239 * This method is overwritten since the node type is inferred from the operator 4240 * and the input node types. 4241 * 4242 * @param {NodeBuilder} builder - The current node builder. 4243 * @param {?string} [output=null] - The output type. 4244 * @return {string} The node type. 4245 */ 4246 generateNodeType(builder, output3 = null) { 4247 const op = this.op; 4248 const aNode = this.aNode; 4249 const bNode = this.bNode; 4250 const typeA = aNode.getNodeType(builder); 4251 const typeB = bNode ? bNode.getNodeType(builder) : null; 4252 if (typeA === "void" || typeB === "void") { 4253 return output3 || "void"; 4254 } else if (op === "%") { 4255 return typeA; 4256 } else if (op === "~" || op === "&" || op === "|" || op === "^" || op === ">>" || op === "<<") { 4257 return builder.getIntegerType(typeA); 4258 } else if (op === "!" || op === "&&" || op === "||" || op === "^^") { 4259 return "bool"; 4260 } else if (op === "==" || op === "!=" || op === "<" || op === ">" || op === "<=" || op === ">=") { 4261 const typeLength = Math.max(builder.getTypeLength(typeA), builder.getTypeLength(typeB)); 4262 return typeLength > 1 ? `bvec${typeLength}` : "bool"; 4263 } else { 4264 if (builder.isMatrix(typeA)) { 4265 if (typeB === "float") { 4266 return typeA; 4267 } else if (builder.isVector(typeB)) { 4268 return builder.getVectorFromMatrix(typeA); 4269 } else if (builder.isMatrix(typeB)) { 4270 return typeA; 4271 } 4272 } else if (builder.isMatrix(typeB)) { 4273 if (typeA === "float") { 4274 return typeB; 4275 } else if (builder.isVector(typeA)) { 4276 return builder.getVectorFromMatrix(typeB); 4277 } 4278 } 4279 if (builder.getTypeLength(typeB) > builder.getTypeLength(typeA)) { 4280 return typeB; 4281 } 4282 return typeA; 4283 } 4284 } 4285 generate(builder, output3) { 4286 const op = this.op; 4287 const { aNode, bNode } = this; 4288 const type = this.getNodeType(builder, output3); 4289 let typeA = null; 4290 let typeB = null; 4291 if (type !== "void") { 4292 typeA = aNode.getNodeType(builder); 4293 typeB = bNode ? bNode.getNodeType(builder) : null; 4294 if (op === "<" || op === ">" || op === "<=" || op === ">=" || op === "==" || op === "!=") { 4295 if (builder.isVector(typeA)) { 4296 typeB = typeA; 4297 } else if (builder.isVector(typeB)) { 4298 typeA = typeB; 4299 } else if (typeA !== typeB) { 4300 typeA = typeB = "float"; 4301 } 4302 } else if (op === ">>" || op === "<<") { 4303 typeA = type; 4304 typeB = builder.changeComponentType(typeB, "uint"); 4305 } else if (op === "%") { 4306 typeA = type; 4307 typeB = builder.isInteger(typeA) && builder.isInteger(typeB) ? typeB : typeA; 4308 } else if (builder.isMatrix(typeA)) { 4309 if (typeB === "float") { 4310 typeB = "float"; 4311 } else if (builder.isVector(typeB)) { 4312 typeB = builder.getVectorFromMatrix(typeA); 4313 } else if (builder.isMatrix(typeB)) ; 4314 else { 4315 typeA = typeB = type; 4316 } 4317 } else if (builder.isMatrix(typeB)) { 4318 if (typeA === "float") { 4319 typeA = "float"; 4320 } else if (builder.isVector(typeA)) { 4321 typeA = builder.getVectorFromMatrix(typeB); 4322 } else { 4323 typeA = typeB = type; 4324 } 4325 } else { 4326 typeA = typeB = type; 4327 } 4328 } else { 4329 typeA = typeB = type; 4330 } 4331 const a = aNode.build(builder, typeA); 4332 const b = bNode ? bNode.build(builder, typeB) : null; 4333 const fnOpSnippet = builder.getFunctionOperator(op); 4334 if (output3 !== "void") { 4335 const isGLSL = builder.renderer.coordinateSystem === WebGLCoordinateSystem; 4336 if (op === "==" || op === "!=" || op === "<" || op === ">" || op === "<=" || op === ">=") { 4337 if (isGLSL) { 4338 if (builder.isVector(typeA)) { 4339 return builder.format(`${this.getOperatorMethod(builder, output3)}( ${a}, ${b} )`, type, output3); 4340 } else { 4341 return builder.format(`( ${a} ${op} ${b} )`, type, output3); 4342 } 4343 } else { 4344 return builder.format(`( ${a} ${op} ${b} )`, type, output3); 4345 } 4346 } else if (op === "%") { 4347 if (builder.isInteger(typeB)) { 4348 return builder.format(`( ${a} % ${b} )`, type, output3); 4349 } else { 4350 return builder.format(`${this.getOperatorMethod(builder, type)}( ${a}, ${b} )`, type, output3); 4351 } 4352 } else if (op === "!" || op === "~") { 4353 return builder.format(`(${op}${a})`, typeA, output3); 4354 } else if (fnOpSnippet) { 4355 return builder.format(`${fnOpSnippet}( ${a}, ${b} )`, type, output3); 4356 } else { 4357 if (builder.isMatrix(typeA) && typeB === "float") { 4358 return builder.format(`( ${b} ${op} ${a} )`, type, output3); 4359 } else if (typeA === "float" && builder.isMatrix(typeB)) { 4360 return builder.format(`${a} ${op} ${b}`, type, output3); 4361 } else { 4362 let snippet = `( ${a} ${op} ${b} )`; 4363 if (!isGLSL && type === "bool" && builder.isVector(typeA) && builder.isVector(typeB)) { 4364 snippet = `all${snippet}`; 4365 } 4366 return builder.format(snippet, type, output3); 4367 } 4368 } 4369 } else if (typeA !== "void") { 4370 if (fnOpSnippet) { 4371 return builder.format(`${fnOpSnippet}( ${a}, ${b} )`, type, output3); 4372 } else { 4373 if (builder.isMatrix(typeA) && typeB === "float") { 4374 return builder.format(`${b} ${op} ${a}`, type, output3); 4375 } else { 4376 return builder.format(`${a} ${op} ${b}`, type, output3); 4377 } 4378 } 4379 } 4380 } 4381 serialize(data) { 4382 super.serialize(data); 4383 data.op = this.op; 4384 } 4385 deserialize(data) { 4386 super.deserialize(data); 4387 this.op = data.op; 4388 } 4389}; 4390var add = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "+").setParameterLength(2, Infinity).setName("add"); 4391var sub = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "-").setParameterLength(2, Infinity).setName("sub"); 4392var mul = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "*").setParameterLength(2, Infinity).setName("mul"); 4393var div = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "/").setParameterLength(2, Infinity).setName("div"); 4394var mod = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "%").setParameterLength(2).setName("mod"); 4395var equal = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "==").setParameterLength(2).setName("equal"); 4396var notEqual = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "!=").setParameterLength(2).setName("notEqual"); 4397var lessThan = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "<").setParameterLength(2).setName("lessThan"); 4398var greaterThan = /* @__PURE__ */ nodeProxyIntent(OperatorNode, ">").setParameterLength(2).setName("greaterThan"); 4399var lessThanEqual = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "<=").setParameterLength(2).setName("lessThanEqual"); 4400var greaterThanEqual = /* @__PURE__ */ nodeProxyIntent(OperatorNode, ">=").setParameterLength(2).setName("greaterThanEqual"); 4401var and = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "&&").setParameterLength(2, Infinity).setName("and"); 4402var or = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "||").setParameterLength(2, Infinity).setName("or"); 4403var not = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "!").setParameterLength(1).setName("not"); 4404var xor = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "^^").setParameterLength(2).setName("xor"); 4405var bitAnd = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "&").setParameterLength(2).setName("bitAnd"); 4406var bitNot = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "~").setParameterLength(1).setName("bitNot"); 4407var bitOr = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "|").setParameterLength(2).setName("bitOr"); 4408var bitXor = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "^").setParameterLength(2).setName("bitXor"); 4409var shiftLeft = /* @__PURE__ */ nodeProxyIntent(OperatorNode, "<<").setParameterLength(2).setName("shiftLeft"); 4410var shiftRight = /* @__PURE__ */ nodeProxyIntent(OperatorNode, ">>").setParameterLength(2).setName("shiftRight"); 4411var incrementBefore = Fn(([a]) => { 4412 a.addAssign(1); 4413 return a; 4414}); 4415var decrementBefore = Fn(([a]) => { 4416 a.subAssign(1); 4417 return a; 4418}); 4419var increment = /* @__PURE__ */ Fn(([a]) => { 4420 const temp = int(a).toConst(); 4421 a.addAssign(1); 4422 return temp; 4423}); 4424var decrement = /* @__PURE__ */ Fn(([a]) => { 4425 const temp = int(a).toConst(); 4426 a.subAssign(1); 4427 return temp; 4428}); 4429addMethodChaining("add", add); 4430addMethodChaining("sub", sub); 4431addMethodChaining("mul", mul); 4432addMethodChaining("div", div); 4433addMethodChaining("mod", mod); 4434addMethodChaining("equal", equal); 4435addMethodChaining("notEqual", notEqual); 4436addMethodChaining("lessThan", lessThan); 4437addMethodChaining("greaterThan", greaterThan); 4438addMethodChaining("lessThanEqual", lessThanEqual); 4439addMethodChaining("greaterThanEqual", greaterThanEqual); 4440addMethodChaining("and", and); 4441addMethodChaining("or", or); 4442addMethodChaining("not", not); 4443addMethodChaining("xor", xor); 4444addMethodChaining("bitAnd", bitAnd); 4445addMethodChaining("bitNot", bitNot); 4446addMethodChaining("bitOr", bitOr); 4447addMethodChaining("bitXor", bitXor); 4448addMethodChaining("shiftLeft", shiftLeft); 4449addMethodChaining("shiftRight", shiftRight); 4450addMethodChaining("incrementBefore", incrementBefore); 4451addMethodChaining("decrementBefore", decrementBefore); 4452addMethodChaining("increment", increment); 4453addMethodChaining("decrement", decrement); 4454var modInt = (a, b) => { 4455 warn('TSL: "modInt()" is deprecated. Use "mod( int( ... ) )" instead.', new StackTrace()); 4456 return mod(int(a), int(b)); 4457}; 4458addMethodChaining("modInt", modInt); 4459var MathNode = class _MathNode extends TempNode { 4460 static get type() { 4461 return "MathNode"; 4462 } 4463 /** 4464 * Constructs a new math node. 4465 * 4466 * @param {string} method - The method name. 4467 * @param {Node} aNode - The first input. 4468 * @param {?Node} [bNode=null] - The second input. 4469 * @param {?Node} [cNode=null] - The third input. 4470 */ 4471 constructor(method, aNode, bNode = null, cNode = null) { 4472 super(); 4473 if ((method === _MathNode.MAX || method === _MathNode.MIN) && arguments.length > 3) { 4474 let finalOp = new _MathNode(method, aNode, bNode); 4475 for (let i = 2; i < arguments.length - 1; i++) { 4476 finalOp = new _MathNode(method, finalOp, arguments[i]); 4477 } 4478 aNode = finalOp; 4479 bNode = arguments[arguments.length - 1]; 4480 cNode = null; 4481 } 4482 this.method = method; 4483 this.aNode = aNode; 4484 this.bNode = bNode; 4485 this.cNode = cNode; 4486 this.isMathNode = true; 4487 } 4488 /** 4489 * The input type is inferred from the node types of the input nodes. 4490 * 4491 * @param {NodeBuilder} builder - The current node builder. 4492 * @return {string} The input type. 4493 */ 4494 getInputType(builder) { 4495 const aType = this.aNode.getNodeType(builder); 4496 const bType = this.bNode ? this.bNode.getNodeType(builder) : null; 4497 const cType = this.cNode ? this.cNode.getNodeType(builder) : null; 4498 const aLen = builder.isMatrix(aType) ? 0 : builder.getTypeLength(aType); 4499 const bLen = builder.isMatrix(bType) ? 0 : builder.getTypeLength(bType); 4500 const cLen = builder.isMatrix(cType) ? 0 : builder.getTypeLength(cType); 4501 if (aLen > bLen && aLen > cLen) { 4502 return aType; 4503 } else if (bLen > cLen) { 4504 return bType; 4505 } else if (cLen > aLen) { 4506 return cType; 4507 } 4508 return aType; 4509 } 4510 /** 4511 * The selected method as well as the input type determine the node type of this node. 4512 * 4513 * @param {NodeBuilder} builder - The current node builder. 4514 * @return {string} The node type. 4515 */ 4516 generateNodeType(builder) { 4517 const method = this.method; 4518 if (method === _MathNode.LENGTH || method === _MathNode.DISTANCE || method === _MathNode.DOT) { 4519 return "float"; 4520 } else if (method === _MathNode.CROSS) { 4521 return "vec3"; 4522 } else if (method === _MathNode.ALL || method === _MathNode.ANY) { 4523 return "bool"; 4524 } else if (method === _MathNode.EQUALS) { 4525 return builder.changeComponentType(this.aNode.getNodeType(builder), "bool"); 4526 } else { 4527 return this.getInputType(builder); 4528 } 4529 } 4530 setup(builder) { 4531 const { aNode, bNode, method } = this; 4532 let outputNode = null; 4533 if (method === _MathNode.ONE_MINUS) { 4534 outputNode = sub(1, aNode); 4535 } else if (method === _MathNode.RECIPROCAL) { 4536 outputNode = div(1, aNode); 4537 } else if (method === _MathNode.DIFFERENCE) { 4538 outputNode = abs(sub(aNode, bNode)); 4539 } else if (method === _MathNode.TRANSFORM_DIRECTION) { 4540 let tA = aNode; 4541 let tB = bNode; 4542 if (builder.isMatrix(tA.getNodeType(builder))) { 4543 tB = vec4(vec3(tB), 0); 4544 } else { 4545 tA = vec4(vec3(tA), 0); 4546 } 4547 const mulNode = mul(tA, tB).xyz; 4548 outputNode = normalize(mulNode); 4549 } 4550 if (outputNode !== null) { 4551 return outputNode; 4552 } else { 4553 return super.setup(builder); 4554 } 4555 } 4556 generate(builder, output3) { 4557 const properties = builder.getNodeProperties(this); 4558 if (properties.outputNode) { 4559 return super.generate(builder, output3); 4560 } 4561 let method = this.method; 4562 const type = this.getNodeType(builder); 4563 const inputType = this.getInputType(builder); 4564 const a = this.aNode; 4565 const b = this.bNode; 4566 const c = this.cNode; 4567 const coordinateSystem = builder.renderer.coordinateSystem; 4568 if (method === _MathNode.NEGATE) { 4569 return builder.format("( - " + a.build(builder, inputType) + " )", type, output3); 4570 } else { 4571 const params = []; 4572 if (method === _MathNode.CROSS) { 4573 params.push( 4574 a.build(builder, type), 4575 b.build(builder, type) 4576 ); 4577 } else if (coordinateSystem === WebGLCoordinateSystem && method === _MathNode.STEP) { 4578 params.push( 4579 a.build(builder, builder.getTypeLength(a.getNodeType(builder)) === 1 ? "float" : inputType), 4580 b.build(builder, inputType) 4581 ); 4582 } else if (coordinateSystem === WebGLCoordinateSystem && (method === _MathNode.MIN || method === _MathNode.MAX)) { 4583 params.push( 4584 a.build(builder, inputType), 4585 b.build(builder, builder.getTypeLength(b.getNodeType(builder)) === 1 ? "float" : inputType) 4586 ); 4587 } else if (method === _MathNode.REFRACT) { 4588 params.push( 4589 a.build(builder, inputType), 4590 b.build(builder, inputType), 4591 c.build(builder, "float") 4592 ); 4593 } else if (method === _MathNode.MIX) { 4594 params.push( 4595 a.build(builder, inputType), 4596 b.build(builder, inputType), 4597 c.build(builder, builder.getTypeLength(c.getNodeType(builder)) === 1 ? "float" : inputType) 4598 ); 4599 } else { 4600 if (coordinateSystem === WebGPUCoordinateSystem && method === _MathNode.ATAN && b !== null) { 4601 method = "atan2"; 4602 } 4603 if (builder.shaderStage !== "fragment" && (method === _MathNode.DFDX || method === _MathNode.DFDY)) { 4604 warn(`TSL: '${method}' is not supported in the ${builder.shaderStage} stage.`, this.stackTrace); 4605 method = "/*" + method + "*/"; 4606 } 4607 params.push(a.build(builder, inputType)); 4608 if (b !== null) params.push(b.build(builder, inputType)); 4609 if (c !== null) params.push(c.build(builder, inputType)); 4610 } 4611 return builder.format(`${builder.getMethod(method, type)}( ${params.join(", ")} )`, type, output3); 4612 } 4613 } 4614 serialize(data) { 4615 super.serialize(data); 4616 data.method = this.method; 4617 } 4618 deserialize(data) { 4619 super.deserialize(data); 4620 this.method = data.method; 4621 } 4622}; 4623MathNode.ALL = "all"; 4624MathNode.ANY = "any"; 4625MathNode.RADIANS = "radians"; 4626MathNode.DEGREES = "degrees"; 4627MathNode.EXP = "exp"; 4628MathNode.EXP2 = "exp2"; 4629MathNode.LOG = "log"; 4630MathNode.LOG2 = "log2"; 4631MathNode.SQRT = "sqrt"; 4632MathNode.INVERSE_SQRT = "inversesqrt"; 4633MathNode.FLOOR = "floor"; 4634MathNode.CEIL = "ceil"; 4635MathNode.NORMALIZE = "normalize"; 4636MathNode.FRACT = "fract"; 4637MathNode.SIN = "sin"; 4638MathNode.SINH = "sinh"; 4639MathNode.COS = "cos"; 4640MathNode.COSH = "cosh"; 4641MathNode.TAN = "tan"; 4642MathNode.TANH = "tanh"; 4643MathNode.ASIN = "asin"; 4644MathNode.ASINH = "asinh"; 4645MathNode.ACOS = "acos"; 4646MathNode.ACOSH = "acosh"; 4647MathNode.ATAN = "atan"; 4648MathNode.ATANH = "atanh"; 4649MathNode.ABS = "abs"; 4650MathNode.SIGN = "sign"; 4651MathNode.LENGTH = "length"; 4652MathNode.NEGATE = "negate"; 4653MathNode.ONE_MINUS = "oneMinus"; 4654MathNode.DFDX = "dFdx"; 4655MathNode.DFDY = "dFdy"; 4656MathNode.ROUND = "round"; 4657MathNode.RECIPROCAL = "reciprocal"; 4658MathNode.TRUNC = "trunc"; 4659MathNode.FWIDTH = "fwidth"; 4660MathNode.TRANSPOSE = "transpose"; 4661MathNode.DETERMINANT = "determinant"; 4662MathNode.INVERSE = "inverse"; 4663MathNode.EQUALS = "equals"; 4664MathNode.MIN = "min"; 4665MathNode.MAX = "max"; 4666MathNode.STEP = "step"; 4667MathNode.REFLECT = "reflect"; 4668MathNode.DISTANCE = "distance"; 4669MathNode.DIFFERENCE = "difference"; 4670MathNode.DOT = "dot"; 4671MathNode.CROSS = "cross"; 4672MathNode.POW = "pow"; 4673MathNode.TRANSFORM_DIRECTION = "transformDirection"; 4674MathNode.MIX = "mix"; 4675MathNode.CLAMP = "clamp"; 4676MathNode.REFRACT = "refract"; 4677MathNode.SMOOTHSTEP = "smoothstep"; 4678MathNode.FACEFORWARD = "faceforward"; 4679var EPSILON = /* @__PURE__ */ float(1e-6); 4680var INFINITY = /* @__PURE__ */ float(1e6); 4681var PI = /* @__PURE__ */ float(Math.PI); 4682var PI2 = /* @__PURE__ */ float(Math.PI * 2); 4683var TWO_PI = /* @__PURE__ */ float(Math.PI * 2); 4684var HALF_PI = /* @__PURE__ */ float(Math.PI * 0.5); 4685var all = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ALL).setParameterLength(1); 4686var any = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ANY).setParameterLength(1); 4687var radians = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.RADIANS).setParameterLength(1); 4688var degrees = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DEGREES).setParameterLength(1); 4689var exp = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.EXP).setParameterLength(1); 4690var exp2 = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.EXP2).setParameterLength(1); 4691var log2 = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.LOG).setParameterLength(1); 4692var log22 = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.LOG2).setParameterLength(1); 4693var sqrt = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.SQRT).setParameterLength(1); 4694var inverseSqrt = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.INVERSE_SQRT).setParameterLength(1); 4695var floor = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.FLOOR).setParameterLength(1); 4696var ceil = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.CEIL).setParameterLength(1); 4697var normalize = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.NORMALIZE).setParameterLength(1); 4698var fract = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.FRACT).setParameterLength(1); 4699var sin = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.SIN).setParameterLength(1); 4700var sinh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.SINH).setParameterLength(1); 4701var cos = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.COS).setParameterLength(1); 4702var cosh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.COSH).setParameterLength(1); 4703var tan = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.TAN).setParameterLength(1); 4704var tanh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.TANH).setParameterLength(1); 4705var asin = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ASIN).setParameterLength(1); 4706var asinh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ASINH).setParameterLength(1); 4707var acos = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ACOS).setParameterLength(1); 4708var acosh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ACOSH).setParameterLength(1); 4709var atan = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ATAN).setParameterLength(1, 2); 4710var atanh = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ATANH).setParameterLength(1); 4711var abs = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ABS).setParameterLength(1); 4712var sign = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.SIGN).setParameterLength(1); 4713var length = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.LENGTH).setParameterLength(1); 4714var negate = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.NEGATE).setParameterLength(1); 4715var oneMinus = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ONE_MINUS).setParameterLength(1); 4716var dFdx = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DFDX).setParameterLength(1); 4717var dFdy = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DFDY).setParameterLength(1); 4718var round = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.ROUND).setParameterLength(1); 4719var reciprocal = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.RECIPROCAL).setParameterLength(1); 4720var trunc = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.TRUNC).setParameterLength(1); 4721var fwidth = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.FWIDTH).setParameterLength(1); 4722var transpose = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.TRANSPOSE).setParameterLength(1); 4723var determinant = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DETERMINANT).setParameterLength(1); 4724var inverse = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.INVERSE).setParameterLength(1); 4725var min$1 = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.MIN).setParameterLength(2, Infinity); 4726var max$1 = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.MAX).setParameterLength(2, Infinity); 4727var step = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.STEP).setParameterLength(2); 4728var reflect = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.REFLECT).setParameterLength(2); 4729var distance = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DISTANCE).setParameterLength(2); 4730var difference = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DIFFERENCE).setParameterLength(2); 4731var dot = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.DOT).setParameterLength(2); 4732var cross = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.CROSS).setParameterLength(2); 4733var pow = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.POW).setParameterLength(2); 4734var pow2 = (x) => mul(x, x); 4735var pow3 = (x) => mul(x, x, x); 4736var pow4 = (x) => mul(x, x, x, x); 4737var transformDirection = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.TRANSFORM_DIRECTION).setParameterLength(2); 4738var cbrt = (a) => mul(sign(a), pow(abs(a), 1 / 3)); 4739var lengthSq = (a) => dot(a, a); 4740var mix = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.MIX).setParameterLength(3); 4741var clamp = (value, low = 0, high = 1) => new MathNode(MathNode.CLAMP, nodeObject(value), nodeObject(low), nodeObject(high)); 4742var saturate = (value) => clamp(value); 4743var refract = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.REFRACT).setParameterLength(3); 4744var smoothstep = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.SMOOTHSTEP).setParameterLength(3); 4745var faceForward = /* @__PURE__ */ nodeProxyIntent(MathNode, MathNode.FACEFORWARD).setParameterLength(3); 4746var rand = /* @__PURE__ */ Fn(([uv3]) => { 4747 const a = 12.9898, b = 78.233, c = 43758.5453; 4748 const dt = dot(uv3.xy, vec2(a, b)), sn = mod(dt, PI); 4749 return fract(sin(sn).mul(c)); 4750}); 4751var mixElement = (t, e1, e2) => mix(e1, e2, t); 4752var smoothstepElement = (x, low, high) => smoothstep(low, high, x); 4753var stepElement = (x, edge) => step(edge, x); 4754var faceforward = faceForward; 4755var inversesqrt = inverseSqrt; 4756addMethodChaining("all", all); 4757addMethodChaining("any", any); 4758addMethodChaining("radians", radians); 4759addMethodChaining("degrees", degrees); 4760addMethodChaining("exp", exp); 4761addMethodChaining("exp2", exp2); 4762addMethodChaining("log", log2); 4763addMethodChaining("log2", log22); 4764addMethodChaining("sqrt", sqrt); 4765addMethodChaining("inverseSqrt", inverseSqrt); 4766addMethodChaining("floor", floor); 4767addMethodChaining("ceil", ceil); 4768addMethodChaining("normalize", normalize); 4769addMethodChaining("fract", fract); 4770addMethodChaining("sin", sin); 4771addMethodChaining("sinh", sinh); 4772addMethodChaining("cos", cos); 4773addMethodChaining("cosh", cosh); 4774addMethodChaining("tan", tan); 4775addMethodChaining("tanh", tanh); 4776addMethodChaining("asin", asin); 4777addMethodChaining("asinh", asinh); 4778addMethodChaining("acos", acos); 4779addMethodChaining("acosh", acosh); 4780addMethodChaining("atan", atan); 4781addMethodChaining("atanh", atanh); 4782addMethodChaining("abs", abs); 4783addMethodChaining("sign", sign); 4784addMethodChaining("length", length); 4785addMethodChaining("lengthSq", lengthSq); 4786addMethodChaining("negate", negate); 4787addMethodChaining("oneMinus", oneMinus); 4788addMethodChaining("dFdx", dFdx); 4789addMethodChaining("dFdy", dFdy); 4790addMethodChaining("round", round); 4791addMethodChaining("reciprocal", reciprocal); 4792addMethodChaining("trunc", trunc); 4793addMethodChaining("fwidth", fwidth); 4794addMethodChaining("min", min$1); 4795addMethodChaining("max", max$1); 4796addMethodChaining("step", stepElement); 4797addMethodChaining("reflect", reflect); 4798addMethodChaining("distance", distance); 4799addMethodChaining("dot", dot); 4800addMethodChaining("cross", cross); 4801addMethodChaining("pow", pow); 4802addMethodChaining("pow2", pow2); 4803addMethodChaining("pow3", pow3); 4804addMethodChaining("pow4", pow4); 4805addMethodChaining("transformDirection", transformDirection); 4806addMethodChaining("mix", mixElement); 4807addMethodChaining("clamp", clamp); 4808addMethodChaining("refract", refract); 4809addMethodChaining("smoothstep", smoothstepElement); 4810addMethodChaining("faceForward", faceForward); 4811addMethodChaining("difference", difference); 4812addMethodChaining("saturate", saturate); 4813addMethodChaining("cbrt", cbrt); 4814addMethodChaining("transpose", transpose); 4815addMethodChaining("determinant", determinant); 4816addMethodChaining("inverse", inverse); 4817addMethodChaining("rand", rand); 4818var ConditionalNode = class extends Node2 { 4819 static get type() { 4820 return "ConditionalNode"; 4821 } 4822 /** 4823 * Constructs a new conditional node. 4824 * 4825 * @param {Node} condNode - The node that defines the condition. 4826 * @param {Node} ifNode - The node that is evaluate when the condition ends up `true`. 4827 * @param {?Node} [elseNode=null] - The node that is evaluate when the condition ends up `false`. 4828 */ 4829 constructor(condNode, ifNode, elseNode = null) { 4830 super(); 4831 this.condNode = condNode; 4832 this.ifNode = ifNode; 4833 this.elseNode = elseNode; 4834 } 4835 /** 4836 * This method is overwritten since the node type is inferred from the if/else 4837 * nodes. 4838 * 4839 * @param {NodeBuilder} builder - The current node builder. 4840 * @return {string} The node type. 4841 */ 4842 generateNodeType(builder) { 4843 const { ifNode, elseNode } = builder.getNodeProperties(this); 4844 if (ifNode === void 0) { 4845 builder.flowBuildStage(this, "setup"); 4846 return this.getNodeType(builder); 4847 } 4848 const ifType = ifNode.getNodeType(builder); 4849 if (elseNode !== null) { 4850 const elseType = elseNode.getNodeType(builder); 4851 if (builder.getTypeLength(elseType) > builder.getTypeLength(ifType)) { 4852 return elseType; 4853 } 4854 } 4855 return ifType; 4856 } 4857 setup(builder) { 4858 const condNode = this.condNode; 4859 const ifNode = this.ifNode.isolate(); 4860 const elseNode = this.elseNode ? this.elseNode.isolate() : null; 4861 const currentNodeBlock = builder.context.nodeBlock; 4862 builder.getDataFromNode(ifNode).parentNodeBlock = currentNodeBlock; 4863 if (elseNode !== null) builder.getDataFromNode(elseNode).parentNodeBlock = currentNodeBlock; 4864 const isUniformFlow = builder.context.uniformFlow; 4865 const properties = builder.getNodeProperties(this); 4866 properties.condNode = condNode; 4867 properties.ifNode = isUniformFlow ? ifNode : ifNode.context({ nodeBlock: ifNode }); 4868 properties.elseNode = elseNode ? isUniformFlow ? elseNode : elseNode.context({ nodeBlock: elseNode }) : null; 4869 } 4870 generate(builder, output3) { 4871 const type = this.getNodeType(builder); 4872 const nodeData = builder.getDataFromNode(this); 4873 if (nodeData.nodeProperty !== void 0) { 4874 return nodeData.nodeProperty; 4875 } 4876 const { condNode, ifNode, elseNode } = builder.getNodeProperties(this); 4877 const functionNode = builder.currentFunctionNode; 4878 const needsOutput = output3 !== "void"; 4879 const nodeProperty = needsOutput ? property(type).build(builder) : ""; 4880 nodeData.nodeProperty = nodeProperty; 4881 const nodeSnippet = condNode.build(builder, "bool"); 4882 const isUniformFlow = builder.context.uniformFlow; 4883 if (isUniformFlow && elseNode !== null) { 4884 const ifSnippet2 = ifNode.build(builder, type); 4885 const elseSnippet = elseNode.build(builder, type); 4886 const mathSnippet = builder.getTernary(nodeSnippet, ifSnippet2, elseSnippet); 4887 return builder.format(mathSnippet, type, output3); 4888 } 4889 builder.addFlowCode(` 4890${builder.tab}if ( ${nodeSnippet} ) { 4891 4892`).addFlowTab(); 4893 let ifSnippet = ifNode.build(builder, type); 4894 if (ifSnippet) { 4895 if (needsOutput) { 4896 ifSnippet = nodeProperty + " = " + ifSnippet + ";"; 4897 } else { 4898 ifSnippet = "return " + ifSnippet + ";"; 4899 if (functionNode === null) { 4900 warn("TSL: Return statement used in an inline 'Fn()'. Define a layout struct to allow return values.", this.stackTrace); 4901 ifSnippet = "// " + ifSnippet; 4902 } 4903 } 4904 } 4905 builder.removeFlowTab().addFlowCode(builder.tab + " " + ifSnippet + "\n\n" + builder.tab + "}"); 4906 if (elseNode !== null) { 4907 builder.addFlowCode(" else {\n\n").addFlowTab(); 4908 let elseSnippet = elseNode.build(builder, type); 4909 if (elseSnippet) { 4910 if (needsOutput) { 4911 elseSnippet = nodeProperty + " = " + elseSnippet + ";"; 4912 } else { 4913 elseSnippet = "return " + elseSnippet + ";"; 4914 if (functionNode === null) { 4915 warn("TSL: Return statement used in an inline 'Fn()'. Define a layout struct to allow return values.", this.stackTrace); 4916 elseSnippet = "// " + elseSnippet; 4917 } 4918 } 4919 } 4920 builder.removeFlowTab().addFlowCode(builder.tab + " " + elseSnippet + "\n\n" + builder.tab + "}\n\n"); 4921 } else { 4922 builder.addFlowCode("\n\n"); 4923 } 4924 return builder.format(nodeProperty, type, output3); 4925 } 4926}; 4927var select = /* @__PURE__ */ nodeProxy(ConditionalNode).setParameterLength(2, 3); 4928addMethodChaining("select", select); 4929var ContextNode = class extends Node2 { 4930 static get type() { 4931 return "ContextNode"; 4932 } 4933 /** 4934 * Constructs a new context node. 4935 * 4936 * @param {Node} node - The node whose context should be modified. 4937 * @param {Object} [value={}] - The modified context data. 4938 */ 4939 constructor(node = null, value = {}) { 4940 super(); 4941 this.isContextNode = true; 4942 this.node = node; 4943 this.value = value; 4944 } 4945 /** 4946 * This method is overwritten to ensure it returns the reference to {@link ContextNode#node}. 4947 * 4948 * @return {Node} A reference to {@link ContextNode#node}. 4949 */ 4950 getScope() { 4951 return this.node.getScope(); 4952 } 4953 /** 4954 * This method is overwritten to ensure it returns the type of {@link ContextNode#node}. 4955 * 4956 * @param {NodeBuilder} builder - The current node builder. 4957 * @return {string} The node type. 4958 */ 4959 generateNodeType(builder) { 4960 return this.node.getNodeType(builder); 4961 } 4962 /** 4963 * Gathers the context data from all parent context nodes. 4964 * 4965 * @return {Object} The gathered context data. 4966 */ 4967 getFlowContextData() { 4968 const children2 = []; 4969 this.traverse((node) => { 4970 if (node.isContextNode === true) { 4971 children2.push(node.value); 4972 } 4973 }); 4974 return Object.assign({}, ...children2); 4975 } 4976 /** 4977 * This method is overwritten to ensure it returns the member type of {@link ContextNode#node}. 4978 * 4979 * @param {NodeBuilder} builder - The current node builder. 4980 * @param {string} name - The member name. 4981 * @returns {string} The member type. 4982 */ 4983 getMemberType(builder, name) { 4984 return this.node.getMemberType(builder, name); 4985 } 4986 analyze(builder) { 4987 const previousContext = builder.addContext(this.value); 4988 this.node.build(builder); 4989 builder.setContext(previousContext); 4990 } 4991 setup(builder) { 4992 const previousContext = builder.addContext(this.value); 4993 this.node.build(builder); 4994 builder.setContext(previousContext); 4995 } 4996 generate(builder, output3) { 4997 const previousContext = builder.addContext(this.value); 4998 const snippet = this.node.build(builder, output3); 4999 builder.setContext(previousContext); 5000 return snippet; 5001 } 5002}; 5003var context = (nodeOrValue = null, value = {}) => { 5004 let node = nodeOrValue; 5005 if (node === null || node.isNode !== true) { 5006 value = node || value; 5007 node = null; 5008 } 5009 return new ContextNode(node, value); 5010}; 5011var uniformFlow = (node) => context(node, { uniformFlow: true }); 5012var setName = (node, name) => context(node, { nodeName: name }); 5013function builtinShadowContext(shadowNode, light, node = null) { 5014 return context(node, { 5015 getShadow: ({ light: shadowLight, shadowColorNode }) => { 5016 if (light === shadowLight) { 5017 return shadowColorNode.mul(shadowNode); 5018 } 5019 return shadowColorNode; 5020 } 5021 }); 5022} 5023function builtinAOContext(aoNode, node = null) { 5024 return context(node, { 5025 getAO: (inputNode, { material }) => { 5026 if (material.transparent === true) return inputNode; 5027 return inputNode !== null ? inputNode.mul(aoNode) : aoNode; 5028 } 5029 }); 5030} 5031function label(node, name) { 5032 warn('TSL: "label()" has been deprecated. Use "setName()" instead.'); 5033 return setName(node, name); 5034} 5035addMethodChaining("context", context); 5036addMethodChaining("label", label); 5037addMethodChaining("uniformFlow", uniformFlow); 5038addMethodChaining("setName", setName); 5039addMethodChaining("builtinShadowContext", (node, shadowNode, light) => builtinShadowContext(shadowNode, light, node)); 5040addMethodChaining("builtinAOContext", (node, aoValue) => builtinAOContext(aoValue, node)); 5041var VarNode = class extends Node2 { 5042 static get type() { 5043 return "VarNode"; 5044 } 5045 /** 5046 * Constructs a new variable node. 5047 * 5048 * @param {Node} node - The node for which a variable should be created. 5049 * @param {?string} [name=null] - The name of the variable in the shader. 5050 * @param {boolean} [readOnly=false] - The read-only flag. 5051 */ 5052 constructor(node, name = null, readOnly = false) { 5053 super(); 5054 this.node = node; 5055 this.name = name; 5056 this.global = true; 5057 this.isVarNode = true; 5058 this.readOnly = readOnly; 5059 this.parents = true; 5060 this.intent = false; 5061 } 5062 /** 5063 * Sets the intent flag for this node. 5064 * 5065 * This flag is used to indicate that this node is used for intent 5066 * and should not be built directly. Instead, it is used to indicate that 5067 * the node should be treated as a variable intent. 5068 * 5069 * It's useful for assigning variables without needing creating a new variable node. 5070 * 5071 * @param {boolean} value - The value to set for the intent flag. 5072 * @returns {VarNode} This node. 5073 */ 5074 setIntent(value) { 5075 this.intent = value; 5076 return this; 5077 } 5078 /** 5079 * Checks if this node is used for intent. 5080 * 5081 * @param {NodeBuilder} builder - The node builder. 5082 * @returns {boolean} Whether this node is used for intent. 5083 */ 5084 isIntent(builder) { 5085 const data = builder.getDataFromNode(this); 5086 if (data.forceDeclaration === true) return false; 5087 return this.intent; 5088 } 5089 /** 5090 * Returns the intent flag of this node. 5091 * 5092 * @return {boolean} The intent flag. 5093 */ 5094 getIntent() { 5095 return this.intent; 5096 } 5097 getMemberType(builder, name) { 5098 return this.node.getMemberType(builder, name); 5099 } 5100 getElementType(builder) { 5101 return this.node.getElementType(builder); 5102 } 5103 generateNodeType(builder) { 5104 return this.node.getNodeType(builder); 5105 } 5106 getArrayCount(builder) { 5107 return this.node.getArrayCount(builder); 5108 } 5109 isAssign(builder) { 5110 const data = builder.getDataFromNode(this); 5111 return data.assign; 5112 } 5113 build(...params) { 5114 const builder = params[0]; 5115 if (this._hasStack(builder) === false && builder.buildStage === "setup") { 5116 if (builder.context.nodeLoop || builder.context.nodeBlock) { 5117 let addBefore = false; 5118 if (this.node.isShaderCallNodeInternal && this.node.shaderNode.getLayout() === null) { 5119 if (builder.fnCall && builder.fnCall.shaderNode) { 5120 const shaderNodeData = builder.getDataFromNode(this.node.shaderNode); 5121 if (shaderNodeData.hasLoop) { 5122 const data = builder.getDataFromNode(this); 5123 data.forceDeclaration = true; 5124 addBefore = true; 5125 } 5126 } 5127 } 5128 const baseStack = builder.getBaseStack(); 5129 if (addBefore) { 5130 baseStack.addToStackBefore(this); 5131 } else { 5132 baseStack.addToStack(this); 5133 } 5134 } 5135 } 5136 if (this.isIntent(builder)) { 5137 if (this.isAssign(builder) !== true) { 5138 return this.node.build(...params); 5139 } 5140 } 5141 return super.build(...params); 5142 } 5143 generate(builder) { 5144 const { node, name, readOnly } = this; 5145 const { renderer } = builder; 5146 const isWebGPUBackend = renderer.backend.isWebGPUBackend === true; 5147 let isDeterministic = false; 5148 let shouldTreatAsReadOnly = false; 5149 if (readOnly) { 5150 isDeterministic = builder.isDeterministic(node); 5151 shouldTreatAsReadOnly = isWebGPUBackend ? readOnly : isDeterministic; 5152 } 5153 const nodeType = this.getNodeType(builder); 5154 if (nodeType == "void") { 5155 if (this.isIntent(builder) !== true) { 5156 error('TSL: ".toVar()" can not be used with void type.', this.stackTrace); 5157 } 5158 const snippet2 = node.build(builder); 5159 return snippet2; 5160 } 5161 const vectorType = builder.getVectorType(nodeType); 5162 const snippet = node.build(builder, vectorType); 5163 const nodeVar = builder.getVarFromNode(this, name, vectorType, void 0, shouldTreatAsReadOnly); 5164 const propertyName = builder.getPropertyName(nodeVar); 5165 let declarationPrefix = propertyName; 5166 if (shouldTreatAsReadOnly) { 5167 if (isWebGPUBackend) { 5168 declarationPrefix = isDeterministic ? `const ${propertyName}` : `let ${propertyName}`; 5169 } else { 5170 const count = node.getArrayCount(builder); 5171 declarationPrefix = `const ${builder.getVar(nodeVar.type, propertyName, count)}`; 5172 } 5173 } 5174 builder.addLineFlowCode(`${declarationPrefix} = ${snippet}`, this); 5175 return propertyName; 5176 } 5177 _hasStack(builder) { 5178 const nodeData = builder.getDataFromNode(this); 5179 return nodeData.stack !== void 0; 5180 } 5181}; 5182var createVar = /* @__PURE__ */ nodeProxy(VarNode); 5183var Var = (node, name = null) => createVar(node, name).toStack(); 5184var Const = (node, name = null) => createVar(node, name, true).toStack(); 5185var VarIntent = (node) => { 5186 return createVar(node).setIntent(true).toStack(); 5187}; 5188addMethodChaining("toVar", Var); 5189addMethodChaining("toConst", Const); 5190addMethodChaining("toVarIntent", VarIntent); 5191var SubBuildNode = class extends Node2 { 5192 static get type() { 5193 return "SubBuild"; 5194 } 5195 constructor(node, name, nodeType = null) { 5196 super(nodeType); 5197 this.node = node; 5198 this.name = name; 5199 this.isSubBuildNode = true; 5200 } 5201 generateNodeType(builder) { 5202 if (this.nodeType !== null) return this.nodeType; 5203 builder.addSubBuild(this.name); 5204 const nodeType = this.node.getNodeType(builder); 5205 builder.removeSubBuild(); 5206 return nodeType; 5207 } 5208 build(builder, ...params) { 5209 builder.addSubBuild(this.name); 5210 const data = this.node.build(builder, ...params); 5211 builder.removeSubBuild(); 5212 return data; 5213 } 5214}; 5215var subBuild = (node, name, type = null) => new SubBuildNode(nodeObject(node), name, type); 5216var VaryingNode = class extends Node2 { 5217 static get type() { 5218 return "VaryingNode"; 5219 } 5220 /** 5221 * Constructs a new varying node. 5222 * 5223 * @param {Node} node - The node for which a varying should be created. 5224 * @param {?string} name - The name of the varying in the shader. 5225 */ 5226 constructor(node, name = null) { 5227 super(); 5228 this.node = subBuild(node, "VERTEX"); 5229 this.name = name; 5230 this.isVaryingNode = true; 5231 this.interpolationType = null; 5232 this.interpolationSampling = null; 5233 this.global = true; 5234 } 5235 /** 5236 * Defines the interpolation type of the varying. 5237 * 5238 * @param {string} type - The interpolation type. 5239 * @param {?string} sampling - The interpolation sampling type 5240 * @return {VaryingNode} A reference to this node. 5241 */ 5242 setInterpolation(type, sampling = null) { 5243 this.interpolationType = type; 5244 this.interpolationSampling = sampling; 5245 return this; 5246 } 5247 getHash(builder) { 5248 return this.name || super.getHash(builder); 5249 } 5250 generateNodeType(builder) { 5251 return this.node.getNodeType(builder); 5252 } 5253 /** 5254 * This method performs the setup of a varying node with the current node builder. 5255 * 5256 * @param {NodeBuilder} builder - The current node builder. 5257 * @return {NodeVarying} The node varying from the node builder. 5258 */ 5259 setupVarying(builder) { 5260 const properties = builder.getNodeProperties(this); 5261 let varying3 = properties.varying; 5262 if (varying3 === void 0) { 5263 const name = this.name; 5264 const type = this.getNodeType(builder); 5265 const interpolationType = this.interpolationType; 5266 const interpolationSampling = this.interpolationSampling; 5267 properties.varying = varying3 = builder.getVaryingFromNode(this, name, type, interpolationType, interpolationSampling); 5268 properties.node = subBuild(this.node, "VERTEX"); 5269 } 5270 varying3.needsInterpolation || (varying3.needsInterpolation = builder.shaderStage === "fragment"); 5271 return varying3; 5272 } 5273 setup(builder) { 5274 this.setupVarying(builder); 5275 builder.flowNodeFromShaderStage(NodeShaderStage.VERTEX, this.node); 5276 } 5277 analyze(builder) { 5278 this.setupVarying(builder); 5279 builder.flowNodeFromShaderStage(NodeShaderStage.VERTEX, this.node); 5280 } 5281 generate(builder) { 5282 const propertyKey = builder.getSubBuildProperty("property", builder.currentStack); 5283 const properties = builder.getNodeProperties(this); 5284 const varying3 = this.setupVarying(builder); 5285 if (properties[propertyKey] === void 0) { 5286 const type = this.getNodeType(builder); 5287 const propertyName = builder.getPropertyName(varying3, NodeShaderStage.VERTEX); 5288 builder.flowNodeFromShaderStage(NodeShaderStage.VERTEX, properties.node, type, propertyName); 5289 properties[propertyKey] = propertyName; 5290 } 5291 return builder.getPropertyName(varying3); 5292 } 5293}; 5294var varying = /* @__PURE__ */ nodeProxy(VaryingNode).setParameterLength(1, 2); 5295var vertexStage = (node) => varying(node); 5296addMethodChaining("toVarying", varying); 5297addMethodChaining("toVertexStage", vertexStage); 5298var sRGBTransferEOTF = /* @__PURE__ */ Fn(([color3]) => { 5299 const a = color3.mul(0.9478672986).add(0.0521327014).pow(2.4); 5300 const b = color3.mul(0.0773993808); 5301 const factor = color3.lessThanEqual(0.04045); 5302 const rgbResult = mix(a, b, factor); 5303 return rgbResult; 5304}).setLayout({ 5305 name: "sRGBTransferEOTF", 5306 type: "vec3", 5307 inputs: [ 5308 { name: "color", type: "vec3" } 5309 ] 5310}); 5311var sRGBTransferOETF = /* @__PURE__ */ Fn(([color3]) => { 5312 const a = color3.pow(0.41666).mul(1.055).sub(0.055); 5313 const b = color3.mul(12.92); 5314 const factor = color3.lessThanEqual(31308e-7); 5315 const rgbResult = mix(a, b, factor); 5316 return rgbResult; 5317}).setLayout({ 5318 name: "sRGBTransferOETF", 5319 type: "vec3", 5320 inputs: [ 5321 { name: "color", type: "vec3" } 5322 ] 5323}); 5324var WORKING_COLOR_SPACE = "WorkingColorSpace"; 5325var OUTPUT_COLOR_SPACE = "OutputColorSpace"; 5326var ColorSpaceNode = class extends TempNode { 5327 static get type() { 5328 return "ColorSpaceNode"; 5329 } 5330 /** 5331 * Constructs a new color space node. 5332 * 5333 * @param {Node} colorNode - Represents the color to convert. 5334 * @param {string} source - The source color space. 5335 * @param {string} target - The target color space. 5336 */ 5337 constructor(colorNode, source, target) { 5338 super("vec4"); 5339 this.colorNode = colorNode; 5340 this.source = source; 5341 this.target = target; 5342 } 5343 /** 5344 * This method resolves the constants `WORKING_COLOR_SPACE` and 5345 * `OUTPUT_COLOR_SPACE` based on the current configuration of the 5346 * color management and renderer. 5347 * 5348 * @param {NodeBuilder} builder - The current node builder. 5349 * @param {string} colorSpace - The color space to resolve. 5350 * @return {string} The resolved color space. 5351 */ 5352 resolveColorSpace(builder, colorSpace) { 5353 if (colorSpace === WORKING_COLOR_SPACE) { 5354 return ColorManagement.workingColorSpace; 5355 } else if (colorSpace === OUTPUT_COLOR_SPACE) { 5356 return builder.context.outputColorSpace || builder.renderer.outputColorSpace; 5357 } 5358 return colorSpace; 5359 } 5360 setup(builder) { 5361 const { colorNode } = this; 5362 const source = this.resolveColorSpace(builder, this.source); 5363 const target = this.resolveColorSpace(builder, this.target); 5364 let outputNode = colorNode; 5365 if (ColorManagement.enabled === false || source === target || !source || !target) { 5366 return outputNode; 5367 } 5368 if (ColorManagement.getTransfer(source) === SRGBTransfer) { 5369 outputNode = vec4(sRGBTransferEOTF(outputNode.rgb), outputNode.a); 5370 } 5371 if (ColorManagement.getPrimaries(source) !== ColorManagement.getPrimaries(target)) { 5372 outputNode = vec4( 5373 mat3(ColorManagement._getMatrix(new Matrix3(), source, target)).mul(outputNode.rgb), 5374 outputNode.a 5375 ); 5376 } 5377 if (ColorManagement.getTransfer(target) === SRGBTransfer) { 5378 outputNode = vec4(sRGBTransferOETF(outputNode.rgb), outputNode.a); 5379 } 5380 return outputNode; 5381 } 5382}; 5383var workingToColorSpace = (node, targetColorSpace) => new ColorSpaceNode(nodeObject(node), WORKING_COLOR_SPACE, targetColorSpace); 5384var colorSpaceToWorking = (node, sourceColorSpace) => new ColorSpaceNode(nodeObject(node), sourceColorSpace, WORKING_COLOR_SPACE); 5385var convertColorSpace = (node, sourceColorSpace, targetColorSpace) => new ColorSpaceNode(nodeObject(node), sourceColorSpace, targetColorSpace); 5386addMethodChaining("workingToColorSpace", workingToColorSpace); 5387addMethodChaining("colorSpaceToWorking", colorSpaceToWorking); 5388var ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { 5389 static get type() { 5390 return "ReferenceElementNode"; 5391 } 5392 /** 5393 * Constructs a new reference element node. 5394 * 5395 * @param {ReferenceBaseNode} referenceNode - The reference node. 5396 * @param {Node} indexNode - The index node that defines the element access. 5397 */ 5398 constructor(referenceNode, indexNode) { 5399 super(referenceNode, indexNode); 5400 this.referenceNode = referenceNode; 5401 this.isReferenceElementNode = true; 5402 } 5403 /** 5404 * This method is overwritten since the node type is inferred from 5405 * the uniform type of the reference node. 5406 * 5407 * @return {string} The node type. 5408 */ 5409 generateNodeType() { 5410 return this.referenceNode.uniformType; 5411 } 5412 generate(builder) { 5413 const snippet = super.generate(builder); 5414 const arrayType = this.referenceNode.getNodeType(); 5415 const elementType = this.getNodeType(); 5416 return builder.format(snippet, arrayType, elementType); 5417 } 5418}; 5419var ReferenceBaseNode = class extends Node2 { 5420 static get type() { 5421 return "ReferenceBaseNode"; 5422 } 5423 /** 5424 * Constructs a new reference base node. 5425 * 5426 * @param {string} property - The name of the property the node refers to. 5427 * @param {string} uniformType - The uniform type that should be used to represent the property value. 5428 * @param {?Object} [object=null] - The object the property belongs to. 5429 * @param {?number} [count=null] - When the linked property is an array-like, this parameter defines its length. 5430 */ 5431 constructor(property3, uniformType, object = null, count = null) { 5432 super(); 5433 this.property = property3; 5434 this.uniformType = uniformType; 5435 this.object = object; 5436 this.count = count; 5437 this.properties = property3.split("."); 5438 this.reference = object; 5439 this.node = null; 5440 this.group = null; 5441 this.updateType = NodeUpdateType.OBJECT; 5442 } 5443 /** 5444 * Sets the uniform group for this reference node. 5445 * 5446 * @param {UniformGroupNode} group - The uniform group to set. 5447 * @return {ReferenceBaseNode} A reference to this node. 5448 */ 5449 setGroup(group) { 5450 this.group = group; 5451 return this; 5452 } 5453 /** 5454 * When the referred property is array-like, this method can be used 5455 * to access elements via an index node. 5456 * 5457 * @param {IndexNode} indexNode - indexNode. 5458 * @return {ReferenceElementNode} A reference to an element. 5459 */ 5460 element(indexNode) { 5461 return new ReferenceElementNode$1(this, nodeObject(indexNode)); 5462 } 5463 /** 5464 * Sets the node type which automatically defines the internal 5465 * uniform type. 5466 * 5467 * @param {string} uniformType - The type to set. 5468 */ 5469 setNodeType(uniformType) { 5470 const node = uniform(null, uniformType); 5471 if (this.group !== null) { 5472 node.setGroup(this.group); 5473 } 5474 this.node = node; 5475 } 5476 /** 5477 * This method is overwritten since the node type is inferred from 5478 * the type of the reference node. 5479 * 5480 * @param {NodeBuilder} builder - The current node builder. 5481 * @return {string} The node type. 5482 */ 5483 generateNodeType(builder) { 5484 if (this.node === null) { 5485 this.updateReference(builder); 5486 this.updateValue(); 5487 } 5488 return this.node.getNodeType(builder); 5489 } 5490 /** 5491 * Returns the property value from the given referred object. 5492 * 5493 * @param {Object} [object=this.reference] - The object to retrieve the property value from. 5494 * @return {any} The value. 5495 */ 5496 getValueFromReference(object = this.reference) { 5497 const { properties } = this; 5498 let value = object[properties[0]]; 5499 for (let i = 1; i < properties.length; i++) { 5500 value = value[properties[i]]; 5501 } 5502 return value; 5503 } 5504 /** 5505 * Allows to update the reference based on the given state. The state is only 5506 * evaluated {@link ReferenceBaseNode#object} is not set. 5507 * 5508 * @param {(NodeFrame|NodeBuilder)} state - The current state. 5509 * @return {Object} The updated reference. 5510 */ 5511 updateReference(state) { 5512 this.reference = this.object !== null ? this.object : state.object; 5513 return this.reference; 5514 } 5515 /** 5516 * The output of the reference node is the internal uniform node. 5517 * 5518 * @return {UniformNode} The output node. 5519 */ 5520 setup() { 5521 this.updateValue(); 5522 return this.node; 5523 } 5524 /** 5525 * Overwritten to update the internal uniform value. 5526 * 5527 * @param {NodeFrame} frame - A reference to the current node frame. 5528 */ 5529 update() { 5530 this.updateValue(); 5531 } 5532 /** 5533 * Retrieves the value from the referred object property and uses it 5534 * to updated the internal uniform. 5535 */ 5536 updateValue() { 5537 if (this.node === null) this.setNodeType(this.uniformType); 5538 const value = this.getValueFromReference(); 5539 if (Array.isArray(value)) { 5540 this.node.array = value; 5541 } else { 5542 this.node.value = value; 5543 } 5544 } 5545}; 5546var reference$1 = (name, type, object) => new ReferenceBaseNode(name, type, object); 5547var RendererReferenceNode = class extends ReferenceBaseNode { 5548 static get type() { 5549 return "RendererReferenceNode"; 5550 } 5551 /** 5552 * Constructs a new renderer reference node. 5553 * 5554 * @param {string} property - The name of the property the node refers to. 5555 * @param {string} inputType - The uniform type that should be used to represent the property value. 5556 * @param {?Renderer} [renderer=null] - The renderer the property belongs to. When no renderer is set, 5557 * the node refers to the renderer of the current state. 5558 */ 5559 constructor(property3, inputType, renderer = null) { 5560 super(property3, inputType, renderer); 5561 this.renderer = renderer; 5562 this.setGroup(renderGroup); 5563 } 5564 /** 5565 * Updates the reference based on the given state. The state is only evaluated 5566 * {@link RendererReferenceNode#renderer} is not set. 5567 * 5568 * @param {(NodeFrame|NodeBuilder)} state - The current state. 5569 * @return {Object} The updated reference. 5570 */ 5571 updateReference(state) { 5572 this.reference = this.renderer !== null ? this.renderer : state.renderer; 5573 return this.reference; 5574 } 5575}; 5576var rendererReference = (name, type, renderer = null) => new RendererReferenceNode(name, type, renderer); 5577var ToneMappingNode = class extends TempNode { 5578 static get type() { 5579 return "ToneMappingNode"; 5580 } 5581 /** 5582 * Constructs a new tone mapping node. 5583 * 5584 * @param {number} toneMapping - The tone mapping type. 5585 * @param {Node} exposureNode - The tone mapping exposure. 5586 * @param {Node} [colorNode=null] - The color node to process. 5587 */ 5588 constructor(toneMapping3, exposureNode = toneMappingExposure, colorNode = null) { 5589 super("vec3"); 5590 this._toneMapping = toneMapping3; 5591 this.exposureNode = exposureNode; 5592 this.colorNode = colorNode; 5593 } 5594 /** 5595 * Overwrites the default `customCacheKey()` implementation by including the tone 5596 * mapping type into the cache key. 5597 * 5598 * @return {number} The hash. 5599 */ 5600 customCacheKey() { 5601 return hash$1(this._toneMapping); 5602 } 5603 /** 5604 * Sets the tone mapping type. 5605 * 5606 * @param {number} value - The tone mapping type. 5607 * @return {ToneMappingNode} A reference to this node. 5608 */ 5609 setToneMapping(value) { 5610 this._toneMapping = value; 5611 return this; 5612 } 5613 /** 5614 * Gets the tone mapping type. 5615 * 5616 * @returns {number} The tone mapping type. 5617 */ 5618 getToneMapping() { 5619 return this._toneMapping; 5620 } 5621 setup(builder) { 5622 const colorNode = this.colorNode || builder.context.color; 5623 const toneMapping3 = this._toneMapping; 5624 if (toneMapping3 === NoToneMapping) return colorNode; 5625 let outputNode = null; 5626 const toneMappingFn = builder.renderer.library.getToneMappingFunction(toneMapping3); 5627 if (toneMappingFn !== null) { 5628 outputNode = vec4(toneMappingFn(colorNode.rgb, this.exposureNode), colorNode.a); 5629 } else { 5630 error("ToneMappingNode: Unsupported Tone Mapping configuration.", toneMapping3); 5631 outputNode = colorNode; 5632 } 5633 return outputNode; 5634 } 5635}; 5636var toneMapping = (mapping, exposure, color3) => new ToneMappingNode(mapping, nodeObject(exposure), nodeObject(color3)); 5637var toneMappingExposure = /* @__PURE__ */ rendererReference("toneMappingExposure", "float"); 5638addMethodChaining("toneMapping", (color3, mapping, exposure) => toneMapping(mapping, exposure, color3)); 5639var _bufferLib = /* @__PURE__ */ new WeakMap(); 5640function _getBufferAttribute(value, itemSize) { 5641 let buffer3 = _bufferLib.get(value); 5642 if (buffer3 === void 0) { 5643 buffer3 = new InterleavedBuffer(value, itemSize); 5644 _bufferLib.set(value, buffer3); 5645 } 5646 return buffer3; 5647} 5648var BufferAttributeNode = class extends InputNode { 5649 static get type() { 5650 return "BufferAttributeNode"; 5651 } 5652 /** 5653 * Constructs a new buffer attribute node. 5654 * 5655 * @param {BufferAttribute|InterleavedBuffer|TypedArray} value - The attribute data. 5656 * @param {?string} [bufferType=null] - The buffer type (e.g. `'vec3'`). 5657 * @param {number} [bufferStride=0] - The buffer stride. 5658 * @param {number} [bufferOffset=0] - The buffer offset. 5659 */ 5660 constructor(value, bufferType = null, bufferStride = 0, bufferOffset = 0) { 5661 super(value, bufferType); 5662 this.isBufferNode = true; 5663 this.bufferType = bufferType; 5664 this.bufferStride = bufferStride; 5665 this.bufferOffset = bufferOffset; 5666 this.usage = StaticDrawUsage; 5667 this.instanced = false; 5668 this.attribute = null; 5669 this.global = true; 5670 if (value && value.isBufferAttribute === true && value.itemSize <= 4) { 5671 this.attribute = value; 5672 this.usage = value.usage; 5673 this.instanced = value.isInstancedBufferAttribute; 5674 } 5675 } 5676 /** 5677 * This method is overwritten since the attribute data might be shared 5678 * and thus the hash should be shared as well. 5679 * 5680 * @param {NodeBuilder} builder - The current node builder. 5681 * @return {string} The hash. 5682 */ 5683 getHash(builder) { 5684 let id; 5685 if (this.bufferStride === 0 && this.bufferOffset === 0) { 5686 let bufferData = builder.globalCache.getData(this.value); 5687 if (bufferData === void 0) { 5688 bufferData = { 5689 node: this 5690 }; 5691 builder.globalCache.setData(this.value, bufferData); 5692 } 5693 id = bufferData.node.id; 5694 } else { 5695 id = this.id; 5696 } 5697 return String(id); 5698 } 5699 /** 5700 * This method is overwritten since the node type is inferred from 5701 * the buffer attribute. 5702 * 5703 * @param {NodeBuilder} builder - The current node builder. 5704 * @return {string} The node type. 5705 */ 5706 generateNodeType(builder) { 5707 if (this.bufferType === null) { 5708 this.bufferType = builder.getTypeFromAttribute(this.attribute); 5709 } 5710 return this.bufferType; 5711 } 5712 /** 5713 * Depending on which value was passed to the node, `setup()` behaves 5714 * differently. If no instance of `BufferAttribute` was passed, the method 5715 * creates an internal attribute and configures it respectively. 5716 * 5717 * @param {NodeBuilder} builder - The current node builder. 5718 */ 5719 setup(builder) { 5720 if (this.attribute !== null) return; 5721 const type = this.getNodeType(builder); 5722 const itemSize = builder.getTypeLength(type); 5723 const value = this.value; 5724 const stride = this.bufferStride || itemSize; 5725 const offset3 = this.bufferOffset; 5726 let buffer3; 5727 if (value.isInterleavedBuffer === true) { 5728 buffer3 = value; 5729 } else if (value.isBufferAttribute === true) { 5730 buffer3 = _getBufferAttribute(value.array, stride); 5731 } else { 5732 buffer3 = _getBufferAttribute(value, stride); 5733 } 5734 const bufferAttribute3 = new InterleavedBufferAttribute(buffer3, itemSize, offset3); 5735 buffer3.setUsage(this.usage); 5736 this.attribute = bufferAttribute3; 5737 this.attribute.isInstancedBufferAttribute = this.instanced; 5738 } 5739 /** 5740 * Generates the code snippet of the buffer attribute node. 5741 * 5742 * @param {NodeBuilder} builder - The current node builder. 5743 * @return {string} The generated code snippet. 5744 */ 5745 generate(builder) { 5746 const nodeType = this.getNodeType(builder); 5747 const nodeAttribute = builder.getBufferAttributeFromNode(this, nodeType); 5748 const propertyName = builder.getPropertyName(nodeAttribute); 5749 let output3 = null; 5750 if (builder.shaderStage === "vertex" || builder.shaderStage === "compute") { 5751 this.name = propertyName; 5752 output3 = propertyName; 5753 } else { 5754 const nodeVarying = varying(this); 5755 output3 = nodeVarying.build(builder, nodeType); 5756 } 5757 return output3; 5758 } 5759 /** 5760 * Overwrites the default implementation to return a fixed value `'bufferAttribute'`. 5761 * 5762 * @param {NodeBuilder} builder - The current node builder. 5763 * @return {string} The input type. 5764 */ 5765 getInputType() { 5766 return "bufferAttribute"; 5767 } 5768 /** 5769 * Sets the `usage` property to the given value. 5770 * 5771 * @param {number} value - The usage to set. 5772 * @return {BufferAttributeNode} A reference to this node. 5773 */ 5774 setUsage(value) { 5775 this.usage = value; 5776 if (this.attribute && this.attribute.isBufferAttribute === true) { 5777 this.attribute.usage = value; 5778 } 5779 return this; 5780 } 5781 /** 5782 * Sets the `instanced` property to the given value. 5783 * 5784 * @param {boolean} value - The value to set. 5785 * @return {BufferAttributeNode} A reference to this node. 5786 */ 5787 setInstanced(value) { 5788 this.instanced = value; 5789 return this; 5790 } 5791}; 5792function createBufferAttribute(array3, type = null, stride = 0, offset3 = 0, usage = StaticDrawUsage, instanced = false) { 5793 if (type === "mat3" || type === null && array3.itemSize === 9) { 5794 return mat3( 5795 new BufferAttributeNode(array3, "vec3", 9, 0).setUsage(usage).setInstanced(instanced), 5796 new BufferAttributeNode(array3, "vec3", 9, 3).setUsage(usage).setInstanced(instanced), 5797 new BufferAttributeNode(array3, "vec3", 9, 6).setUsage(usage).setInstanced(instanced) 5798 ); 5799 } else if (type === "mat4" || type === null && array3.itemSize === 16) { 5800 return mat4( 5801 new BufferAttributeNode(array3, "vec4", 16, 0).setUsage(usage).setInstanced(instanced), 5802 new BufferAttributeNode(array3, "vec4", 16, 4).setUsage(usage).setInstanced(instanced), 5803 new BufferAttributeNode(array3, "vec4", 16, 8).setUsage(usage).setInstanced(instanced), 5804 new BufferAttributeNode(array3, "vec4", 16, 12).setUsage(usage).setInstanced(instanced) 5805 ); 5806 } 5807 return new BufferAttributeNode(array3, type, stride, offset3).setUsage(usage); 5808} 5809var bufferAttribute = (array3, type = null, stride = 0, offset3 = 0) => createBufferAttribute(array3, type, stride, offset3); 5810var dynamicBufferAttribute = (array3, type = null, stride = 0, offset3 = 0) => createBufferAttribute(array3, type, stride, offset3, DynamicDrawUsage); 5811var instancedBufferAttribute = (array3, type = null, stride = 0, offset3 = 0) => createBufferAttribute(array3, type, stride, offset3, StaticDrawUsage, true); 5812var instancedDynamicBufferAttribute = (array3, type = null, stride = 0, offset3 = 0) => createBufferAttribute(array3, type, stride, offset3, DynamicDrawUsage, true); 5813addMethodChaining("toAttribute", (bufferNode) => bufferAttribute(bufferNode.value)); 5814var IndexNode = class _IndexNode extends Node2 { 5815 static get type() { 5816 return "IndexNode"; 5817 } 5818 /** 5819 * Constructs a new index node. 5820 * 5821 * @param {('vertex'|'instance'|'subgroup'|'invocationLocal'|'invocationGlobal'|'invocationSubgroup'|'draw')} scope - The scope of the index node. 5822 */ 5823 constructor(scope) { 5824 super("uint"); 5825 this.scope = scope; 5826 this.isIndexNode = true; 5827 } 5828 generate(builder) { 5829 const nodeType = this.getNodeType(builder); 5830 const scope = this.scope; 5831 let propertyName; 5832 if (scope === _IndexNode.VERTEX) { 5833 propertyName = builder.getVertexIndex(); 5834 } else if (scope === _IndexNode.INSTANCE) { 5835 propertyName = builder.getInstanceIndex(); 5836 } else if (scope === _IndexNode.DRAW) { 5837 propertyName = builder.getDrawIndex(); 5838 } else if (scope === _IndexNode.INVOCATION_LOCAL) { 5839 propertyName = builder.getInvocationLocalIndex(); 5840 } else if (scope === _IndexNode.INVOCATION_SUBGROUP) { 5841 propertyName = builder.getInvocationSubgroupIndex(); 5842 } else if (scope === _IndexNode.SUBGROUP) { 5843 propertyName = builder.getSubgroupIndex(); 5844 } else { 5845 throw new Error("THREE.IndexNode: Unknown scope: " + scope); 5846 } 5847 let output3; 5848 if (builder.shaderStage === "vertex" || builder.shaderStage === "compute") { 5849 output3 = propertyName; 5850 } else { 5851 const nodeVarying = varying(this); 5852 output3 = nodeVarying.build(builder, nodeType); 5853 } 5854 return output3; 5855 } 5856}; 5857IndexNode.VERTEX = "vertex"; 5858IndexNode.INSTANCE = "instance"; 5859IndexNode.SUBGROUP = "subgroup"; 5860IndexNode.INVOCATION_LOCAL = "invocationLocal"; 5861IndexNode.INVOCATION_SUBGROUP = "invocationSubgroup"; 5862IndexNode.DRAW = "draw"; 5863var vertexIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.VERTEX); 5864var instanceIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.INSTANCE); 5865var subgroupIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.SUBGROUP); 5866var invocationSubgroupIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.INVOCATION_SUBGROUP); 5867var invocationLocalIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.INVOCATION_LOCAL); 5868var drawIndex = /* @__PURE__ */ nodeImmutable(IndexNode, IndexNode.DRAW); 5869var ComputeNode = class extends Node2 { 5870 static get type() { 5871 return "ComputeNode"; 5872 } 5873 /** 5874 * Constructs a new compute node. 5875 * 5876 * @param {Node} computeNode - The node that defines the compute shader logic. 5877 * @param {Array<number>} workgroupSize - An array defining the X, Y, and Z dimensions of the workgroup for compute shader execution. 5878 */ 5879 constructor(computeNode, workgroupSize) { 5880 super("void"); 5881 this.isComputeNode = true; 5882 this.computeNode = computeNode; 5883 this.workgroupSize = workgroupSize; 5884 this.count = null; 5885 this.dispatchSize = null; 5886 this.version = 1; 5887 this.name = ""; 5888 this.updateBeforeType = NodeUpdateType.OBJECT; 5889 this.onInitFunction = null; 5890 this.countNode = null; 5891 } 5892 /** 5893 * Executes the `dispose` event for this node. 5894 */ 5895 dispose() { 5896 this.dispatchEvent({ type: "dispose" }); 5897 } 5898 /** 5899 * Sets the {@link ComputeNode#name} property. 5900 * 5901 * @param {string} name - The name of the uniform. 5902 * @return {ComputeNode} A reference to this node. 5903 */ 5904 setName(name) { 5905 this.name = name; 5906 return this; 5907 } 5908 /** 5909 * Sets the {@link ComputeNode#name} property. 5910 * 5911 * @deprecated 5912 * @param {string} name - The name of the uniform. 5913 * @return {ComputeNode} A reference to this node. 5914 */ 5915 label(name) { 5916 warn('TSL: "label()" has been deprecated. Use "setName()" instead.', new StackTrace()); 5917 return this.setName(name); 5918 } 5919 /** 5920 * Sets the callback to run during initialization. 5921 * 5922 * @param {Function} callback - The callback function. 5923 * @return {ComputeNode} A reference to this node. 5924 */ 5925 onInit(callback) { 5926 this.onInitFunction = callback; 5927 return this; 5928 } 5929 /** 5930 * The method execute the compute for this node. 5931 * 5932 * @param {NodeFrame} frame - A reference to the current node frame. 5933 */ 5934 updateBefore({ renderer }) { 5935 renderer.compute(this); 5936 } 5937 setup(builder) { 5938 if (this.count !== null && this.countNode === null) { 5939 this.countNode = uniform(this.count, "uint").onObjectUpdate(() => this.count); 5940 } 5941 const result = this.computeNode.build(builder); 5942 if (result) { 5943 const properties = builder.getNodeProperties(this); 5944 properties.outputComputeNode = result.outputNode; 5945 result.outputNode = null; 5946 } 5947 return result; 5948 } 5949 generate(builder, output3) { 5950 const { shaderStage } = builder; 5951 if (shaderStage === "compute") { 5952 const snippet = this.computeNode.build(builder, "void"); 5953 if (snippet !== "") { 5954 builder.addLineFlowCode(snippet, this); 5955 } 5956 if (this.count !== null && builder.allowEarlyReturns === true) { 5957 const countSnippet = this.countNode.build(builder, "uint"); 5958 const indexSnippet = instanceIndex.build(builder, "uint"); 5959 builder.flow.code = `${builder.tab}if ( ${indexSnippet} >= ${countSnippet} ) { return; } 5960 5961${builder.flow.code}`; 5962 } 5963 } else { 5964 const properties = builder.getNodeProperties(this); 5965 const outputComputeNode = properties.outputComputeNode; 5966 if (outputComputeNode) { 5967 return outputComputeNode.build(builder, output3); 5968 } 5969 } 5970 } 5971}; 5972var computeKernel = (node, workgroupSize = [64]) => { 5973 if (workgroupSize.length === 0 || workgroupSize.length > 3) { 5974 error("TSL: compute() workgroupSize must have 1, 2, or 3 elements", new StackTrace()); 5975 } 5976 for (let i = 0; i < workgroupSize.length; i++) { 5977 const val = workgroupSize[i]; 5978 if (typeof val !== "number" || val <= 0 || !Number.isInteger(val)) { 5979 error(`TSL: compute() workgroupSize element at index [ ${i} ] must be a positive integer`, new StackTrace()); 5980 } 5981 } 5982 while (workgroupSize.length < 3) workgroupSize.push(1); 5983 return new ComputeNode(nodeObject(node), workgroupSize); 5984}; 5985var compute = (node, count, workgroupSize) => { 5986 const computeNode = computeKernel(node, workgroupSize); 5987 if (typeof count === "number") { 5988 computeNode.count = count; 5989 } else { 5990 computeNode.dispatchSize = count; 5991 } 5992 return computeNode; 5993}; 5994addMethodChaining("compute", compute); 5995addMethodChaining("computeKernel", computeKernel); 5996var IsolateNode = class extends Node2 { 5997 static get type() { 5998 return "IsolateNode"; 5999 } 6000 /** 6001 * Constructs a new cache node. 6002 * 6003 * @param {Node} node - The node that should be cached. 6004 * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not. 6005 */ 6006 constructor(node, parent = true) { 6007 super(); 6008 this.node = node; 6009 this.parent = parent; 6010 this.isIsolateNode = true; 6011 } 6012 generateNodeType(builder) { 6013 const previousCache = builder.getCache(); 6014 const cache4 = builder.getCacheFromNode(this, this.parent); 6015 builder.setCache(cache4); 6016 const nodeType = this.node.getNodeType(builder); 6017 builder.setCache(previousCache); 6018 return nodeType; 6019 } 6020 build(builder, ...params) { 6021 const previousCache = builder.getCache(); 6022 const cache4 = builder.getCacheFromNode(this, this.parent); 6023 builder.setCache(cache4); 6024 const data = this.node.build(builder, ...params); 6025 builder.setCache(previousCache); 6026 return data; 6027 } 6028 setParent(parent) { 6029 this.parent = parent; 6030 return this; 6031 } 6032 getParent() { 6033 return this.parent; 6034 } 6035}; 6036var isolate = (node) => new IsolateNode(nodeObject(node)); 6037function cache(node, parent = true) { 6038 warn('TSL: "cache()" has been deprecated. Use "isolate()" instead.'); 6039 return isolate(node).setParent(parent); 6040} 6041addMethodChaining("cache", cache); 6042addMethodChaining("isolate", isolate); 6043var BypassNode = class extends Node2 { 6044 static get type() { 6045 return "BypassNode"; 6046 } 6047 /** 6048 * Constructs a new bypass node. 6049 * 6050 * @param {Node} outputNode - The output node. 6051 * @param {Node} callNode - The call node. 6052 */ 6053 constructor(outputNode, callNode) { 6054 super(); 6055 this.isBypassNode = true; 6056 this.outputNode = outputNode; 6057 this.callNode = callNode; 6058 } 6059 generateNodeType(builder) { 6060 return this.outputNode.getNodeType(builder); 6061 } 6062 generate(builder) { 6063 const snippet = this.callNode.build(builder, "void"); 6064 if (snippet !== "") { 6065 builder.addLineFlowCode(snippet, this); 6066 } 6067 return this.outputNode.build(builder); 6068 } 6069}; 6070var bypass = /* @__PURE__ */ nodeProxy(BypassNode).setParameterLength(2); 6071addMethodChaining("bypass", bypass); 6072var remap = /* @__PURE__ */ Fn(([node, inLowNode, inHighNode, outLowNode = float(0), outHighNode = float(1), doClamp = bool(false)]) => { 6073 let t = node.sub(inLowNode).div(inHighNode.sub(inLowNode)); 6074 if (defined(doClamp)) t = t.clamp(); 6075 return t.mul(outHighNode.sub(outLowNode)).add(outLowNode); 6076}); 6077function remapClamp(node, inLowNode, inHighNode, outLowNode = float(0), outHighNode = float(1)) { 6078 return remap(node, inLowNode, inHighNode, outLowNode, outHighNode, true); 6079} 6080addMethodChaining("remap", remap); 6081addMethodChaining("remapClamp", remapClamp); 6082var ExpressionNode = class extends Node2 { 6083 static get type() { 6084 return "ExpressionNode"; 6085 } 6086 /** 6087 * Constructs a new expression node. 6088 * 6089 * @param {string} [snippet=''] - The native code snippet. 6090 * @param {string} [nodeType='void'] - The node type. 6091 */ 6092 constructor(snippet = "", nodeType = "void") { 6093 super(nodeType); 6094 this.snippet = snippet; 6095 } 6096 generate(builder, output3) { 6097 const type = this.getNodeType(builder); 6098 const snippet = this.snippet; 6099 if (type === "void") { 6100 builder.addLineFlowCode(snippet, this); 6101 } else { 6102 return builder.format(snippet, type, output3); 6103 } 6104 } 6105}; 6106var expression = /* @__PURE__ */ nodeProxy(ExpressionNode).setParameterLength(1, 2); 6107var Discard = (conditional) => (conditional ? select(conditional, expression("discard")) : expression("discard")).toStack(); 6108var Return = () => expression("return").toStack(); 6109addMethodChaining("discard", Discard); 6110var RenderOutputNode = class extends TempNode { 6111 static get type() { 6112 return "RenderOutputNode"; 6113 } 6114 /** 6115 * Constructs a new render output node. 6116 * 6117 * @param {Node} colorNode - The color node to process. 6118 * @param {?number} toneMapping - The tone mapping type. 6119 * @param {?string} outputColorSpace - The output color space. 6120 */ 6121 constructor(colorNode, toneMapping3, outputColorSpace) { 6122 super("vec4"); 6123 this.colorNode = colorNode; 6124 this._toneMapping = toneMapping3; 6125 this.outputColorSpace = outputColorSpace; 6126 this.isRenderOutputNode = true; 6127 } 6128 /** 6129 * Sets the tone mapping type. 6130 * 6131 * @param {number} value - The tone mapping type. 6132 * @return {ToneMappingNode} A reference to this node. 6133 */ 6134 setToneMapping(value) { 6135 this._toneMapping = value; 6136 return this; 6137 } 6138 /** 6139 * Gets the tone mapping type. 6140 * 6141 * @returns {number} The tone mapping type. 6142 */ 6143 getToneMapping() { 6144 return this._toneMapping; 6145 } 6146 setup({ context: context3 }) { 6147 let outputNode = this.colorNode || context3.color; 6148 const toneMapping3 = (this._toneMapping !== null ? this._toneMapping : context3.toneMapping) || NoToneMapping; 6149 const outputColorSpace = (this.outputColorSpace !== null ? this.outputColorSpace : context3.outputColorSpace) || NoColorSpace; 6150 if (toneMapping3 !== NoToneMapping) { 6151 outputNode = outputNode.toneMapping(toneMapping3); 6152 } 6153 if (outputColorSpace !== NoColorSpace && outputColorSpace !== ColorManagement.workingColorSpace) { 6154 outputNode = outputNode.workingToColorSpace(outputColorSpace); 6155 } 6156 return outputNode; 6157 } 6158}; 6159var renderOutput = (color3, toneMapping3 = null, outputColorSpace = null) => new RenderOutputNode(nodeObject(color3), toneMapping3, outputColorSpace); 6160addMethodChaining("renderOutput", renderOutput); 6161var DebugNode = class extends TempNode { 6162 static get type() { 6163 return "DebugNode"; 6164 } 6165 constructor(node, callback = null) { 6166 super(); 6167 this.node = node; 6168 this.callback = callback; 6169 } 6170 generateNodeType(builder) { 6171 return this.node.getNodeType(builder); 6172 } 6173 setup(builder) { 6174 return this.node.build(builder); 6175 } 6176 analyze(builder) { 6177 return this.node.build(builder); 6178 } 6179 generate(builder) { 6180 const callback = this.callback; 6181 const snippet = this.node.build(builder); 6182 if (callback !== null) { 6183 callback(builder, snippet); 6184 } else { 6185 const title = "--- TSL debug - " + builder.shaderStage + " shader ---"; 6186 const border = "-".repeat(title.length); 6187 let code3 = ""; 6188 code3 += "// #" + title + "#\n"; 6189 code3 += builder.flow.code.replace(/^\t/mg, "") + "\n"; 6190 code3 += "/* ... */ " + snippet + " /* ... */\n"; 6191 code3 += "// #" + border + "#\n"; 6192 log(code3); 6193 } 6194 return snippet; 6195 } 6196}; 6197var debug = (node, callback = null) => new DebugNode(nodeObject(node), callback).toStack(); 6198addMethodChaining("debug", debug); 6199var InspectorBase = class extends EventDispatcher { 6200 /** 6201 * Creates a new InspectorBase. 6202 */ 6203 constructor() { 6204 super(); 6205 this._renderer = null; 6206 this.currentFrame = null; 6207 } 6208 /** 6209 * Returns the node frame for the current renderer. 6210 * 6211 * @return {Object} The node frame. 6212 */ 6213 get nodeFrame() { 6214 return this._renderer._nodes.nodeFrame; 6215 } 6216 /** 6217 * Sets the renderer for this inspector. 6218 * 6219 * @param {WebGLRenderer} renderer - The renderer to associate with this inspector. 6220 * @return {InspectorBase} This inspector instance. 6221 */ 6222 setRenderer(renderer) { 6223 this._renderer = renderer; 6224 return this; 6225 } 6226 /** 6227 * Returns the renderer associated with this inspector. 6228 * 6229 * @return {WebGLRenderer} The associated renderer. 6230 */ 6231 getRenderer() { 6232 return this._renderer; 6233 } 6234 /** 6235 * Initializes the inspector. 6236 */ 6237 init() { 6238 } 6239 /** 6240 * Called when a frame begins. 6241 */ 6242 begin() { 6243 } 6244 /** 6245 * Called when a frame ends. 6246 */ 6247 finish() { 6248 } 6249 /** 6250 * Inspects a node. 6251 * 6252 * @param {Node} node - The node to inspect. 6253 */ 6254 inspect() { 6255 } 6256 /** 6257 * When a compute operation is performed. 6258 * 6259 * @param {ComputeNode} computeNode - The compute node being executed. 6260 * @param {number|Array<number>} dispatchSizeOrCount - The dispatch size or count. 6261 */ 6262 computeAsync() { 6263 } 6264 /** 6265 * Called when a compute operation begins. 6266 * 6267 * @param {string} uid - A unique identifier for the render context. 6268 * @param {ComputeNode} computeNode - The compute node being executed. 6269 */ 6270 beginCompute() { 6271 } 6272 /** 6273 * Called when a compute operation ends. 6274 * 6275 * @param {string} uid - A unique identifier for the render context. 6276 * @param {ComputeNode} computeNode - The compute node being executed. 6277 */ 6278 finishCompute() { 6279 } 6280 /** 6281 * Called when a render operation begins. 6282 * 6283 * @param {string} uid - A unique identifier for the render context. 6284 * @param {Scene} scene - The scene being rendered. 6285 * @param {Camera} camera - The camera being used for rendering. 6286 * @param {?WebGLRenderTarget} renderTarget - The render target, if any. 6287 */ 6288 beginRender() { 6289 } 6290 /** 6291 * Called when an animation loop ends. 6292 * 6293 * @param {string} uid - A unique identifier for the render context. 6294 */ 6295 finishRender() { 6296 } 6297 /** 6298 * Called when a texture copy operation is performed. 6299 * 6300 * @param {Texture} srcTexture - The source texture. 6301 * @param {Texture} dstTexture - The destination texture. 6302 */ 6303 copyTextureToTexture() { 6304 } 6305 /** 6306 * Called when a framebuffer copy operation is performed. 6307 * 6308 * @param {Texture} framebufferTexture - The texture associated with the framebuffer. 6309 */ 6310 copyFramebufferToTexture() { 6311 } 6312}; 6313var InspectorNode = class extends Node2 { 6314 /** 6315 * Returns the type of the node. 6316 * 6317 * @returns {string} 6318 */ 6319 static get type() { 6320 return "InspectorNode"; 6321 } 6322 /** 6323 * Creates an InspectorNode. 6324 * 6325 * @param {Node} node - The node to inspect. 6326 * @param {string} [name=''] - Optional name for the inspector node. 6327 * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. 6328 */ 6329 constructor(node, name = "", callback = null) { 6330 super(); 6331 this.node = node; 6332 this.name = name; 6333 this.callback = callback; 6334 this.updateType = NodeUpdateType.FRAME; 6335 this.isInspectorNode = true; 6336 } 6337 /** 6338 * Returns the name of the inspector node. 6339 * 6340 * @returns {string} 6341 */ 6342 getName() { 6343 return this.name || this.node.name; 6344 } 6345 /** 6346 * Updates the inspector node, allowing inspection of the wrapped node. 6347 * 6348 * @param {NodeFrame} frame - A reference to the current node frame. 6349 */ 6350 update(frame) { 6351 frame.renderer.inspector.inspect(this); 6352 } 6353 /** 6354 * Returns the type of the wrapped node. 6355 * 6356 * @param {NodeBuilder} builder - The node builder. 6357 * @returns {string} 6358 */ 6359 generateNodeType(builder) { 6360 return this.node.getNodeType(builder); 6361 } 6362 /** 6363 * Sets up the inspector node. 6364 * 6365 * @param {NodeBuilder} builder - The node builder. 6366 * @returns {Node} The setup node. 6367 */ 6368 setup(builder) { 6369 let node = this.node; 6370 if (builder.context.inspector === true && this.callback !== null) { 6371 node = this.callback(node); 6372 } 6373 if (builder.renderer.backend.isWebGPUBackend !== true && builder.renderer.inspector.constructor !== InspectorBase) { 6374 warnOnce('TSL: ".toInspector()" is only available with WebGPU.'); 6375 } 6376 return node; 6377 } 6378}; 6379function inspector(node, name = "", callback = null) { 6380 node = nodeObject(node); 6381 return node.before(new InspectorNode(node, name, callback)); 6382} 6383addMethodChaining("toInspector", inspector); 6384function addNodeElement(name) { 6385 warn("TSL: AddNodeElement has been removed in favor of tree-shaking. Trying add", name); 6386} 6387var AttributeNode = class extends Node2 { 6388 static get type() { 6389 return "AttributeNode"; 6390 } 6391 /** 6392 * Constructs a new attribute node. 6393 * 6394 * @param {string} attributeName - The name of the attribute. 6395 * @param {?string} nodeType - The node type. 6396 */ 6397 constructor(attributeName, nodeType = null) { 6398 super(nodeType); 6399 this.global = true; 6400 this._attributeName = attributeName; 6401 } 6402 getHash(builder) { 6403 return this.getAttributeName(builder); 6404 } 6405 generateNodeType(builder) { 6406 let nodeType = this.nodeType; 6407 if (nodeType === null) { 6408 const attributeName = this.getAttributeName(builder); 6409 if (builder.hasGeometryAttribute(attributeName)) { 6410 const attribute3 = builder.geometry.getAttribute(attributeName); 6411 nodeType = builder.getTypeFromAttribute(attribute3); 6412 } else { 6413 nodeType = "float"; 6414 } 6415 } 6416 return nodeType; 6417 } 6418 /** 6419 * Sets the attribute name to the given value. The method can be 6420 * overwritten in derived classes if the final name must be computed 6421 * analytically. 6422 * 6423 * @param {string} attributeName - The name of the attribute. 6424 * @return {AttributeNode} A reference to this node. 6425 */ 6426 setAttributeName(attributeName) { 6427 this._attributeName = attributeName; 6428 return this; 6429 } 6430 /** 6431 * Returns the attribute name of this node. The method can be 6432 * overwritten in derived classes if the final name must be computed 6433 * analytically. 6434 * 6435 * @param {NodeBuilder} builder - The current node builder. 6436 * @return {string} The attribute name. 6437 */ 6438 getAttributeName() { 6439 return this._attributeName; 6440 } 6441 generate(builder) { 6442 const attributeName = this.getAttributeName(builder); 6443 const nodeType = this.getNodeType(builder); 6444 const geometryAttribute = builder.hasGeometryAttribute(attributeName); 6445 if (geometryAttribute === true) { 6446 const attribute3 = builder.geometry.getAttribute(attributeName); 6447 const attributeType = builder.getTypeFromAttribute(attribute3); 6448 const nodeAttribute = builder.getAttribute(attributeName, attributeType); 6449 if (builder.shaderStage === "vertex") { 6450 return builder.format(nodeAttribute.name, attributeType, nodeType); 6451 } else { 6452 const nodeVarying = varying(this); 6453 return nodeVarying.build(builder, nodeType); 6454 } 6455 } else { 6456 warn(`AttributeNode: Vertex attribute "${attributeName}" not found on geometry.`); 6457 return builder.generateConst(nodeType); 6458 } 6459 } 6460 serialize(data) { 6461 super.serialize(data); 6462 data.global = this.global; 6463 data._attributeName = this._attributeName; 6464 } 6465 deserialize(data) { 6466 super.deserialize(data); 6467 this.global = data.global; 6468 this._attributeName = data._attributeName; 6469 } 6470}; 6471var attribute = (name, nodeType = null) => new AttributeNode(name, nodeType); 6472var uv$1 = (index = 0) => attribute("uv" + (index > 0 ? index : ""), "vec2"); 6473var TextureSizeNode = class extends Node2 { 6474 static get type() { 6475 return "TextureSizeNode"; 6476 } 6477 /** 6478 * Constructs a new texture size node. 6479 * 6480 * @param {TextureNode} textureNode - A texture node which size should be retrieved. 6481 * @param {?Node<int>} [levelNode=null] - A level node which defines the requested mip. 6482 */ 6483 constructor(textureNode, levelNode = null) { 6484 super("uvec2"); 6485 this.isTextureSizeNode = true; 6486 this.textureNode = textureNode; 6487 this.levelNode = levelNode; 6488 } 6489 generate(builder, output3) { 6490 const textureProperty = this.textureNode.build(builder, "property"); 6491 const level = this.levelNode === null ? "0" : this.levelNode.build(builder, "int"); 6492 return builder.format(`${builder.getMethod("textureDimensions")}( ${textureProperty}, ${level} )`, this.getNodeType(builder), output3); 6493 } 6494}; 6495var textureSize = /* @__PURE__ */ nodeProxy(TextureSizeNode).setParameterLength(1, 2); 6496var MaxMipLevelNode = class extends UniformNode { 6497 static get type() { 6498 return "MaxMipLevelNode"; 6499 } 6500 /** 6501 * Constructs a new max mip level node. 6502 * 6503 * @param {TextureNode} textureNode - The texture node to compute the max mip level for. 6504 */ 6505 constructor(textureNode) { 6506 super(0); 6507 this._textureNode = textureNode; 6508 this.updateType = NodeUpdateType.FRAME; 6509 } 6510 /** 6511 * The texture node to compute the max mip level for. 6512 * 6513 * @readonly 6514 * @type {TextureNode} 6515 */ 6516 get textureNode() { 6517 return this._textureNode; 6518 } 6519 /** 6520 * The texture. 6521 * 6522 * @readonly 6523 * @type {Texture} 6524 */ 6525 get texture() { 6526 return this._textureNode.value; 6527 } 6528 update() { 6529 const texture3 = this.texture; 6530 const images = texture3.images; 6531 const image = images && images.length > 0 ? images[0] && images[0].image || images[0] : texture3.image; 6532 if (image && image.width !== void 0) { 6533 const { width, height } = image; 6534 this.value = Math.log2(Math.max(width, height)); 6535 } 6536 } 6537}; 6538var maxMipLevel = /* @__PURE__ */ nodeProxy(MaxMipLevelNode).setParameterLength(1); 6539var NodeError = class extends Error { 6540 constructor(message, stackTrace = null) { 6541 super(message); 6542 this.name = "NodeError"; 6543 this.stackTrace = stackTrace; 6544 } 6545}; 6546var EmptyTexture$1 = /* @__PURE__ */ new Texture(); 6547var TextureNode = class extends UniformNode { 6548 static get type() { 6549 return "TextureNode"; 6550 } 6551 /** 6552 * Constructs a new texture node. 6553 * 6554 * @param {Texture} [value=EmptyTexture] - The texture. 6555 * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node. 6556 * @param {?Node<int>} [levelNode=null] - The level node. 6557 * @param {?Node<float>} [biasNode=null] - The bias node. 6558 */ 6559 constructor(value = EmptyTexture$1, uvNode = null, levelNode = null, biasNode = null) { 6560 super(value); 6561 this.isTextureNode = true; 6562 this.uvNode = uvNode; 6563 this.levelNode = levelNode; 6564 this.biasNode = biasNode; 6565 this.compareNode = null; 6566 this.depthNode = null; 6567 this.gradNode = null; 6568 this.offsetNode = null; 6569 this.sampler = true; 6570 this.updateMatrix = false; 6571 this.updateType = NodeUpdateType.NONE; 6572 this.referenceNode = null; 6573 this._value = value; 6574 this._matrixUniform = null; 6575 this._flipYUniform = null; 6576 this.setUpdateMatrix(uvNode === null); 6577 } 6578 set value(value) { 6579 if (this.referenceNode) { 6580 this.referenceNode.value = value; 6581 } else { 6582 this._value = value; 6583 } 6584 } 6585 /** 6586 * The texture value. 6587 * 6588 * @type {Texture} 6589 */ 6590 get value() { 6591 return this.referenceNode ? this.referenceNode.value : this._value; 6592 } 6593 /** 6594 * Overwritten since the uniform hash is defined by the texture's UUID. 6595 * 6596 * @param {NodeBuilder} builder - The current node builder. 6597 * @return {string} The uniform hash. 6598 */ 6599 getUniformHash() { 6600 return this.value.uuid; 6601 } 6602 /** 6603 * Overwritten since the node type is inferred from the texture type. 6604 * 6605 * @param {NodeBuilder} builder - The current node builder. 6606 * @return {string} The node type. 6607 */ 6608 generateNodeType() { 6609 if (this.value.isDepthTexture === true) return "float"; 6610 if (this.value.type === UnsignedIntType) { 6611 return "uvec4"; 6612 } else if (this.value.type === IntType) { 6613 return "ivec4"; 6614 } 6615 return "vec4"; 6616 } 6617 /** 6618 * Overwrites the default implementation to return a fixed value `'texture'`. 6619 * 6620 * @param {NodeBuilder} builder - The current node builder. 6621 * @return {string} The input type. 6622 */ 6623 getInputType() { 6624 return "texture"; 6625 } 6626 /** 6627 * Returns a default uvs based on the current texture's channel. 6628 * 6629 * @return {AttributeNode<vec2>} The default uvs. 6630 */ 6631 getDefaultUV() { 6632 return uv$1(this.value.channel); 6633 } 6634 /** 6635 * Overwritten to always return the texture reference of the node. 6636 * 6637 * @param {any} state - This method can be invocated in different contexts so `state` can refer to any object type. 6638 * @return {Texture} The texture reference. 6639 */ 6640 updateReference() { 6641 return this.value; 6642 } 6643 /** 6644 * Transforms the given uv node with the texture transformation matrix. 6645 * 6646 * @param {Node} uvNode - The uv node to transform. 6647 * @return {Node} The transformed uv node. 6648 */ 6649 getTransformedUV(uvNode) { 6650 if (this._matrixUniform === null) this._matrixUniform = uniform(this.value.matrix); 6651 return this._matrixUniform.mul(vec3(uvNode, 1)).xy; 6652 } 6653 /** 6654 * Defines whether the uv transformation matrix should automatically be updated or not. 6655 * 6656 * @param {boolean} value - The update toggle. 6657 * @return {TextureNode} A reference to this node. 6658 */ 6659 setUpdateMatrix(value) { 6660 this.updateMatrix = value; 6661 return this; 6662 } 6663 /** 6664 * Setups the uv node. Depending on the backend as well as texture's image and type, it might be necessary 6665 * to modify the uv node for correct sampling. 6666 * 6667 * @param {NodeBuilder} builder - The current node builder. 6668 * @param {Node} uvNode - The uv node to setup. 6669 * @return {Node} The updated uv node. 6670 */ 6671 setupUV(builder, uvNode) { 6672 if (builder.isFlipY()) { 6673 if (this._flipYUniform === null) this._flipYUniform = uniform(false); 6674 uvNode = uvNode.toVar(); 6675 if (this.sampler) { 6676 uvNode = this._flipYUniform.select(uvNode.flipY(), uvNode); 6677 } else { 6678 uvNode = this._flipYUniform.select(uvNode.setY(int(textureSize(this, this.levelNode).y).sub(uvNode.y).sub(1)), uvNode); 6679 } 6680 } 6681 return uvNode; 6682 } 6683 /** 6684 * Setups texture node by preparing the internal nodes for code generation. 6685 * 6686 * @param {NodeBuilder} builder - The current node builder. 6687 */ 6688 setup(builder) { 6689 const properties = builder.getNodeProperties(this); 6690 properties.referenceNode = this.referenceNode; 6691 const texture3 = this.value; 6692 if (!texture3 || texture3.isTexture !== true) { 6693 throw new NodeError("THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().", this.stackTrace); 6694 } 6695 const uvNode = Fn(() => { 6696 let uvNode2 = this.uvNode; 6697 if ((uvNode2 === null || builder.context.forceUVContext === true) && builder.context.getUV) { 6698 uvNode2 = builder.context.getUV(this, builder); 6699 } 6700 if (!uvNode2) uvNode2 = this.getDefaultUV(); 6701 if (this.updateMatrix === true) { 6702 uvNode2 = this.getTransformedUV(uvNode2); 6703 } 6704 uvNode2 = this.setupUV(builder, uvNode2); 6705 this.updateType = this._matrixUniform !== null || this._flipYUniform !== null ? NodeUpdateType.OBJECT : NodeUpdateType.NONE; 6706 return uvNode2; 6707 })(); 6708 let levelNode = this.levelNode; 6709 if (levelNode === null && builder.context.getTextureLevel) { 6710 levelNode = builder.context.getTextureLevel(this); 6711 } 6712 let compareNode = null; 6713 let compareStepNode = null; 6714 if (this.compareNode !== null) { 6715 if (builder.renderer.hasCompatibility(Compatibility.TEXTURE_COMPARE)) { 6716 compareNode = this.compareNode; 6717 } else { 6718 const compareFunction = texture3.compareFunction; 6719 if (compareFunction === null || compareFunction === LessCompare || compareFunction === LessEqualCompare || compareFunction === GreaterCompare || compareFunction === GreaterEqualCompare) { 6720 compareStepNode = this.compareNode; 6721 } else { 6722 compareNode = this.compareNode; 6723 warnOnce('TSL: Only "LessCompare", "LessEqualCompare", "GreaterCompare" and "GreaterEqualCompare" are supported for depth texture comparison fallback.'); 6724 } 6725 } 6726 } 6727 properties.uvNode = uvNode; 6728 properties.levelNode = levelNode; 6729 properties.biasNode = this.biasNode; 6730 properties.compareNode = compareNode; 6731 properties.compareStepNode = compareStepNode; 6732 properties.gradNode = this.gradNode; 6733 properties.depthNode = this.depthNode; 6734 properties.offsetNode = this.offsetNode; 6735 } 6736 /** 6737 * Generates the uv code snippet. 6738 * 6739 * @param {NodeBuilder} builder - The current node builder. 6740 * @param {Node} uvNode - The uv node to generate code for. 6741 * @return {string} The generated code snippet. 6742 */ 6743 generateUV(builder, uvNode) { 6744 return uvNode.build(builder, this.sampler === true ? "vec2" : "ivec2"); 6745 } 6746 /** 6747 * Generates the offset code snippet. 6748 * 6749 * @param {NodeBuilder} builder - The current node builder. 6750 * @param {Node} offsetNode - The offset node to generate code for. 6751 * @return {string} The generated code snippet. 6752 */ 6753 generateOffset(builder, offsetNode) { 6754 return offsetNode.build(builder, "ivec2"); 6755 } 6756 /** 6757 * Generates the snippet for the texture sampling. 6758 * 6759 * @param {NodeBuilder} builder - The current node builder. 6760 * @param {string} textureProperty - The texture property. 6761 * @param {string} uvSnippet - The uv snippet. 6762 * @param {?string} levelSnippet - The level snippet. 6763 * @param {?string} biasSnippet - The bias snippet. 6764 * @param {?string} depthSnippet - The depth snippet. 6765 * @param {?string} compareSnippet - The compare snippet. 6766 * @param {?Array<string>} gradSnippet - The grad snippet. 6767 * @param {?string} offsetSnippet - The offset snippet. 6768 * @return {string} The generated code snippet. 6769 */ 6770 generateSnippet(builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet) { 6771 const texture3 = this.value; 6772 let snippet; 6773 if (biasSnippet) { 6774 snippet = builder.generateTextureBias(texture3, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet); 6775 } else if (gradSnippet) { 6776 snippet = builder.generateTextureGrad(texture3, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet); 6777 } else if (compareSnippet) { 6778 snippet = builder.generateTextureCompare(texture3, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet); 6779 } else if (this.sampler === false) { 6780 snippet = builder.generateTextureLoad(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet); 6781 } else if (levelSnippet) { 6782 snippet = builder.generateTextureLevel(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet); 6783 } else { 6784 snippet = builder.generateTexture(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet); 6785 } 6786 return snippet; 6787 } 6788 /** 6789 * Generates the code snippet of the texture node. 6790 * 6791 * @param {NodeBuilder} builder - The current node builder. 6792 * @param {string} output - The current output. 6793 * @return {string} The generated code snippet. 6794 */ 6795 generate(builder, output3) { 6796 const texture3 = this.value; 6797 const properties = builder.getNodeProperties(this); 6798 const textureProperty = super.generate(builder, "property"); 6799 if (/^sampler/.test(output3)) { 6800 return textureProperty + "_sampler"; 6801 } else if (builder.isReference(output3)) { 6802 return textureProperty; 6803 } else { 6804 const nodeData = builder.getDataFromNode(this); 6805 const nodeType = this.getNodeType(builder); 6806 let propertyName = nodeData.propertyName; 6807 if (propertyName === void 0) { 6808 const { uvNode, levelNode, biasNode, compareNode, compareStepNode, depthNode, gradNode, offsetNode } = properties; 6809 const uvSnippet = this.generateUV(builder, uvNode); 6810 const levelSnippet = levelNode ? levelNode.build(builder, "float") : null; 6811 const biasSnippet = biasNode ? biasNode.build(builder, "float") : null; 6812 const depthSnippet = depthNode ? depthNode.build(builder, "int") : null; 6813 const compareSnippet = compareNode ? compareNode.build(builder, "float") : null; 6814 const compareStepSnippet = compareStepNode ? compareStepNode.build(builder, "float") : null; 6815 const gradSnippet = gradNode ? [gradNode[0].build(builder, "vec2"), gradNode[1].build(builder, "vec2")] : null; 6816 const offsetSnippet = offsetNode ? this.generateOffset(builder, offsetNode) : null; 6817 let finalDepthSnippet = depthSnippet; 6818 if (finalDepthSnippet === null && texture3.isArrayTexture && this.isTexture3DNode !== true) { 6819 finalDepthSnippet = "0"; 6820 } 6821 const nodeVar = builder.getVarFromNode(this); 6822 propertyName = builder.getPropertyName(nodeVar); 6823 let snippet2 = this.generateSnippet(builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, finalDepthSnippet, compareSnippet, gradSnippet, offsetSnippet); 6824 if (compareStepSnippet !== null) { 6825 const compareFunction = texture3.compareFunction; 6826 if (compareFunction === GreaterCompare || compareFunction === GreaterEqualCompare) { 6827 snippet2 = step(expression(snippet2, nodeType), expression(compareStepSnippet, "float")).build(builder, nodeType); 6828 } else { 6829 snippet2 = step(expression(compareStepSnippet, "float"), expression(snippet2, nodeType)).build(builder, nodeType); 6830 } 6831 } 6832 builder.addLineFlowCode(`${propertyName} = ${snippet2}`, this); 6833 nodeData.snippet = snippet2; 6834 nodeData.propertyName = propertyName; 6835 } 6836 let snippet = propertyName; 6837 if (builder.needsToWorkingColorSpace(texture3)) { 6838 snippet = colorSpaceToWorking(expression(snippet, nodeType), texture3.colorSpace).setup(builder).build(builder, nodeType); 6839 } 6840 return builder.format(snippet, nodeType, output3); 6841 } 6842 } 6843 /** 6844 * Sets the sampler value. 6845 * 6846 * @param {boolean} value - The sampler value to set. 6847 * @return {TextureNode} A reference to this texture node. 6848 */ 6849 setSampler(value) { 6850 this.sampler = value; 6851 return this; 6852 } 6853 /** 6854 * Returns the sampler value. 6855 * 6856 * @return {boolean} The sampler value. 6857 */ 6858 getSampler() { 6859 return this.sampler; 6860 } 6861 // @TODO: Move to TSL 6862 /** 6863 * Samples the texture with the given uv node. 6864 * 6865 * @param {Node} uvNode - The uv node. 6866 * @return {TextureNode} A texture node representing the texture sample. 6867 */ 6868 sample(uvNode) { 6869 const textureNode = this.clone(); 6870 textureNode.uvNode = nodeObject(uvNode); 6871 textureNode.referenceNode = this.getBase(); 6872 return nodeObject(textureNode); 6873 } 6874 /** 6875 * TSL function for creating a texture node that fetches/loads texels without interpolation. 6876 * 6877 * @param {Node<uvec2>} uvNode - The uv node. 6878 * @returns {TextureNode} A texture node representing the texture load. 6879 */ 6880 load(uvNode) { 6881 return this.sample(uvNode).setSampler(false); 6882 } 6883 /** 6884 * Samples a blurred version of the texture by defining an internal bias. 6885 * 6886 * @param {Node<float>} amountNode - How blurred the texture should be. 6887 * @return {TextureNode} A texture node representing the texture sample. 6888 */ 6889 blur(amountNode) { 6890 const textureNode = this.clone(); 6891 textureNode.biasNode = nodeObject(amountNode).mul(maxMipLevel(textureNode)); 6892 textureNode.referenceNode = this.getBase(); 6893 const map = textureNode.value; 6894 if (textureNode.generateMipmaps === false && (map && map.generateMipmaps === false || map.minFilter === NearestFilter || map.magFilter === NearestFilter)) { 6895 warn("TSL: texture().blur() requires mipmaps and sampling. Use .generateMipmaps=true and .minFilter/.magFilter=THREE.LinearFilter in the Texture."); 6896 textureNode.biasNode = null; 6897 } 6898 return nodeObject(textureNode); 6899 } 6900 /** 6901 * Samples a specific mip of the texture. 6902 * 6903 * @param {Node<int>} levelNode - The mip level to sample. 6904 * @return {TextureNode} A texture node representing the texture sample. 6905 */ 6906 level(levelNode) { 6907 const textureNode = this.clone(); 6908 textureNode.levelNode = nodeObject(levelNode); 6909 textureNode.referenceNode = this.getBase(); 6910 return nodeObject(textureNode); 6911 } 6912 /** 6913 * Returns the texture size of the requested level. 6914 * 6915 * @param {Node<int>} levelNode - The level to compute the size for. 6916 * @return {TextureSizeNode} The texture size. 6917 */ 6918 size(levelNode) { 6919 return textureSize(this, levelNode); 6920 } 6921 /** 6922 * Samples the texture with the given bias. 6923 * 6924 * @param {Node<float>} biasNode - The bias node. 6925 * @return {TextureNode} A texture node representing the texture sample. 6926 */ 6927 bias(biasNode) { 6928 const textureNode = this.clone(); 6929 textureNode.biasNode = nodeObject(biasNode); 6930 textureNode.referenceNode = this.getBase(); 6931 return nodeObject(textureNode); 6932 } 6933 /** 6934 * Returns the base texture of this node. 6935 * @return {TextureNode} The base texture node. 6936 */ 6937 getBase() { 6938 return this.referenceNode ? this.referenceNode.getBase() : this; 6939 } 6940 /** 6941 * Samples the texture by executing a compare operation. 6942 * 6943 * @param {Node<float>} compareNode - The node that defines the compare value. 6944 * @return {TextureNode} A texture node representing the texture sample. 6945 */ 6946 compare(compareNode) { 6947 const textureNode = this.clone(); 6948 textureNode.compareNode = nodeObject(compareNode); 6949 textureNode.referenceNode = this.getBase(); 6950 return nodeObject(textureNode); 6951 } 6952 /** 6953 * Samples the texture using an explicit gradient. 6954 * 6955 * @param {Node<vec2>} gradNodeX - The gradX node. 6956 * @param {Node<vec2>} gradNodeY - The gradY node. 6957 * @return {TextureNode} A texture node representing the texture sample. 6958 */ 6959 grad(gradNodeX, gradNodeY) { 6960 const textureNode = this.clone(); 6961 textureNode.gradNode = [nodeObject(gradNodeX), nodeObject(gradNodeY)]; 6962 textureNode.referenceNode = this.getBase(); 6963 return nodeObject(textureNode); 6964 } 6965 /** 6966 * Samples the texture by defining a depth node. 6967 * 6968 * @param {Node<int>} depthNode - The depth node. 6969 * @return {TextureNode} A texture node representing the texture sample. 6970 */ 6971 depth(depthNode) { 6972 const textureNode = this.clone(); 6973 textureNode.depthNode = nodeObject(depthNode); 6974 textureNode.referenceNode = this.getBase(); 6975 return nodeObject(textureNode); 6976 } 6977 /** 6978 * Samples the texture by defining an offset node. 6979 * 6980 * @param {Node<ivec2>} offsetNode - The offset node. 6981 * @return {TextureNode} A texture node representing the texture sample. 6982 */ 6983 offset(offsetNode) { 6984 const textureNode = this.clone(); 6985 textureNode.offsetNode = nodeObject(offsetNode); 6986 textureNode.referenceNode = this.getBase(); 6987 return nodeObject(textureNode); 6988 } 6989 // -- 6990 serialize(data) { 6991 super.serialize(data); 6992 data.value = this.value.toJSON(data.meta).uuid; 6993 data.sampler = this.sampler; 6994 data.updateMatrix = this.updateMatrix; 6995 data.updateType = this.updateType; 6996 } 6997 deserialize(data) { 6998 super.deserialize(data); 6999 this.value = data.meta.textures[data.value]; 7000 this.sampler = data.sampler; 7001 this.updateMatrix = data.updateMatrix; 7002 this.updateType = data.updateType; 7003 } 7004 /** 7005 * The update is used to implement the update of the uv transformation matrix. 7006 */ 7007 update() { 7008 const texture3 = this.value; 7009 const matrixUniform = this._matrixUniform; 7010 if (matrixUniform !== null) matrixUniform.value = texture3.matrix; 7011 if (texture3.matrixAutoUpdate === true) { 7012 texture3.updateMatrix(); 7013 } 7014 const flipYUniform = this._flipYUniform; 7015 if (flipYUniform !== null) { 7016 flipYUniform.value = texture3.image instanceof ImageBitmap && texture3.flipY === true || texture3.isRenderTargetTexture === true || texture3.isFramebufferTexture === true || texture3.isDepthTexture === true; 7017 } 7018 } 7019 /** 7020 * Clones the texture node. 7021 * 7022 * @return {TextureNode} The cloned texture node. 7023 */ 7024 clone() { 7025 const newNode = new this.constructor(this.value, this.uvNode, this.levelNode, this.biasNode); 7026 newNode.sampler = this.sampler; 7027 newNode.depthNode = this.depthNode; 7028 newNode.compareNode = this.compareNode; 7029 newNode.gradNode = this.gradNode; 7030 newNode.offsetNode = this.offsetNode; 7031 return newNode; 7032 } 7033}; 7034var textureBase = /* @__PURE__ */ nodeProxy(TextureNode).setParameterLength(1, 4).setName("texture"); 7035var texture = (value = EmptyTexture$1, uvNode = null, levelNode = null, biasNode = null) => { 7036 let textureNode; 7037 if (value && value.isTextureNode === true) { 7038 textureNode = nodeObject(value.clone()); 7039 textureNode.referenceNode = value.getBase(); 7040 if (uvNode !== null) textureNode.uvNode = nodeObject(uvNode); 7041 if (levelNode !== null) textureNode.levelNode = nodeObject(levelNode); 7042 if (biasNode !== null) textureNode.biasNode = nodeObject(biasNode); 7043 } else { 7044 textureNode = textureBase(value, uvNode, levelNode, biasNode); 7045 } 7046 return textureNode; 7047}; 7048var uniformTexture = (value = EmptyTexture$1) => texture(value); 7049var textureLoad = (...params) => texture(...params).setSampler(false); 7050var textureLevel = (value, uv3, level) => texture(value, uv3).level(level); 7051var sampler = (value) => (value.isNode === true ? value : texture(value)).convert("sampler"); 7052var samplerComparison = (value) => (value.isNode === true ? value : texture(value)).convert("samplerComparison"); 7053var BufferNode = class extends UniformNode { 7054 static get type() { 7055 return "BufferNode"; 7056 } 7057 /** 7058 * Constructs a new buffer node. 7059 * 7060 * @param {Array<number>} value - Array-like buffer data. 7061 * @param {string} bufferType - The data type of the buffer. 7062 * @param {number} [bufferCount=0] - The count of buffer elements. 7063 */ 7064 constructor(value, bufferType, bufferCount = 0) { 7065 super(value, bufferType); 7066 this.isBufferNode = true; 7067 this.bufferType = bufferType; 7068 this.bufferCount = bufferCount; 7069 this.updateRanges = []; 7070 } 7071 /** 7072 * Adds a range of data in the data array to be updated on the GPU. 7073 * 7074 * @param {number} start - Position at which to start update. 7075 * @param {number} count - The number of components to update. 7076 */ 7077 addUpdateRange(start, count) { 7078 this.updateRanges.push({ start, count }); 7079 } 7080 /** 7081 * Clears the update ranges. 7082 */ 7083 clearUpdateRanges() { 7084 this.updateRanges.length = 0; 7085 } 7086 /** 7087 * The data type of the buffer elements. 7088 * 7089 * @param {NodeBuilder} builder - The current node builder. 7090 * @return {string} The element type. 7091 */ 7092 getElementType(builder) { 7093 return this.getNodeType(builder); 7094 } 7095 /** 7096 * Overwrites the default implementation to return a fixed value `'buffer'`. 7097 * 7098 * @param {NodeBuilder} builder - The current node builder. 7099 * @return {string} The input type. 7100 */ 7101 getInputType() { 7102 return "buffer"; 7103 } 7104}; 7105var buffer = (value, type, count) => new BufferNode(value, type, count); 7106var UniformArrayElementNode = class extends ArrayElementNode { 7107 static get type() { 7108 return "UniformArrayElementNode"; 7109 } 7110 /** 7111 * Constructs a new buffer node. 7112 * 7113 * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access. 7114 * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array. 7115 */ 7116 constructor(uniformArrayNode, indexNode) { 7117 super(uniformArrayNode, indexNode); 7118 this.isArrayBufferElementNode = true; 7119 } 7120 generate(builder) { 7121 const snippet = super.generate(builder); 7122 const type = this.getNodeType(builder); 7123 const paddedType = this.node.getPaddedType(); 7124 return builder.format(snippet, paddedType, type); 7125 } 7126}; 7127var UniformArrayNode = class extends BufferNode { 7128 static get type() { 7129 return "UniformArrayNode"; 7130 } 7131 /** 7132 * Constructs a new uniform array node. 7133 * 7134 * @param {Array<any>} value - Array holding the buffer data. 7135 * @param {?string} [elementType=null] - The data type of a buffer element. 7136 */ 7137 constructor(value, elementType = null) { 7138 super(null); 7139 this.array = value; 7140 this.elementType = elementType === null ? getValueType(value[0]) : elementType; 7141 this.paddedType = this.getPaddedType(); 7142 this.updateType = NodeUpdateType.RENDER; 7143 this.isArrayBufferNode = true; 7144 } 7145 /** 7146 * This method is overwritten since the node type is inferred from the 7147 * {@link UniformArrayNode#paddedType}. 7148 * 7149 * @param {NodeBuilder} builder - The current node builder. 7150 * @return {string} The node type. 7151 */ 7152 generateNodeType() { 7153 return this.paddedType; 7154 } 7155 /** 7156 * The data type of the array elements. 7157 * 7158 * @param {NodeBuilder} builder - The current node builder. 7159 * @return {string} The element type. 7160 */ 7161 getElementType() { 7162 return this.elementType; 7163 } 7164 /** 7165 * Returns the padded type based on the element type. 7166 * 7167 * @return {string} The padded type. 7168 */ 7169 getPaddedType() { 7170 const elementType = this.elementType; 7171 let paddedType = "vec4"; 7172 if (elementType === "mat2") { 7173 paddedType = "mat2"; 7174 } else if (/mat/.test(elementType) === true) { 7175 paddedType = "mat4"; 7176 } else if (elementType.charAt(0) === "i") { 7177 paddedType = "ivec4"; 7178 } else if (elementType.charAt(0) === "u") { 7179 paddedType = "uvec4"; 7180 } 7181 return paddedType; 7182 } 7183 /** 7184 * The update makes sure to correctly transfer the data from the (complex) objects 7185 * in the array to the internal, correctly padded value buffer. 7186 * 7187 * @param {NodeFrame} frame - A reference to the current node frame. 7188 */ 7189 update() { 7190 const { array: array3, value } = this; 7191 const elementType = this.elementType; 7192 if (elementType === "float" || elementType === "int" || elementType === "uint") { 7193 for (let i = 0; i < array3.length; i++) { 7194 const index = i * 4; 7195 value[index] = array3[i]; 7196 } 7197 } else if (elementType === "color") { 7198 for (let i = 0; i < array3.length; i++) { 7199 const index = i * 4; 7200 const vector = array3[i]; 7201 value[index] = vector.r; 7202 value[index + 1] = vector.g; 7203 value[index + 2] = vector.b || 0; 7204 } 7205 } else if (elementType === "mat2") { 7206 for (let i = 0; i < array3.length; i++) { 7207 const index = i * 4; 7208 const matrix = array3[i]; 7209 value[index] = matrix.elements[0]; 7210 value[index + 1] = matrix.elements[1]; 7211 value[index + 2] = matrix.elements[2]; 7212 value[index + 3] = matrix.elements[3]; 7213 } 7214 } else if (elementType === "mat3") { 7215 for (let i = 0; i < array3.length; i++) { 7216 const index = i * 16; 7217 const matrix = array3[i]; 7218 value[index] = matrix.elements[0]; 7219 value[index + 1] = matrix.elements[1]; 7220 value[index + 2] = matrix.elements[2]; 7221 value[index + 4] = matrix.elements[3]; 7222 value[index + 5] = matrix.elements[4]; 7223 value[index + 6] = matrix.elements[5]; 7224 value[index + 8] = matrix.elements[6]; 7225 value[index + 9] = matrix.elements[7]; 7226 value[index + 10] = matrix.elements[8]; 7227 value[index + 15] = 1; 7228 } 7229 } else if (elementType === "mat4") { 7230 for (let i = 0; i < array3.length; i++) { 7231 const index = i * 16; 7232 const matrix = array3[i]; 7233 for (let i2 = 0; i2 < matrix.elements.length; i2++) { 7234 value[index + i2] = matrix.elements[i2]; 7235 } 7236 } 7237 } else { 7238 for (let i = 0; i < array3.length; i++) { 7239 const index = i * 4; 7240 const vector = array3[i]; 7241 value[index] = vector.x; 7242 value[index + 1] = vector.y; 7243 value[index + 2] = vector.z || 0; 7244 value[index + 3] = vector.w || 0; 7245 } 7246 } 7247 } 7248 /** 7249 * Implement the value buffer creation based on the array data. 7250 * 7251 * @param {NodeBuilder} builder - A reference to the current node builder. 7252 * @return {null} 7253 */ 7254 setup(builder) { 7255 const length3 = this.array.length; 7256 const elementType = this.elementType; 7257 let arrayType = Float32Array; 7258 const paddedType = this.paddedType; 7259 const paddedElementLength = builder.getTypeLength(paddedType); 7260 if (elementType.charAt(0) === "i") arrayType = Int32Array; 7261 if (elementType.charAt(0) === "u") arrayType = Uint32Array; 7262 this.value = new arrayType(length3 * paddedElementLength); 7263 this.bufferCount = length3; 7264 this.bufferType = paddedType; 7265 this.update(); 7266 return super.setup(builder); 7267 } 7268 /** 7269 * Overwrites the default `element()` method to provide element access 7270 * based on {@link UniformArrayNode}. 7271 * 7272 * @param {IndexNode} indexNode - The index node. 7273 * @return {UniformArrayElementNode} 7274 */ 7275 element(indexNode) { 7276 return new UniformArrayElementNode(this, nodeObject(indexNode)); 7277 } 7278}; 7279var uniformArray = (values, nodeType) => new UniformArrayNode(values, nodeType); 7280var BuiltinNode = class extends Node2 { 7281 /** 7282 * Constructs a new builtin node. 7283 * 7284 * @param {string} name - The name of the built-in shader variable. 7285 */ 7286 constructor(name) { 7287 super("float"); 7288 this.name = name; 7289 this.isBuiltinNode = true; 7290 } 7291 /** 7292 * Generates the code snippet of the builtin node. 7293 * 7294 * @param {NodeBuilder} builder - The current node builder. 7295 * @return {string} The generated code snippet. 7296 */ 7297 generate() { 7298 return this.name; 7299 } 7300}; 7301var builtin = nodeProxy(BuiltinNode).setParameterLength(1); 7302var _screenSizeVec; 7303var _viewportVec; 7304var ScreenNode = class _ScreenNode extends Node2 { 7305 static get type() { 7306 return "ScreenNode"; 7307 } 7308 /** 7309 * Constructs a new screen node. 7310 * 7311 * @param {('coordinate'|'viewport'|'size'|'uv'|'dpr')} scope - The node's scope. 7312 */ 7313 constructor(scope) { 7314 super(); 7315 this.scope = scope; 7316 this._output = null; 7317 this.isViewportNode = true; 7318 } 7319 /** 7320 * This method is overwritten since the node type depends on the selected scope. 7321 * 7322 * @return {('float'|'vec2'|'vec4')} The node type. 7323 */ 7324 generateNodeType() { 7325 if (this.scope === _ScreenNode.DPR) return "float"; 7326 if (this.scope === _ScreenNode.VIEWPORT) return "vec4"; 7327 else return "vec2"; 7328 } 7329 /** 7330 * This method is overwritten since the node's update type depends on the selected scope. 7331 * 7332 * @return {NodeUpdateType} The update type. 7333 */ 7334 getUpdateType() { 7335 let updateType = NodeUpdateType.NONE; 7336 if (this.scope === _ScreenNode.SIZE || this.scope === _ScreenNode.VIEWPORT || this.scope === _ScreenNode.DPR) { 7337 updateType = NodeUpdateType.RENDER; 7338 } 7339 this.updateType = updateType; 7340 return updateType; 7341 } 7342 /** 7343 * `ScreenNode` implements {@link Node#update} to retrieve viewport and size information 7344 * from the current renderer. 7345 * 7346 * @param {NodeFrame} frame - A reference to the current node frame. 7347 */ 7348 update({ renderer }) { 7349 const renderTarget = renderer.getRenderTarget(); 7350 if (this.scope === _ScreenNode.VIEWPORT) { 7351 if (renderTarget !== null) { 7352 _viewportVec.copy(renderTarget.viewport); 7353 } else { 7354 renderer.getViewport(_viewportVec); 7355 _viewportVec.multiplyScalar(renderer.getPixelRatio()); 7356 } 7357 } else if (this.scope === _ScreenNode.DPR) { 7358 this._output.value = renderer.getPixelRatio(); 7359 } else { 7360 if (renderTarget !== null) { 7361 _screenSizeVec.width = renderTarget.width; 7362 _screenSizeVec.height = renderTarget.height; 7363 } else { 7364 renderer.getDrawingBufferSize(_screenSizeVec); 7365 } 7366 } 7367 } 7368 setup() { 7369 const scope = this.scope; 7370 let output3 = null; 7371 if (scope === _ScreenNode.SIZE) { 7372 output3 = uniform(_screenSizeVec || (_screenSizeVec = new Vector2())); 7373 } else if (scope === _ScreenNode.VIEWPORT) { 7374 output3 = uniform(_viewportVec || (_viewportVec = new Vector4())); 7375 } else if (scope === _ScreenNode.DPR) { 7376 output3 = uniform(1); 7377 } else { 7378 output3 = vec2(screenCoordinate.div(screenSize)); 7379 } 7380 this._output = output3; 7381 return output3; 7382 } 7383 generate(builder) { 7384 if (this.scope === _ScreenNode.COORDINATE) { 7385 let coord = builder.getFragCoord(); 7386 if (builder.isFlipY()) { 7387 const size3 = builder.getNodeProperties(screenSize).outputNode.build(builder); 7388 coord = `${builder.getType("vec2")}( ${coord}.x, ${size3}.y - ${coord}.y )`; 7389 } 7390 return coord; 7391 } 7392 return super.generate(builder); 7393 } 7394}; 7395ScreenNode.COORDINATE = "coordinate"; 7396ScreenNode.VIEWPORT = "viewport"; 7397ScreenNode.SIZE = "size"; 7398ScreenNode.UV = "uv"; 7399ScreenNode.DPR = "dpr"; 7400var screenDPR = /* @__PURE__ */ nodeImmutable(ScreenNode, ScreenNode.DPR); 7401var screenUV = /* @__PURE__ */ nodeImmutable(ScreenNode, ScreenNode.UV); 7402var screenSize = /* @__PURE__ */ nodeImmutable(ScreenNode, ScreenNode.SIZE); 7403var screenCoordinate = /* @__PURE__ */ nodeImmutable(ScreenNode, ScreenNode.COORDINATE); 7404var viewport = /* @__PURE__ */ nodeImmutable(ScreenNode, ScreenNode.VIEWPORT); 7405var viewportSize = viewport.zw; 7406var viewportCoordinate = /* @__PURE__ */ screenCoordinate.sub(viewport.xy); 7407var viewportUV = /* @__PURE__ */ viewportCoordinate.div(viewportSize); 7408var viewportResolution = /* @__PURE__ */ Fn(() => { 7409 warn('TSL: "viewportResolution" is deprecated. Use "screenSize" instead.', new StackTrace()); 7410 return screenSize; 7411}, "vec2").once()(); 7412var _cameraProjectionMatrixBase = null; 7413var _cameraProjectionMatrixArray = null; 7414var _cameraProjectionMatrixInverseBase = null; 7415var _cameraProjectionMatrixInverseArray = null; 7416var _cameraViewMatrixBase = null; 7417var _cameraViewMatrixArray = null; 7418var _cameraWorldMatrixBase = null; 7419var _cameraWorldMatrixArray = null; 7420var _cameraNormalMatrixBase = null; 7421var _cameraNormalMatrixArray = null; 7422var _cameraPositionBase = null; 7423var _cameraPositionArray = null; 7424var _cameraViewportBase = null; 7425var _cameraViewportArray = null; 7426var cameraIndex = /* @__PURE__ */ uniform(0, "uint").setName("u_cameraIndex").setGroup(sharedUniformGroup("cameraIndex")).toVarying("v_cameraIndex"); 7427var cameraNear = /* @__PURE__ */ uniform("float").setName("cameraNear").setGroup(renderGroup).onRenderUpdate(({ camera }) => camera.near); 7428var cameraFar = /* @__PURE__ */ uniform("float").setName("cameraFar").setGroup(renderGroup).onRenderUpdate(({ camera }) => camera.far); 7429var cameraProjectionMatrix = /* @__PURE__ */ Fn(({ camera }) => { 7430 let cameraProjectionMatrix3; 7431 if (camera.isArrayCamera && camera.cameras.length > 0) { 7432 const matrices = []; 7433 for (const subCamera of camera.cameras) { 7434 matrices.push(subCamera.projectionMatrix); 7435 } 7436 if (_cameraProjectionMatrixArray === null) { 7437 _cameraProjectionMatrixArray = uniformArray(matrices).setGroup(renderGroup).setName("cameraProjectionMatrices"); 7438 } else { 7439 _cameraProjectionMatrixArray.array = matrices; 7440 } 7441 cameraProjectionMatrix3 = _cameraProjectionMatrixArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraProjectionMatrix"); 7442 } else { 7443 if (_cameraProjectionMatrixBase === null) { 7444 _cameraProjectionMatrixBase = uniform(camera.projectionMatrix).setName("cameraProjectionMatrix").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }) => camera2.projectionMatrix); 7445 } 7446 cameraProjectionMatrix3 = _cameraProjectionMatrixBase; 7447 } 7448 return cameraProjectionMatrix3; 7449}).once()(); 7450var cameraProjectionMatrixInverse = /* @__PURE__ */ Fn(({ camera }) => { 7451 let cameraProjectionMatrixInverse3; 7452 if (camera.isArrayCamera && camera.cameras.length > 0) { 7453 const matrices = []; 7454 for (const subCamera of camera.cameras) { 7455 matrices.push(subCamera.projectionMatrixInverse); 7456 } 7457 if (_cameraProjectionMatrixInverseArray === null) { 7458 _cameraProjectionMatrixInverseArray = uniformArray(matrices).setGroup(renderGroup).setName("cameraProjectionMatricesInverse"); 7459 } else { 7460 _cameraProjectionMatrixInverseArray.array = matrices; 7461 } 7462 cameraProjectionMatrixInverse3 = _cameraProjectionMatrixInverseArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraProjectionMatrixInverse"); 7463 } else { 7464 if (_cameraProjectionMatrixInverseBase === null) { 7465 _cameraProjectionMatrixInverseBase = uniform(camera.projectionMatrixInverse).setName("cameraProjectionMatrixInverse").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }) => camera2.projectionMatrixInverse); 7466 } 7467 cameraProjectionMatrixInverse3 = _cameraProjectionMatrixInverseBase; 7468 } 7469 return cameraProjectionMatrixInverse3; 7470}).once()(); 7471var cameraViewMatrix = /* @__PURE__ */ Fn(({ camera }) => { 7472 let cameraViewMatrix3; 7473 if (camera.isArrayCamera && camera.cameras.length > 0) { 7474 const matrices = []; 7475 for (const subCamera of camera.cameras) { 7476 matrices.push(subCamera.matrixWorldInverse); 7477 } 7478 if (_cameraViewMatrixArray === null) { 7479 _cameraViewMatrixArray = uniformArray(matrices).setGroup(renderGroup).setName("cameraViewMatrices"); 7480 } else { 7481 _cameraViewMatrixArray.array = matrices; 7482 } 7483 cameraViewMatrix3 = _cameraViewMatrixArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraViewMatrix"); 7484 } else { 7485 if (_cameraViewMatrixBase === null) { 7486 _cameraViewMatrixBase = uniform(camera.matrixWorldInverse).setName("cameraViewMatrix").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }) => camera2.matrixWorldInverse); 7487 } 7488 cameraViewMatrix3 = _cameraViewMatrixBase; 7489 } 7490 return cameraViewMatrix3; 7491}).once()(); 7492var cameraWorldMatrix = /* @__PURE__ */ Fn(({ camera }) => { 7493 let cameraWorldMatrix3; 7494 if (camera.isArrayCamera && camera.cameras.length > 0) { 7495 const matrices = []; 7496 for (const subCamera of camera.cameras) { 7497 matrices.push(subCamera.matrixWorld); 7498 } 7499 if (_cameraWorldMatrixArray === null) { 7500 _cameraWorldMatrixArray = uniformArray(matrices).setGroup(renderGroup).setName("cameraWorldMatrices"); 7501 } else { 7502 _cameraWorldMatrixArray.array = matrices; 7503 } 7504 cameraWorldMatrix3 = _cameraWorldMatrixArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraWorldMatrix"); 7505 } else { 7506 if (_cameraWorldMatrixBase === null) { 7507 _cameraWorldMatrixBase = uniform(camera.matrixWorld).setName("cameraWorldMatrix").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }) => camera2.matrixWorld); 7508 } 7509 cameraWorldMatrix3 = _cameraWorldMatrixBase; 7510 } 7511 return cameraWorldMatrix3; 7512}).once()(); 7513var cameraNormalMatrix = /* @__PURE__ */ Fn(({ camera }) => { 7514 let cameraNormalMatrix3; 7515 if (camera.isArrayCamera && camera.cameras.length > 0) { 7516 const matrices = []; 7517 for (const subCamera of camera.cameras) { 7518 matrices.push(subCamera.normalMatrix); 7519 } 7520 if (_cameraNormalMatrixArray === null) { 7521 _cameraNormalMatrixArray = uniformArray(matrices).setGroup(renderGroup).setName("cameraNormalMatrices"); 7522 } else { 7523 _cameraNormalMatrixArray.array = matrices; 7524 } 7525 cameraNormalMatrix3 = _cameraNormalMatrixArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraNormalMatrix"); 7526 } else { 7527 if (_cameraNormalMatrixBase === null) { 7528 _cameraNormalMatrixBase = uniform(camera.normalMatrix).setName("cameraNormalMatrix").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }) => camera2.normalMatrix); 7529 } 7530 cameraNormalMatrix3 = _cameraNormalMatrixBase; 7531 } 7532 return cameraNormalMatrix3; 7533}).once()(); 7534var cameraPosition = /* @__PURE__ */ Fn(({ camera }) => { 7535 let cameraPosition3; 7536 if (camera.isArrayCamera && camera.cameras.length > 0) { 7537 const positions = []; 7538 for (let i = 0, l = camera.cameras.length; i < l; i++) { 7539 positions.push(new Vector3()); 7540 } 7541 if (_cameraPositionArray === null) { 7542 _cameraPositionArray = uniformArray(positions).setGroup(renderGroup).setName("cameraPositions").onRenderUpdate(({ camera: camera2 }, self2) => { 7543 const subCameras = camera2.cameras; 7544 const array3 = self2.array; 7545 for (let i = 0, l = subCameras.length; i < l; i++) { 7546 array3[i].setFromMatrixPosition(subCameras[i].matrixWorld); 7547 } 7548 }); 7549 } else { 7550 _cameraPositionArray.array = positions; 7551 } 7552 cameraPosition3 = _cameraPositionArray.element(camera.isMultiViewCamera ? builtin("gl_ViewID_OVR") : cameraIndex).toConst("cameraPosition"); 7553 } else { 7554 if (_cameraPositionBase === null) { 7555 _cameraPositionBase = uniform(new Vector3()).setName("cameraPosition").setGroup(renderGroup).onRenderUpdate(({ camera: camera2 }, self2) => self2.value.setFromMatrixPosition(camera2.matrixWorld)); 7556 } 7557 cameraPosition3 = _cameraPositionBase; 7558 } 7559 return cameraPosition3; 7560}).once()(); 7561var cameraViewport = /* @__PURE__ */ Fn(({ camera }) => { 7562 let cameraViewport3; 7563 if (camera.isArrayCamera && camera.cameras.length > 0) { 7564 const viewports = []; 7565 for (const subCamera of camera.cameras) { 7566 viewports.push(subCamera.viewport); 7567 } 7568 if (_cameraViewportArray === null) { 7569 _cameraViewportArray = uniformArray(viewports, "vec4").setGroup(renderGroup).setName("cameraViewports"); 7570 } else { 7571 _cameraViewportArray.array = viewports; 7572 } 7573 cameraViewport3 = _cameraViewportArray.element(cameraIndex).toConst("cameraViewport"); 7574 } else { 7575 if (_cameraViewportBase === null) { 7576 _cameraViewportBase = vec4(0, 0, screenSize.x, screenSize.y).toConst("cameraViewport"); 7577 } 7578 cameraViewport3 = _cameraViewportBase; 7579 } 7580 return cameraViewport3; 7581}).once()(); 7582var _sphere = /* @__PURE__ */ new Sphere(); 7583var Object3DNode = class _Object3DNode extends Node2 { 7584 static get type() { 7585 return "Object3DNode"; 7586 } 7587 /** 7588 * Constructs a new object 3D node. 7589 * 7590 * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. 7591 * @param {?Object3D} [object3d=null] - The 3D object. 7592 */ 7593 constructor(scope, object3d = null) { 7594 super(); 7595 this.scope = scope; 7596 this.object3d = object3d; 7597 this.updateType = NodeUpdateType.OBJECT; 7598 this.uniformNode = new UniformNode(null); 7599 } 7600 /** 7601 * Overwritten since the node type is inferred from the scope. 7602 * 7603 * @return {('mat4'|'vec3'|'float')} The node type. 7604 */ 7605 generateNodeType() { 7606 const scope = this.scope; 7607 if (scope === _Object3DNode.WORLD_MATRIX) { 7608 return "mat4"; 7609 } else if (scope === _Object3DNode.POSITION || scope === _Object3DNode.VIEW_POSITION || scope === _Object3DNode.DIRECTION || scope === _Object3DNode.SCALE) { 7610 return "vec3"; 7611 } else if (scope === _Object3DNode.RADIUS) { 7612 return "float"; 7613 } 7614 } 7615 /** 7616 * Updates the uniform value depending on the scope. 7617 * 7618 * @param {NodeFrame} frame - The current node frame. 7619 */ 7620 update(frame) { 7621 const object = this.object3d; 7622 const uniformNode = this.uniformNode; 7623 const scope = this.scope; 7624 if (scope === _Object3DNode.WORLD_MATRIX) { 7625 uniformNode.value = object.matrixWorld; 7626 } else if (scope === _Object3DNode.POSITION) { 7627 uniformNode.value = uniformNode.value || new Vector3(); 7628 uniformNode.value.setFromMatrixPosition(object.matrixWorld); 7629 } else if (scope === _Object3DNode.SCALE) { 7630 uniformNode.value = uniformNode.value || new Vector3(); 7631 uniformNode.value.setFromMatrixScale(object.matrixWorld); 7632 } else if (scope === _Object3DNode.DIRECTION) { 7633 uniformNode.value = uniformNode.value || new Vector3(); 7634 object.getWorldDirection(uniformNode.value); 7635 } else if (scope === _Object3DNode.VIEW_POSITION) { 7636 const camera = frame.camera; 7637 uniformNode.value = uniformNode.value || new Vector3(); 7638 uniformNode.value.setFromMatrixPosition(object.matrixWorld); 7639 uniformNode.value.applyMatrix4(camera.matrixWorldInverse); 7640 } else if (scope === _Object3DNode.RADIUS) { 7641 const geometry = frame.object.geometry; 7642 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 7643 _sphere.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld); 7644 uniformNode.value = _sphere.radius; 7645 } 7646 } 7647 /** 7648 * Generates the code snippet of the uniform node. The node type of the uniform 7649 * node also depends on the selected scope. 7650 * 7651 * @param {NodeBuilder} builder - The current node builder. 7652 * @return {string} The generated code snippet. 7653 */ 7654 generate(builder) { 7655 const scope = this.scope; 7656 if (scope === _Object3DNode.WORLD_MATRIX) { 7657 this.uniformNode.nodeType = "mat4"; 7658 } else if (scope === _Object3DNode.POSITION || scope === _Object3DNode.VIEW_POSITION || scope === _Object3DNode.DIRECTION || scope === _Object3DNode.SCALE) { 7659 this.uniformNode.nodeType = "vec3"; 7660 } else if (scope === _Object3DNode.RADIUS) { 7661 this.uniformNode.nodeType = "float"; 7662 } 7663 return this.uniformNode.build(builder); 7664 } 7665 serialize(data) { 7666 super.serialize(data); 7667 data.scope = this.scope; 7668 } 7669 deserialize(data) { 7670 super.deserialize(data); 7671 this.scope = data.scope; 7672 } 7673}; 7674Object3DNode.WORLD_MATRIX = "worldMatrix"; 7675Object3DNode.POSITION = "position"; 7676Object3DNode.SCALE = "scale"; 7677Object3DNode.VIEW_POSITION = "viewPosition"; 7678Object3DNode.DIRECTION = "direction"; 7679Object3DNode.RADIUS = "radius"; 7680var objectDirection = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.DIRECTION).setParameterLength(1); 7681var objectWorldMatrix = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.WORLD_MATRIX).setParameterLength(1); 7682var objectPosition = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.POSITION).setParameterLength(1); 7683var objectScale = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.SCALE).setParameterLength(1); 7684var objectViewPosition = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.VIEW_POSITION).setParameterLength(1); 7685var objectRadius = /* @__PURE__ */ nodeProxy(Object3DNode, Object3DNode.RADIUS).setParameterLength(1); 7686var ModelNode = class extends Object3DNode { 7687 static get type() { 7688 return "ModelNode"; 7689 } 7690 /** 7691 * Constructs a new object model node. 7692 * 7693 * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. 7694 */ 7695 constructor(scope) { 7696 super(scope); 7697 } 7698 /** 7699 * Extracts the model reference from the frame state and then 7700 * updates the uniform value depending on the scope. 7701 * 7702 * @param {NodeFrame} frame - The current node frame. 7703 */ 7704 update(frame) { 7705 this.object3d = frame.object; 7706 super.update(frame); 7707 } 7708}; 7709var modelDirection = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.DIRECTION); 7710var modelWorldMatrix = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.WORLD_MATRIX); 7711var modelPosition = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.POSITION); 7712var modelScale = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.SCALE); 7713var modelViewPosition = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.VIEW_POSITION); 7714var modelRadius = /* @__PURE__ */ nodeImmutable(ModelNode, ModelNode.RADIUS); 7715var modelNormalMatrix = /* @__PURE__ */ uniform(new Matrix3()).onObjectUpdate(({ object }, self2) => self2.value.getNormalMatrix(object.matrixWorld)); 7716var modelWorldMatrixInverse = /* @__PURE__ */ uniform(new Matrix4()).onObjectUpdate(({ object }, self2) => self2.value.copy(object.matrixWorld).invert()); 7717var modelViewMatrix = /* @__PURE__ */ Fn((builder) => { 7718 return builder.context.modelViewMatrix || mediumpModelViewMatrix; 7719}).once()().toVar("modelViewMatrix"); 7720var mediumpModelViewMatrix = /* @__PURE__ */ cameraViewMatrix.mul(modelWorldMatrix); 7721var highpModelViewMatrix = /* @__PURE__ */ Fn((builder) => { 7722 builder.context.isHighPrecisionModelViewMatrix = true; 7723 return uniform("mat4").onObjectUpdate(({ object, camera }) => { 7724 return object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); 7725 }); 7726}).once()().toVar("highpModelViewMatrix"); 7727var highpModelNormalViewMatrix = /* @__PURE__ */ Fn((builder) => { 7728 const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; 7729 return uniform("mat3").onObjectUpdate(({ object, camera }) => { 7730 if (isHighPrecisionModelViewMatrix !== true) { 7731 object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); 7732 } 7733 return object.normalMatrix.getNormalMatrix(object.modelViewMatrix); 7734 }); 7735}).once()().toVar("highpModelNormalViewMatrix"); 7736var clipSpace = /* @__PURE__ */ Fn((builder) => { 7737 if (builder.shaderStage !== "fragment") { 7738 warnOnce("TSL: `clipSpace` is only available in fragment stage."); 7739 return vec4(); 7740 } 7741 return builder.context.clipSpace.toVarying("v_clipSpace"); 7742}).once()(); 7743var positionGeometry = /* @__PURE__ */ attribute("position", "vec3"); 7744var positionLocal = /* @__PURE__ */ positionGeometry.toVarying("positionLocal"); 7745var positionPrevious = /* @__PURE__ */ positionGeometry.toVarying("positionPrevious"); 7746var positionWorld = /* @__PURE__ */ Fn((builder) => { 7747 return modelWorldMatrix.mul(positionLocal).xyz.toVarying(builder.getSubBuildProperty("v_positionWorld")); 7748}, "vec3").once(["POSITION"])(); 7749var positionWorldDirection = /* @__PURE__ */ Fn(() => { 7750 const vertexPWD = positionLocal.transformDirection(modelWorldMatrix).toVarying("v_positionWorldDirection"); 7751 return vertexPWD.normalize().toVar("positionWorldDirection"); 7752}, "vec3").once(["POSITION"])(); 7753var positionView = /* @__PURE__ */ Fn((builder) => { 7754 if (builder.shaderStage === "fragment" && builder.material.vertexNode) { 7755 const viewPos = cameraProjectionMatrixInverse.mul(clipSpace); 7756 return viewPos.xyz.div(viewPos.w).toVar("positionView"); 7757 } 7758 return builder.context.setupPositionView().toVarying("v_positionView"); 7759}, "vec3").once(["POSITION", "VERTEX"])(); 7760var positionViewDirection = /* @__PURE__ */ Fn((builder) => { 7761 let output3; 7762 if (builder.camera.isOrthographicCamera) { 7763 output3 = vec3(0, 0, 1); 7764 } else { 7765 output3 = positionView.negate().toVarying("v_positionViewDirection").normalize(); 7766 } 7767 return output3.toVar("positionViewDirection"); 7768}, "vec3").once(["POSITION"])(); 7769var FrontFacingNode = class extends Node2 { 7770 static get type() { 7771 return "FrontFacingNode"; 7772 } 7773 /** 7774 * Constructs a new front facing node. 7775 */ 7776 constructor() { 7777 super("bool"); 7778 this.isFrontFacingNode = true; 7779 } 7780 generate(builder) { 7781 if (builder.shaderStage !== "fragment") return "true"; 7782 const { material } = builder; 7783 if (material.side === BackSide) { 7784 return "false"; 7785 } 7786 return builder.getFrontFacing(); 7787 } 7788}; 7789var frontFacing = /* @__PURE__ */ nodeImmutable(FrontFacingNode); 7790var faceDirection = /* @__PURE__ */ float(frontFacing).mul(2).sub(1); 7791var directionToFaceDirection = /* @__PURE__ */ Fn(([direction], { material }) => { 7792 const side = material.side; 7793 if (side === BackSide) { 7794 direction = direction.mul(-1); 7795 } else if (side === DoubleSide) { 7796 direction = direction.mul(faceDirection); 7797 } 7798 return direction; 7799}); 7800var normalGeometry = /* @__PURE__ */ attribute("normal", "vec3"); 7801var normalLocal = /* @__PURE__ */ Fn((builder) => { 7802 if (builder.geometry.hasAttribute("normal") === false) { 7803 warn('TSL: Vertex attribute "normal" not found on geometry.'); 7804 return vec3(0, 1, 0); 7805 } 7806 return normalGeometry; 7807}, "vec3").once()().toVar("normalLocal"); 7808var normalFlat = /* @__PURE__ */ positionView.dFdx().cross(positionView.dFdy()).normalize().toVar("normalFlat"); 7809var normalViewGeometry = /* @__PURE__ */ Fn((builder) => { 7810 let node; 7811 if (builder.isFlatShading()) { 7812 node = normalFlat; 7813 } else { 7814 node = transformNormalToView(normalLocal).toVarying("v_normalViewGeometry").normalize(); 7815 } 7816 return node; 7817}, "vec3").once()().toVar("normalViewGeometry"); 7818var normalWorldGeometry = /* @__PURE__ */ Fn((builder) => { 7819 let normal2 = normalViewGeometry.transformDirection(cameraViewMatrix); 7820 if (builder.isFlatShading() !== true) { 7821 normal2 = normal2.toVarying("v_normalWorldGeometry"); 7822 } 7823 return normal2.normalize().toVar("normalWorldGeometry"); 7824}, "vec3").once()(); 7825var normalView = /* @__PURE__ */ Fn((builder) => { 7826 let node; 7827 if (builder.subBuildFn === "NORMAL" || builder.subBuildFn === "VERTEX") { 7828 node = normalViewGeometry; 7829 if (builder.isFlatShading() !== true) { 7830 node = directionToFaceDirection(node); 7831 } 7832 } else { 7833 node = builder.context.setupNormal().context({ getUV: null, getTextureLevel: null }); 7834 } 7835 return node; 7836}, "vec3").once(["NORMAL", "VERTEX"])().toVar("normalView"); 7837var normalWorld = /* @__PURE__ */ normalView.transformDirection(cameraViewMatrix).toVar("normalWorld"); 7838var clearcoatNormalView = /* @__PURE__ */ Fn(({ subBuildFn, context: context3 }) => { 7839 let node; 7840 if (subBuildFn === "NORMAL" || subBuildFn === "VERTEX") { 7841 node = normalView; 7842 } else { 7843 node = context3.setupClearcoatNormal().context({ getUV: null, getTextureLevel: null }); 7844 } 7845 return node; 7846}, "vec3").once(["NORMAL", "VERTEX"])().toVar("clearcoatNormalView"); 7847var transformNormal = /* @__PURE__ */ Fn(([normal2, matrix = modelWorldMatrix]) => { 7848 const m = mat3(matrix); 7849 const transformedNormal = normal2.div(vec3(m[0].dot(m[0]), m[1].dot(m[1]), m[2].dot(m[2]))); 7850 return m.mul(transformedNormal).xyz; 7851}); 7852var transformNormalToView = /* @__PURE__ */ Fn(([normal2], builder) => { 7853 const modelNormalViewMatrix = builder.context.modelNormalViewMatrix; 7854 if (modelNormalViewMatrix) { 7855 return modelNormalViewMatrix.transformDirection(normal2); 7856 } 7857 const transformedNormal = modelNormalMatrix.mul(normal2); 7858 return cameraViewMatrix.transformDirection(transformedNormal); 7859}); 7860var transformedNormalView = Fn(() => { 7861 warn('TSL: "transformedNormalView" is deprecated. Use "normalView" instead.'); 7862 return normalView; 7863}).once(["NORMAL", "VERTEX"])(); 7864var transformedNormalWorld = Fn(() => { 7865 warn('TSL: "transformedNormalWorld" is deprecated. Use "normalWorld" instead.'); 7866 return normalWorld; 7867}).once(["NORMAL", "VERTEX"])(); 7868var transformedClearcoatNormalView = Fn(() => { 7869 warn('TSL: "transformedClearcoatNormalView" is deprecated. Use "clearcoatNormalView" instead.'); 7870 return clearcoatNormalView; 7871}).once(["NORMAL", "VERTEX"])(); 7872var _m1$1 = /* @__PURE__ */ new Matrix4(); 7873var materialRefractionRatio = /* @__PURE__ */ uniform(0).onReference(({ material }) => material).onObjectUpdate(({ material }) => material.refractionRatio); 7874var materialEnvIntensity = /* @__PURE__ */ uniform(1).onReference(({ material }) => material).onObjectUpdate(function({ material, scene }) { 7875 return material.envMap ? material.envMapIntensity : scene.environmentIntensity; 7876}); 7877var materialEnvRotation = /* @__PURE__ */ uniform(new Matrix4()).onReference(function(frame) { 7878 return frame.material; 7879}).onObjectUpdate(function({ material, scene }) { 7880 const rotation = scene.environment !== null && material.envMap === null ? scene.environmentRotation : material.envMapRotation; 7881 if (rotation) { 7882 _m1$1.makeRotationFromEuler(rotation).transpose(); 7883 } else { 7884 _m1$1.identity(); 7885 } 7886 return _m1$1; 7887}); 7888var reflectView = /* @__PURE__ */ positionViewDirection.negate().reflect(normalView); 7889var refractView = /* @__PURE__ */ positionViewDirection.negate().refract(normalView, materialRefractionRatio); 7890var reflectVector = /* @__PURE__ */ reflectView.transformDirection(cameraViewMatrix).toVar("reflectVector"); 7891var refractVector = /* @__PURE__ */ refractView.transformDirection(cameraViewMatrix).toVar("reflectVector"); 7892var EmptyTexture = /* @__PURE__ */ new CubeTexture(); 7893var CubeTextureNode = class extends TextureNode { 7894 static get type() { 7895 return "CubeTextureNode"; 7896 } 7897 /** 7898 * Constructs a new cube texture node. 7899 * 7900 * @param {CubeTexture} value - The cube texture. 7901 * @param {?Node<vec3>} [uvNode=null] - The uv node. 7902 * @param {?Node<int>} [levelNode=null] - The level node. 7903 * @param {?Node<float>} [biasNode=null] - The bias node. 7904 */ 7905 constructor(value, uvNode = null, levelNode = null, biasNode = null) { 7906 super(value, uvNode, levelNode, biasNode); 7907 this.isCubeTextureNode = true; 7908 } 7909 /** 7910 * Overwrites the default implementation to return the appropriate cube texture type. 7911 * 7912 * @param {NodeBuilder} builder - The current node builder. 7913 * @return {string} The input type. 7914 */ 7915 getInputType() { 7916 if (this.value.isDepthTexture === true) { 7917 return "cubeDepthTexture"; 7918 } 7919 return "cubeTexture"; 7920 } 7921 /** 7922 * Returns a default uvs based on the mapping type of the cube texture. 7923 * 7924 * @return {Node<vec3>} The default uv attribute. 7925 */ 7926 getDefaultUV() { 7927 const texture3 = this.value; 7928 if (texture3.mapping === CubeReflectionMapping) { 7929 return reflectVector; 7930 } else if (texture3.mapping === CubeRefractionMapping) { 7931 return refractVector; 7932 } else { 7933 error('CubeTextureNode: Mapping "%s" not supported.', texture3.mapping); 7934 return vec3(0, 0, 0); 7935 } 7936 } 7937 /** 7938 * Overwritten with an empty implementation since the `updateMatrix` flag is ignored 7939 * for cube textures. The uv transformation matrix is not applied to cube textures. 7940 * 7941 * @param {boolean} value - The update toggle. 7942 */ 7943 setUpdateMatrix() { 7944 } 7945 // Ignore .updateMatrix for CubeTextureNode 7946 /** 7947 * Setups the uv node. Depending on the backend as well as the texture type, it might be necessary 7948 * to modify the uv node for correct sampling. 7949 * 7950 * @param {NodeBuilder} builder - The current node builder. 7951 * @param {Node} uvNode - The uv node to setup. 7952 * @return {Node} The updated uv node. 7953 */ 7954 setupUV(builder, uvNode) { 7955 const texture3 = this.value; 7956 if (texture3.isDepthTexture === true) { 7957 if (builder.renderer.coordinateSystem === WebGPUCoordinateSystem) { 7958 return vec3(uvNode.x, uvNode.y.negate(), uvNode.z); 7959 } 7960 return uvNode; 7961 } 7962 uvNode = materialEnvRotation.mul(uvNode); 7963 if (builder.renderer.coordinateSystem === WebGPUCoordinateSystem || !texture3.isRenderTargetTexture) { 7964 uvNode = vec3(uvNode.x.negate(), uvNode.yz); 7965 } 7966 return uvNode; 7967 } 7968 /** 7969 * Generates the uv code snippet. 7970 * 7971 * @param {NodeBuilder} builder - The current node builder. 7972 * @param {Node} cubeUV - The uv node to generate code for. 7973 * @return {string} The generated code snippet. 7974 */ 7975 generateUV(builder, cubeUV) { 7976 return cubeUV.build(builder, this.sampler === true ? "vec3" : "ivec3"); 7977 } 7978}; 7979var cubeTextureBase = /* @__PURE__ */ nodeProxy(CubeTextureNode).setParameterLength(1, 4).setName("cubeTexture"); 7980var cubeTexture = (value = EmptyTexture, uvNode = null, levelNode = null, biasNode = null) => { 7981 let textureNode; 7982 if (value && value.isCubeTextureNode === true) { 7983 textureNode = nodeObject(value.clone()); 7984 textureNode.referenceNode = value; 7985 if (uvNode !== null) textureNode.uvNode = nodeObject(uvNode); 7986 if (levelNode !== null) textureNode.levelNode = nodeObject(levelNode); 7987 if (biasNode !== null) textureNode.biasNode = nodeObject(biasNode); 7988 } else { 7989 textureNode = cubeTextureBase(value, uvNode, levelNode, biasNode); 7990 } 7991 return textureNode; 7992}; 7993var uniformCubeTexture = (value = EmptyTexture) => cubeTextureBase(value); 7994var ReferenceElementNode2 = class extends ArrayElementNode { 7995 static get type() { 7996 return "ReferenceElementNode"; 7997 } 7998 /** 7999 * Constructs a new reference element node. 8000 * 8001 * @param {?ReferenceNode} referenceNode - The reference node. 8002 * @param {Node} indexNode - The index node that defines the element access. 8003 */ 8004 constructor(referenceNode, indexNode) { 8005 super(referenceNode, indexNode); 8006 this.referenceNode = referenceNode; 8007 this.isReferenceElementNode = true; 8008 } 8009 /** 8010 * This method is overwritten since the node type is inferred from 8011 * the uniform type of the reference node. 8012 * 8013 * @return {string} The node type. 8014 */ 8015 generateNodeType() { 8016 return this.referenceNode.uniformType; 8017 } 8018 generate(builder) { 8019 const snippet = super.generate(builder); 8020 const arrayType = this.referenceNode.getNodeType(builder); 8021 const elementType = this.getNodeType(builder); 8022 return builder.format(snippet, arrayType, elementType); 8023 } 8024}; 8025var ReferenceNode = class extends Node2 { 8026 static get type() { 8027 return "ReferenceNode"; 8028 } 8029 /** 8030 * Constructs a new reference node. 8031 * 8032 * @param {string} property - The name of the property the node refers to. 8033 * @param {string} uniformType - The uniform type that should be used to represent the property value. 8034 * @param {?Object} [object=null] - The object the property belongs to. 8035 * @param {?number} [count=null] - When the linked property is an array-like, this parameter defines its length. 8036 */ 8037 constructor(property3, uniformType, object = null, count = null) { 8038 super(); 8039 this.property = property3; 8040 this.uniformType = uniformType; 8041 this.object = object; 8042 this.count = count; 8043 this.properties = property3.split("."); 8044 this.reference = object; 8045 this.node = null; 8046 this.group = null; 8047 this.name = null; 8048 this.updateType = NodeUpdateType.OBJECT; 8049 } 8050 /** 8051 * When the referred property is array-like, this method can be used 8052 * to access elements via an index node. 8053 * 8054 * @param {IndexNode} indexNode - indexNode. 8055 * @return {ReferenceElementNode} A reference to an element. 8056 */ 8057 element(indexNode) { 8058 return new ReferenceElementNode2(this, nodeObject(indexNode)); 8059 } 8060 /** 8061 * Sets the uniform group for this reference node. 8062 * 8063 * @param {UniformGroupNode} group - The uniform group to set. 8064 * @return {ReferenceNode} A reference to this node. 8065 */ 8066 setGroup(group) { 8067 this.group = group; 8068 return this; 8069 } 8070 /** 8071 * Sets the name for the internal uniform. 8072 * 8073 * @param {string} name - The label to set. 8074 * @return {ReferenceNode} A reference to this node. 8075 */ 8076 setName(name) { 8077 this.name = name; 8078 return this; 8079 } 8080 /** 8081 * Sets the label for the internal uniform. 8082 * 8083 * @deprecated 8084 * @param {string} name - The label to set. 8085 * @return {ReferenceNode} A reference to this node. 8086 */ 8087 label(name) { 8088 warn('TSL: "label()" has been deprecated. Use "setName()" instead.'); 8089 return this.setName(name); 8090 } 8091 /** 8092 * Sets the node type which automatically defines the internal 8093 * uniform type. 8094 * 8095 * @param {string} uniformType - The type to set. 8096 */ 8097 setNodeType(uniformType) { 8098 let node = null; 8099 if (this.count !== null) { 8100 node = buffer(null, uniformType, this.count); 8101 } else if (Array.isArray(this.getValueFromReference())) { 8102 node = uniformArray(null, uniformType); 8103 } else if (uniformType === "texture") { 8104 node = texture(null); 8105 } else if (uniformType === "cubeTexture") { 8106 node = cubeTexture(null); 8107 } else { 8108 node = uniform(null, uniformType); 8109 } 8110 if (this.group !== null) { 8111 node.setGroup(this.group); 8112 } 8113 if (this.name !== null) node.setName(this.name); 8114 this.node = node; 8115 } 8116 /** 8117 * This method is overwritten since the node type is inferred from 8118 * the type of the reference node. 8119 * 8120 * @param {NodeBuilder} builder - The current node builder. 8121 * @return {string} The node type. 8122 */ 8123 generateNodeType(builder) { 8124 if (this.node === null) { 8125 this.updateReference(builder); 8126 this.updateValue(); 8127 } 8128 return this.node.getNodeType(builder); 8129 } 8130 /** 8131 * Returns the property value from the given referred object. 8132 * 8133 * @param {Object} [object=this.reference] - The object to retrieve the property value from. 8134 * @return {any} The value. 8135 */ 8136 getValueFromReference(object = this.reference) { 8137 const { properties } = this; 8138 let value = object[properties[0]]; 8139 for (let i = 1; i < properties.length; i++) { 8140 value = value[properties[i]]; 8141 } 8142 return value; 8143 } 8144 /** 8145 * Allows to update the reference based on the given state. The state is only 8146 * evaluated {@link ReferenceNode#object} is not set. 8147 * 8148 * @param {(NodeFrame|NodeBuilder)} state - The current state. 8149 * @return {Object} The updated reference. 8150 */ 8151 updateReference(state) { 8152 this.reference = this.object !== null ? this.object : state.object; 8153 return this.reference; 8154 } 8155 /** 8156 * The output of the reference node is the internal uniform node. 8157 * 8158 * @param {NodeBuilder} builder - The current node builder. 8159 * @return {UniformNode} The output node. 8160 */ 8161 setup() { 8162 this.updateValue(); 8163 return this.node; 8164 } 8165 /** 8166 * Overwritten to update the internal uniform value. 8167 * 8168 * @param {NodeFrame} frame - A reference to the current node frame. 8169 */ 8170 update() { 8171 this.updateValue(); 8172 } 8173 /** 8174 * Retrieves the value from the referred object property and uses it 8175 * to updated the internal uniform. 8176 */ 8177 updateValue() { 8178 if (this.node === null) this.setNodeType(this.uniformType); 8179 const value = this.getValueFromReference(); 8180 if (Array.isArray(value)) { 8181 this.node.array = value; 8182 } else { 8183 this.node.value = value; 8184 } 8185 } 8186}; 8187var reference = (name, type, object) => new ReferenceNode(name, type, object); 8188var referenceBuffer = (name, type, count, object) => new ReferenceNode(name, type, object, count); 8189var MaterialReferenceNode = class extends ReferenceNode { 8190 static get type() { 8191 return "MaterialReferenceNode"; 8192 } 8193 /** 8194 * Constructs a new material reference node. 8195 * 8196 * @param {string} property - The name of the property the node refers to. 8197 * @param {string} inputType - The uniform type that should be used to represent the property value. 8198 * @param {?Material} [material=null] - The material the property belongs to. When no material is set, 8199 * the node refers to the material of the current rendered object. 8200 */ 8201 constructor(property3, inputType, material = null) { 8202 super(property3, inputType, material); 8203 this.material = material; 8204 this.isMaterialReferenceNode = true; 8205 } 8206 /** 8207 * Updates the reference based on the given state. The state is only evaluated 8208 * {@link MaterialReferenceNode#material} is not set. 8209 * 8210 * @param {(NodeFrame|NodeBuilder)} state - The current state. 8211 * @return {Object} The updated reference. 8212 */ 8213 updateReference(state) { 8214 this.reference = this.material !== null ? this.material : state.material; 8215 return this.reference; 8216 } 8217}; 8218var materialReference = (name, type, material = null) => new MaterialReferenceNode(name, type, material); 8219var uv = uv$1(); 8220var q0 = positionView.dFdx(); 8221var q1 = positionView.dFdy(); 8222var st0 = uv.dFdx(); 8223var st1 = uv.dFdy(); 8224var N = normalView; 8225var q1perp = q1.cross(N); 8226var q0perp = N.cross(q0); 8227var T = q1perp.mul(st0.x).add(q0perp.mul(st1.x)); 8228var B = q1perp.mul(st0.y).add(q0perp.mul(st1.y)); 8229var det = T.dot(T).max(B.dot(B)); 8230var scale$1 = det.equal(0).select(0, det.inverseSqrt()); 8231var tangentViewFrame = /* @__PURE__ */ T.mul(scale$1).toVar("tangentViewFrame"); 8232var bitangentViewFrame = /* @__PURE__ */ B.mul(scale$1).toVar("bitangentViewFrame"); 8233var tangentGeometry = /* @__PURE__ */ attribute("tangent", "vec4"); 8234var tangentLocal = /* @__PURE__ */ tangentGeometry.xyz.toVar("tangentLocal"); 8235var tangentView = /* @__PURE__ */ Fn((builder) => { 8236 let node; 8237 if (builder.subBuildFn === "VERTEX" || builder.geometry.hasAttribute("tangent")) { 8238 node = modelViewMatrix.mul(vec4(tangentLocal, 0)).xyz.toVarying("v_tangentView").normalize(); 8239 } else { 8240 node = tangentViewFrame; 8241 } 8242 if (builder.isFlatShading() !== true) { 8243 node = directionToFaceDirection(node); 8244 } 8245 return node; 8246}, "vec3").once(["NORMAL", "VERTEX"])().toVar("tangentView"); 8247var tangentWorld = /* @__PURE__ */ tangentView.transformDirection(cameraViewMatrix).toVarying("v_tangentWorld").normalize().toVar("tangentWorld"); 8248var getBitangent = /* @__PURE__ */ Fn(([crossNormalTangent, varyingName], builder) => { 8249 let bitangent = crossNormalTangent.mul(tangentGeometry.w).xyz; 8250 if (builder.subBuildFn === "NORMAL" && builder.isFlatShading() !== true) { 8251 bitangent = bitangent.toVarying(varyingName); 8252 } 8253 return bitangent; 8254}).once(["NORMAL"]); 8255var bitangentGeometry = /* @__PURE__ */ getBitangent(normalGeometry.cross(tangentGeometry), "v_bitangentGeometry").normalize().toVar("bitangentGeometry"); 8256var bitangentLocal = /* @__PURE__ */ getBitangent(normalLocal.cross(tangentLocal), "v_bitangentLocal").normalize().toVar("bitangentLocal"); 8257var bitangentView = /* @__PURE__ */ Fn((builder) => { 8258 let node; 8259 if (builder.subBuildFn === "VERTEX" || builder.geometry.hasAttribute("tangent")) { 8260 node = getBitangent(normalView.cross(tangentView), "v_bitangentView").normalize(); 8261 } else { 8262 node = bitangentViewFrame; 8263 } 8264 if (builder.isFlatShading() !== true) { 8265 node = directionToFaceDirection(node); 8266 } 8267 return node; 8268}, "vec3").once(["NORMAL", "VERTEX"])().toVar("bitangentView"); 8269var bitangentWorld = /* @__PURE__ */ getBitangent(normalWorld.cross(tangentWorld), "v_bitangentWorld").normalize().toVar("bitangentWorld"); 8270var TBNViewMatrix = /* @__PURE__ */ mat3(tangentView, bitangentView, normalView).toVar("TBNViewMatrix"); 8271var parallaxDirection = /* @__PURE__ */ positionViewDirection.mul(TBNViewMatrix); 8272var parallaxUV = (uv3, scale2) => uv3.sub(parallaxDirection.mul(scale2)); 8273var bentNormalView = /* @__PURE__ */ Fn(() => { 8274 let bentNormal = anisotropyB.cross(positionViewDirection); 8275 bentNormal = bentNormal.cross(anisotropyB).normalize(); 8276 bentNormal = mix(bentNormal, normalView, anisotropy.mul(roughness.oneMinus()).oneMinus().pow2().pow2()).normalize(); 8277 return bentNormal; 8278}).once()(); 8279var directionToColor = (node) => nodeObject(node).mul(0.5).add(0.5); 8280var colorToDirection = (node) => nodeObject(node).mul(2).sub(1); 8281var unpackNormal = (xy) => vec3(xy, sqrt(saturate(float(1).sub(dot(xy, xy))))); 8282var NormalMapNode = class extends TempNode { 8283 static get type() { 8284 return "NormalMapNode"; 8285 } 8286 /** 8287 * Constructs a new normal map node. 8288 * 8289 * @param {Node<vec3>} node - Represents the normal map data. 8290 * @param {?Node<vec2>} [scaleNode=null] - Controls the intensity of the effect. 8291 */ 8292 constructor(node, scaleNode = null) { 8293 super("vec3"); 8294 this.node = node; 8295 this.scaleNode = scaleNode; 8296 this.normalMapType = TangentSpaceNormalMap; 8297 this.unpackNormalMode = NoNormalPacking; 8298 } 8299 setup(builder) { 8300 const { normalMapType, scaleNode, unpackNormalMode } = this; 8301 let normalMap3 = this.node.mul(2).sub(1); 8302 if (normalMapType === TangentSpaceNormalMap) { 8303 if (unpackNormalMode === NormalRGPacking) { 8304 normalMap3 = unpackNormal(normalMap3.xy); 8305 } else if (unpackNormalMode === NormalGAPacking) { 8306 normalMap3 = unpackNormal(normalMap3.yw); 8307 } else if (unpackNormalMode !== NoNormalPacking) { 8308 error(`THREE.NodeMaterial: Unexpected unpack normal mode: ${unpackNormalMode}`); 8309 } 8310 } else { 8311 if (unpackNormalMode !== NoNormalPacking) { 8312 error(`THREE.NodeMaterial: Normal map type '${normalMapType}' is not compatible with unpack normal mode '${unpackNormalMode}'`); 8313 } 8314 } 8315 if (scaleNode !== null) { 8316 let scale2 = scaleNode; 8317 if (builder.isFlatShading() === true) { 8318 scale2 = directionToFaceDirection(scale2); 8319 } 8320 normalMap3 = vec3(normalMap3.xy.mul(scale2), normalMap3.z); 8321 } 8322 let output3 = null; 8323 if (normalMapType === ObjectSpaceNormalMap) { 8324 output3 = transformNormalToView(normalMap3); 8325 } else if (normalMapType === TangentSpaceNormalMap) { 8326 output3 = TBNViewMatrix.mul(normalMap3).normalize(); 8327 } else { 8328 error(`NodeMaterial: Unsupported normal map type: ${normalMapType}`); 8329 output3 = normalView; 8330 } 8331 return output3; 8332 } 8333}; 8334var normalMap = /* @__PURE__ */ nodeProxy(NormalMapNode).setParameterLength(1, 2); 8335var dHdxy_fwd = Fn(({ textureNode, bumpScale }) => { 8336 const sampleTexture = (callback) => textureNode.isolate().context({ getUV: (texNode) => callback(texNode.uvNode || uv$1()), forceUVContext: true }); 8337 const Hll = float(sampleTexture((uvNode) => uvNode)); 8338 return vec2( 8339 float(sampleTexture((uvNode) => uvNode.add(uvNode.dFdx()))).sub(Hll), 8340 float(sampleTexture((uvNode) => uvNode.add(uvNode.dFdy()))).sub(Hll) 8341 ).mul(bumpScale); 8342}); 8343var perturbNormalArb = Fn((inputs) => { 8344 const { surf_pos, surf_norm, dHdxy } = inputs; 8345 const vSigmaX = surf_pos.dFdx().normalize(); 8346 const vSigmaY = surf_pos.dFdy().normalize(); 8347 const vN = surf_norm; 8348 const R1 = vSigmaY.cross(vN); 8349 const R2 = vN.cross(vSigmaX); 8350 const fDet = vSigmaX.dot(R1).mul(faceDirection); 8351 const vGrad = fDet.sign().mul(dHdxy.x.mul(R1).add(dHdxy.y.mul(R2))); 8352 return fDet.abs().mul(surf_norm).sub(vGrad).normalize(); 8353}); 8354var BumpMapNode = class extends TempNode { 8355 static get type() { 8356 return "BumpMapNode"; 8357 } 8358 /** 8359 * Constructs a new bump map node. 8360 * 8361 * @param {Node<float>} textureNode - Represents the bump map data. 8362 * @param {?Node<float>} [scaleNode=null] - Controls the intensity of the bump effect. 8363 */ 8364 constructor(textureNode, scaleNode = null) { 8365 super("vec3"); 8366 this.textureNode = textureNode; 8367 this.scaleNode = scaleNode; 8368 } 8369 setup() { 8370 const bumpScale = this.scaleNode !== null ? this.scaleNode : 1; 8371 const dHdxy = dHdxy_fwd({ textureNode: this.textureNode, bumpScale }); 8372 return perturbNormalArb({ 8373 surf_pos: positionView, 8374 surf_norm: normalView, 8375 dHdxy 8376 }); 8377 } 8378}; 8379var bumpMap = /* @__PURE__ */ nodeProxy(BumpMapNode).setParameterLength(1, 2); 8380var _propertyCache = /* @__PURE__ */ new Map(); 8381var MaterialNode = class _MaterialNode extends Node2 { 8382 static get type() { 8383 return "MaterialNode"; 8384 } 8385 /** 8386 * Constructs a new material node. 8387 * 8388 * @param {string} scope - The scope defines what kind of material property is referred by the node. 8389 */ 8390 constructor(scope) { 8391 super(); 8392 this.scope = scope; 8393 } 8394 /** 8395 * Returns a cached reference node for the given property and type. 8396 * 8397 * @param {string} property - The name of the material property. 8398 * @param {string} type - The uniform type of the property. 8399 * @return {MaterialReferenceNode} A material reference node representing the property access. 8400 */ 8401 getCache(property3, type) { 8402 let node = _propertyCache.get(property3); 8403 if (node === void 0) { 8404 node = materialReference(property3, type); 8405 _propertyCache.set(property3, node); 8406 } 8407 return node; 8408 } 8409 /** 8410 * Returns a float-typed material reference node for the given property name. 8411 * 8412 * @param {string} property - The name of the material property. 8413 * @return {MaterialReferenceNode<float>} A material reference node representing the property access. 8414 */ 8415 getFloat(property3) { 8416 return this.getCache(property3, "float"); 8417 } 8418 /** 8419 * Returns a color-typed material reference node for the given property name. 8420 * 8421 * @param {string} property - The name of the material property. 8422 * @return {MaterialReferenceNode<color>} A material reference node representing the property access. 8423 */ 8424 getColor(property3) { 8425 return this.getCache(property3, "color"); 8426 } 8427 /** 8428 * Returns a texture-typed material reference node for the given property name. 8429 * 8430 * @param {string} property - The name of the material property. 8431 * @return {MaterialReferenceNode} A material reference node representing the property access. 8432 */ 8433 getTexture(property3) { 8434 return this.getCache(property3 === "map" ? "map" : property3 + "Map", "texture"); 8435 } 8436 /** 8437 * The node setup is done depending on the selected scope. Multiple material properties 8438 * might be grouped into a single node composition if they logically belong together. 8439 * 8440 * @param {NodeBuilder} builder - The current node builder. 8441 * @return {Node} The node representing the selected scope. 8442 */ 8443 setup(builder) { 8444 const material = builder.context.material; 8445 const scope = this.scope; 8446 let node = null; 8447 if (scope === _MaterialNode.COLOR) { 8448 const colorNode = material.color !== void 0 ? this.getColor(scope) : vec3(); 8449 if (material.map && material.map.isTexture === true) { 8450 node = colorNode.mul(this.getTexture("map")); 8451 } else { 8452 node = colorNode; 8453 } 8454 } else if (scope === _MaterialNode.OPACITY) { 8455 const opacityNode = this.getFloat(scope); 8456 if (material.alphaMap && material.alphaMap.isTexture === true) { 8457 node = opacityNode.mul(this.getTexture("alpha")); 8458 } else { 8459 node = opacityNode; 8460 } 8461 } else if (scope === _MaterialNode.SPECULAR_STRENGTH) { 8462 if (material.specularMap && material.specularMap.isTexture === true) { 8463 node = this.getTexture("specular").r; 8464 } else { 8465 node = float(1); 8466 } 8467 } else if (scope === _MaterialNode.SPECULAR_INTENSITY) { 8468 const specularIntensityNode = this.getFloat(scope); 8469 if (material.specularIntensityMap && material.specularIntensityMap.isTexture === true) { 8470 node = specularIntensityNode.mul(this.getTexture(scope).a); 8471 } else { 8472 node = specularIntensityNode; 8473 } 8474 } else if (scope === _MaterialNode.SPECULAR_COLOR) { 8475 const specularColorNode = this.getColor(scope); 8476 if (material.specularColorMap && material.specularColorMap.isTexture === true) { 8477 node = specularColorNode.mul(this.getTexture(scope).rgb); 8478 } else { 8479 node = specularColorNode; 8480 } 8481 } else if (scope === _MaterialNode.ROUGHNESS) { 8482 const roughnessNode = this.getFloat(scope); 8483 if (material.roughnessMap && material.roughnessMap.isTexture === true) { 8484 node = roughnessNode.mul(this.getTexture(scope).g); 8485 } else { 8486 node = roughnessNode; 8487 } 8488 } else if (scope === _MaterialNode.METALNESS) { 8489 const metalnessNode = this.getFloat(scope); 8490 if (material.metalnessMap && material.metalnessMap.isTexture === true) { 8491 node = metalnessNode.mul(this.getTexture(scope).b); 8492 } else { 8493 node = metalnessNode; 8494 } 8495 } else if (scope === _MaterialNode.EMISSIVE) { 8496 const emissiveIntensityNode = this.getFloat("emissiveIntensity"); 8497 const emissiveNode = this.getColor(scope).mul(emissiveIntensityNode); 8498 if (material.emissiveMap && material.emissiveMap.isTexture === true) { 8499 node = emissiveNode.mul(this.getTexture(scope)); 8500 } else { 8501 node = emissiveNode; 8502 } 8503 } else if (scope === _MaterialNode.NORMAL) { 8504 if (material.normalMap) { 8505 node = normalMap(this.getTexture("normal"), this.getCache("normalScale", "vec2")); 8506 node.normalMapType = material.normalMapType; 8507 if (material.normalMap.format == RGFormat || material.normalMap.format == RED_GREEN_RGTC2_Format || material.normalMap.format == RG11_EAC_Format) { 8508 node.unpackNormalMode = NormalRGPacking; 8509 } 8510 } else if (material.bumpMap) { 8511 node = bumpMap(this.getTexture("bump").r, this.getFloat("bumpScale")); 8512 } else { 8513 node = normalView; 8514 } 8515 } else if (scope === _MaterialNode.CLEARCOAT) { 8516 const clearcoatNode = this.getFloat(scope); 8517 if (material.clearcoatMap && material.clearcoatMap.isTexture === true) { 8518 node = clearcoatNode.mul(this.getTexture(scope).r); 8519 } else { 8520 node = clearcoatNode; 8521 } 8522 } else if (scope === _MaterialNode.CLEARCOAT_ROUGHNESS) { 8523 const clearcoatRoughnessNode = this.getFloat(scope); 8524 if (material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true) { 8525 node = clearcoatRoughnessNode.mul(this.getTexture(scope).r); 8526 } else { 8527 node = clearcoatRoughnessNode; 8528 } 8529 } else if (scope === _MaterialNode.CLEARCOAT_NORMAL) { 8530 if (material.clearcoatNormalMap) { 8531 node = normalMap(this.getTexture(scope), this.getCache(scope + "Scale", "vec2")); 8532 } else { 8533 node = normalView; 8534 } 8535 } else if (scope === _MaterialNode.SHEEN) { 8536 const sheenNode = this.getColor("sheenColor").mul(this.getFloat("sheen")); 8537 if (material.sheenColorMap && material.sheenColorMap.isTexture === true) { 8538 node = sheenNode.mul(this.getTexture("sheenColor").rgb); 8539 } else { 8540 node = sheenNode; 8541 } 8542 } else if (scope === _MaterialNode.SHEEN_ROUGHNESS) { 8543 const sheenRoughnessNode = this.getFloat(scope); 8544 if (material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true) { 8545 node = sheenRoughnessNode.mul(this.getTexture(scope).a); 8546 } else { 8547 node = sheenRoughnessNode; 8548 } 8549 node = node.clamp(1e-4, 1); 8550 } else if (scope === _MaterialNode.ANISOTROPY) { 8551 if (material.anisotropyMap && material.anisotropyMap.isTexture === true) { 8552 const anisotropyPolar = this.getTexture(scope); 8553 const anisotropyMat = mat2(materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x); 8554 node = anisotropyMat.mul(anisotropyPolar.rg.mul(2).sub(vec2(1)).normalize().mul(anisotropyPolar.b)); 8555 } else { 8556 node = materialAnisotropyVector; 8557 } 8558 } else if (scope === _MaterialNode.IRIDESCENCE_THICKNESS) { 8559 const iridescenceThicknessMaximum = reference("1", "float", material.iridescenceThicknessRange); 8560 if (material.iridescenceThicknessMap) { 8561 const iridescenceThicknessMinimum = reference("0", "float", material.iridescenceThicknessRange); 8562 node = iridescenceThicknessMaximum.sub(iridescenceThicknessMinimum).mul(this.getTexture(scope).g).add(iridescenceThicknessMinimum); 8563 } else { 8564 node = iridescenceThicknessMaximum; 8565 } 8566 } else if (scope === _MaterialNode.TRANSMISSION) { 8567 const transmissionNode = this.getFloat(scope); 8568 if (material.transmissionMap) { 8569 node = transmissionNode.mul(this.getTexture(scope).r); 8570 } else { 8571 node = transmissionNode; 8572 } 8573 } else if (scope === _MaterialNode.THICKNESS) { 8574 const thicknessNode = this.getFloat(scope); 8575 if (material.thicknessMap) { 8576 node = thicknessNode.mul(this.getTexture(scope).g); 8577 } else { 8578 node = thicknessNode; 8579 } 8580 } else if (scope === _MaterialNode.IOR) { 8581 node = this.getFloat(scope); 8582 } else if (scope === _MaterialNode.LIGHT_MAP) { 8583 node = this.getTexture(scope).rgb.mul(this.getFloat("lightMapIntensity")); 8584 } else if (scope === _MaterialNode.AO) { 8585 node = this.getTexture(scope).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1); 8586 } else if (scope === _MaterialNode.LINE_DASH_OFFSET) { 8587 node = material.dashOffset ? this.getFloat(scope) : float(0); 8588 } else { 8589 const outputType = this.getNodeType(builder); 8590 node = this.getCache(scope, outputType); 8591 } 8592 return node; 8593 } 8594}; 8595MaterialNode.ALPHA_TEST = "alphaTest"; 8596MaterialNode.COLOR = "color"; 8597MaterialNode.OPACITY = "opacity"; 8598MaterialNode.SHININESS = "shininess"; 8599MaterialNode.SPECULAR = "specular"; 8600MaterialNode.SPECULAR_STRENGTH = "specularStrength"; 8601MaterialNode.SPECULAR_INTENSITY = "specularIntensity"; 8602MaterialNode.SPECULAR_COLOR = "specularColor"; 8603MaterialNode.REFLECTIVITY = "reflectivity"; 8604MaterialNode.ROUGHNESS = "roughness"; 8605MaterialNode.METALNESS = "metalness"; 8606MaterialNode.NORMAL = "normal"; 8607MaterialNode.CLEARCOAT = "clearcoat"; 8608MaterialNode.CLEARCOAT_ROUGHNESS = "clearcoatRoughness"; 8609MaterialNode.CLEARCOAT_NORMAL = "clearcoatNormal"; 8610MaterialNode.EMISSIVE = "emissive"; 8611MaterialNode.ROTATION = "rotation"; 8612MaterialNode.SHEEN = "sheen"; 8613MaterialNode.SHEEN_ROUGHNESS = "sheenRoughness"; 8614MaterialNode.ANISOTROPY = "anisotropy"; 8615MaterialNode.IRIDESCENCE = "iridescence"; 8616MaterialNode.IRIDESCENCE_IOR = "iridescenceIOR"; 8617MaterialNode.IRIDESCENCE_THICKNESS = "iridescenceThickness"; 8618MaterialNode.IOR = "ior"; 8619MaterialNode.TRANSMISSION = "transmission"; 8620MaterialNode.THICKNESS = "thickness"; 8621MaterialNode.ATTENUATION_DISTANCE = "attenuationDistance"; 8622MaterialNode.ATTENUATION_COLOR = "attenuationColor"; 8623MaterialNode.LINE_SCALE = "scale"; 8624MaterialNode.LINE_DASH_SIZE = "dashSize"; 8625MaterialNode.LINE_GAP_SIZE = "gapSize"; 8626MaterialNode.LINE_WIDTH = "linewidth"; 8627MaterialNode.LINE_DASH_OFFSET = "dashOffset"; 8628MaterialNode.POINT_SIZE = "size"; 8629MaterialNode.DISPERSION = "dispersion"; 8630MaterialNode.LIGHT_MAP = "light"; 8631MaterialNode.AO = "ao"; 8632var materialAlphaTest = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ALPHA_TEST); 8633var materialColor = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.COLOR); 8634var materialShininess = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SHININESS); 8635var materialEmissive = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.EMISSIVE); 8636var materialOpacity = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.OPACITY); 8637var materialSpecular = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SPECULAR); 8638var materialSpecularIntensity = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SPECULAR_INTENSITY); 8639var materialSpecularColor = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SPECULAR_COLOR); 8640var materialSpecularStrength = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SPECULAR_STRENGTH); 8641var materialReflectivity = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.REFLECTIVITY); 8642var materialRoughness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ROUGHNESS); 8643var materialMetalness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.METALNESS); 8644var materialNormal = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.NORMAL); 8645var materialClearcoat = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.CLEARCOAT); 8646var materialClearcoatRoughness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS); 8647var materialClearcoatNormal = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.CLEARCOAT_NORMAL); 8648var materialRotation = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ROTATION); 8649var materialSheen = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SHEEN); 8650var materialSheenRoughness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.SHEEN_ROUGHNESS); 8651var materialAnisotropy = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ANISOTROPY); 8652var materialIridescence = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.IRIDESCENCE); 8653var materialIridescenceIOR = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.IRIDESCENCE_IOR); 8654var materialIridescenceThickness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS); 8655var materialTransmission = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.TRANSMISSION); 8656var materialThickness = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.THICKNESS); 8657var materialIOR = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.IOR); 8658var materialAttenuationDistance = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ATTENUATION_DISTANCE); 8659var materialAttenuationColor = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.ATTENUATION_COLOR); 8660var materialLineScale = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LINE_SCALE); 8661var materialLineDashSize = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LINE_DASH_SIZE); 8662var materialLineGapSize = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LINE_GAP_SIZE); 8663var materialLineWidth = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LINE_WIDTH); 8664var materialLineDashOffset = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LINE_DASH_OFFSET); 8665var materialPointSize = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.POINT_SIZE); 8666var materialDispersion = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.DISPERSION); 8667var materialLightMap = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.LIGHT_MAP); 8668var materialAO = /* @__PURE__ */ nodeImmutable(MaterialNode, MaterialNode.AO); 8669var materialAnisotropyVector = /* @__PURE__ */ uniform(new Vector2()).onReference(function(frame) { 8670 return frame.material; 8671}).onRenderUpdate(function({ material }) { 8672 this.value.set(material.anisotropy * Math.cos(material.anisotropyRotation), material.anisotropy * Math.sin(material.anisotropyRotation)); 8673}); 8674var modelViewProjection = /* @__PURE__ */ Fn((builder) => { 8675 return builder.context.setupModelViewProjection(); 8676}, "vec4").once()().toVarying("v_modelViewProjection"); 8677var StorageArrayElementNode = class extends ArrayElementNode { 8678 static get type() { 8679 return "StorageArrayElementNode"; 8680 } 8681 /** 8682 * Constructs storage buffer element node. 8683 * 8684 * @param {StorageBufferNode} storageBufferNode - The storage buffer node. 8685 * @param {Node} indexNode - The index node that defines the element access. 8686 */ 8687 constructor(storageBufferNode, indexNode) { 8688 super(storageBufferNode, indexNode); 8689 this.isStorageArrayElementNode = true; 8690 } 8691 /** 8692 * The storage buffer node. 8693 * 8694 * @param {Node} value 8695 * @type {StorageBufferNode} 8696 */ 8697 set storageBufferNode(value) { 8698 this.node = value; 8699 } 8700 get storageBufferNode() { 8701 return this.node; 8702 } 8703 getMemberType(builder, name) { 8704 const structTypeNode = this.storageBufferNode.structTypeNode; 8705 if (structTypeNode) { 8706 return structTypeNode.getMemberType(builder, name); 8707 } 8708 return "void"; 8709 } 8710 setup(builder) { 8711 if (builder.isAvailable("storageBuffer") === false) { 8712 if (this.node.isPBO === true) { 8713 builder.setupPBO(this.node); 8714 } 8715 } 8716 return super.setup(builder); 8717 } 8718 generate(builder, output3) { 8719 let snippet; 8720 const isAssignContext = builder.context.assign; 8721 if (builder.isAvailable("storageBuffer") === false) { 8722 if (this.node.isPBO === true && isAssignContext !== true && (this.node.value.isInstancedBufferAttribute || builder.shaderStage !== "compute")) { 8723 snippet = builder.generatePBO(this); 8724 } else { 8725 snippet = this.node.build(builder); 8726 } 8727 } else { 8728 snippet = super.generate(builder); 8729 } 8730 if (isAssignContext !== true) { 8731 const type = this.getNodeType(builder); 8732 snippet = builder.format(snippet, type, output3); 8733 } 8734 return snippet; 8735 } 8736}; 8737var storageElement = /* @__PURE__ */ nodeProxy(StorageArrayElementNode).setParameterLength(2); 8738var StorageBufferNode = class extends BufferNode { 8739 static get type() { 8740 return "StorageBufferNode"; 8741 } 8742 /** 8743 * Constructs a new storage buffer node. 8744 * 8745 * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. 8746 * @param {?(string|Struct)} [bufferType=null] - The buffer type (e.g. `'vec3'`). 8747 * @param {number} [bufferCount=0] - The buffer count. 8748 */ 8749 constructor(value, bufferType = null, bufferCount = 0) { 8750 let nodeType, structTypeNode = null; 8751 if (bufferType && bufferType.isStruct) { 8752 nodeType = "struct"; 8753 structTypeNode = bufferType.layout; 8754 if (value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute) { 8755 bufferCount = value.count; 8756 } 8757 } else if (bufferType === null && (value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute)) { 8758 nodeType = getTypeFromLength(value.itemSize); 8759 bufferCount = value.count; 8760 } else { 8761 nodeType = bufferType; 8762 } 8763 super(value, nodeType, bufferCount); 8764 this.isStorageBufferNode = true; 8765 this.structTypeNode = structTypeNode; 8766 this.access = NodeAccess.READ_WRITE; 8767 this.isAtomic = false; 8768 this.isPBO = false; 8769 this._attribute = null; 8770 this._varying = null; 8771 this.global = true; 8772 if (value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true) { 8773 if (value.isInstancedBufferAttribute) value.isStorageInstancedBufferAttribute = true; 8774 else value.isStorageBufferAttribute = true; 8775 } 8776 } 8777 /** 8778 * This method is overwritten since the buffer data might be shared 8779 * and thus the hash should be shared as well. 8780 * 8781 * @param {NodeBuilder} builder - The current node builder. 8782 * @return {string} The hash. 8783 */ 8784 getHash(builder) { 8785 let id; 8786 if (this.bufferCount === 0) { 8787 let bufferData = builder.globalCache.getData(this.value); 8788 if (bufferData === void 0) { 8789 bufferData = { 8790 node: this 8791 }; 8792 builder.globalCache.setData(this.value, bufferData); 8793 } 8794 id = bufferData.node.id; 8795 } else { 8796 id = this.id; 8797 } 8798 return String(id); 8799 } 8800 /** 8801 * Overwrites the default implementation to return a fixed value `'indirectStorageBuffer'` or `'storageBuffer'`. 8802 * 8803 * @param {NodeBuilder} builder - The current node builder. 8804 * @return {string} The input type. 8805 */ 8806 getInputType() { 8807 return this.value.isIndirectStorageBufferAttribute ? "indirectStorageBuffer" : "storageBuffer"; 8808 } 8809 /** 8810 * Enables element access with the given index node. 8811 * 8812 * @param {IndexNode} indexNode - The index node. 8813 * @return {StorageArrayElementNode} A node representing the element access. 8814 */ 8815 element(indexNode) { 8816 return storageElement(this, indexNode); 8817 } 8818 /** 8819 * Defines whether this node is a PBO or not. Only relevant for WebGL. 8820 * 8821 * @param {boolean} value - The value so set. 8822 * @return {StorageBufferNode} A reference to this node. 8823 */ 8824 setPBO(value) { 8825 this.isPBO = value; 8826 return this; 8827 } 8828 /** 8829 * Returns the `isPBO` value. 8830 * 8831 * @return {boolean} Whether the node represents a PBO or not. 8832 */ 8833 getPBO() { 8834 return this.isPBO; 8835 } 8836 /** 8837 * Defines the node access. 8838 * 8839 * @param {string} value - The node access. 8840 * @return {StorageBufferNode} A reference to this node. 8841 */ 8842 setAccess(value) { 8843 this.access = value; 8844 return this; 8845 } 8846 /** 8847 * Convenience method for configuring a read-only node access. 8848 * 8849 * @return {StorageBufferNode} A reference to this node. 8850 */ 8851 toReadOnly() { 8852 return this.setAccess(NodeAccess.READ_ONLY); 8853 } 8854 /** 8855 * Defines whether the node is atomic or not. 8856 * 8857 * @param {boolean} value - The atomic flag. 8858 * @return {StorageBufferNode} A reference to this node. 8859 */ 8860 setAtomic(value) { 8861 this.isAtomic = value; 8862 return this; 8863 } 8864 /** 8865 * Convenience method for making this node atomic. 8866 * 8867 * @return {StorageBufferNode} A reference to this node. 8868 */ 8869 toAtomic() { 8870 return this.setAtomic(true); 8871 } 8872 /** 8873 * Returns attribute data for this storage buffer node. 8874 * 8875 * @return {{attribute: BufferAttributeNode, varying: VaryingNode}} The attribute data. 8876 */ 8877 getAttributeData() { 8878 if (this._attribute === null) { 8879 this._attribute = bufferAttribute(this.value); 8880 this._varying = varying(this._attribute); 8881 } 8882 return { 8883 attribute: this._attribute, 8884 varying: this._varying 8885 }; 8886 } 8887 /** 8888 * This method is overwritten since the node type from the availability of storage buffers 8889 * and the attribute data. 8890 * 8891 * @param {NodeBuilder} builder - The current node builder. 8892 * @return {string} The node type. 8893 */ 8894 generateNodeType(builder) { 8895 if (this.structTypeNode !== null) { 8896 return this.structTypeNode.getNodeType(builder); 8897 } 8898 if (builder.isAvailable("storageBuffer") || builder.isAvailable("indirectStorageBuffer")) { 8899 return super.generateNodeType(builder); 8900 } 8901 const { attribute: attribute3 } = this.getAttributeData(); 8902 return attribute3.getNodeType(builder); 8903 } 8904 /** 8905 * Returns the type of a member of the struct. 8906 * 8907 * @param {NodeBuilder} builder - The current node builder. 8908 * @param {string} name - The name of the member. 8909 * @return {string} The type of the member. 8910 */ 8911 getMemberType(builder, name) { 8912 if (this.structTypeNode !== null) { 8913 return this.structTypeNode.getMemberType(builder, name); 8914 } 8915 return "void"; 8916 } 8917 /** 8918 * Generates the code snippet of the storage buffer node. 8919 * 8920 * @param {NodeBuilder} builder - The current node builder. 8921 * @return {string} The generated code snippet. 8922 */ 8923 generate(builder) { 8924 if (this.structTypeNode !== null) this.structTypeNode.build(builder); 8925 if (builder.isAvailable("storageBuffer") || builder.isAvailable("indirectStorageBuffer")) { 8926 return super.generate(builder); 8927 } 8928 const { attribute: attribute3, varying: varying3 } = this.getAttributeData(); 8929 const output3 = varying3.build(builder); 8930 builder.registerTransform(output3, attribute3); 8931 return output3; 8932 } 8933}; 8934var storage = (value, type = null, count = 0) => new StorageBufferNode(value, type, count); 8935var InstanceNode = class extends Node2 { 8936 static get type() { 8937 return "InstanceNode"; 8938 } 8939 /** 8940 * Constructs a new instance node. 8941 * 8942 * @param {number} count - The number of instances. 8943 * @param {InstancedBufferAttribute|StorageInstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. 8944 * @param {?InstancedBufferAttribute|StorageInstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. 8945 */ 8946 constructor(count, instanceMatrix, instanceColor = null) { 8947 super("void"); 8948 this.count = count; 8949 this.instanceMatrix = instanceMatrix; 8950 this.instanceColor = instanceColor; 8951 this.instanceMatrixNode = null; 8952 this.instanceColorNode = null; 8953 this.updateType = NodeUpdateType.FRAME; 8954 this.buffer = null; 8955 this.bufferColor = null; 8956 this.previousInstanceMatrixNode = null; 8957 } 8958 /** 8959 * Tracks whether the matrix data is provided via a storage buffer. 8960 * 8961 * @type {boolean} 8962 */ 8963 get isStorageMatrix() { 8964 const { instanceMatrix } = this; 8965 return instanceMatrix && instanceMatrix.isStorageInstancedBufferAttribute === true; 8966 } 8967 /** 8968 * Tracks whether the color data is provided via a storage buffer. 8969 * 8970 * @type {boolean} 8971 */ 8972 get isStorageColor() { 8973 const { instanceColor } = this; 8974 return instanceColor && instanceColor.isStorageInstancedBufferAttribute === true; 8975 } 8976 /** 8977 * Setups the internal buffers and nodes and assigns the transformed vertex data 8978 * to predefined node variables for accumulation. That follows the same patterns 8979 * like with morph and skinning nodes. 8980 * 8981 * @param {NodeBuilder} builder - The current node builder. 8982 */ 8983 setup(builder) { 8984 let { instanceMatrixNode, instanceColorNode } = this; 8985 if (instanceMatrixNode === null) { 8986 instanceMatrixNode = this._createInstanceMatrixNode(true, builder); 8987 this.instanceMatrixNode = instanceMatrixNode; 8988 } 8989 const { instanceColor, isStorageColor } = this; 8990 if (instanceColor && instanceColorNode === null) { 8991 if (isStorageColor) { 8992 instanceColorNode = storage(instanceColor, "vec3", Math.max(instanceColor.count, 1)).element(instanceIndex); 8993 } else { 8994 const bufferAttribute3 = new InstancedBufferAttribute(instanceColor.array, 3); 8995 const bufferFn = instanceColor.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; 8996 this.bufferColor = bufferAttribute3; 8997 instanceColorNode = vec3(bufferFn(bufferAttribute3, "vec3", 3, 0)); 8998 } 8999 this.instanceColorNode = instanceColorNode; 9000 } 9001 const instancePosition = instanceMatrixNode.mul(positionLocal).xyz; 9002 positionLocal.assign(instancePosition); 9003 if (builder.needsPreviousData()) { 9004 positionPrevious.assign(this.getPreviousInstancedPosition(builder)); 9005 } 9006 if (builder.hasGeometryAttribute("normal")) { 9007 const instanceNormal = transformNormal(normalLocal, instanceMatrixNode); 9008 normalLocal.assign(instanceNormal); 9009 } 9010 if (this.instanceColorNode !== null) { 9011 varyingProperty("vec3", "vInstanceColor").assign(this.instanceColorNode); 9012 } 9013 } 9014 /** 9015 * Checks if the internal buffers require an update. 9016 * 9017 * @param {NodeFrame} frame - The current node frame. 9018 */ 9019 update(frame) { 9020 if (this.buffer !== null && this.isStorageMatrix !== true) { 9021 this.buffer.clearUpdateRanges(); 9022 this.buffer.updateRanges.push(...this.instanceMatrix.updateRanges); 9023 if (this.instanceMatrix.version !== this.buffer.version) { 9024 this.buffer.version = this.instanceMatrix.version; 9025 } 9026 } 9027 if (this.instanceColor && this.bufferColor !== null && this.isStorageColor !== true) { 9028 this.bufferColor.clearUpdateRanges(); 9029 this.bufferColor.updateRanges.push(...this.instanceColor.updateRanges); 9030 if (this.instanceColor.version !== this.bufferColor.version) { 9031 this.bufferColor.version = this.instanceColor.version; 9032 } 9033 } 9034 if (this.previousInstanceMatrixNode !== null) { 9035 frame.object.previousInstanceMatrix.array.set(this.instanceMatrix.array); 9036 } 9037 } 9038 /** 9039 * Computes the transformed/instanced vertex position of the previous frame. 9040 * 9041 * @param {NodeBuilder} builder - The current node builder. 9042 * @return {Node<vec3>} The instanced position from the previous frame. 9043 */ 9044 getPreviousInstancedPosition(builder) { 9045 const instancedMesh3 = builder.object; 9046 if (this.previousInstanceMatrixNode === null) { 9047 instancedMesh3.previousInstanceMatrix = this.instanceMatrix.clone(); 9048 this.previousInstanceMatrixNode = this._createInstanceMatrixNode(false, builder); 9049 } 9050 return this.previousInstanceMatrixNode.mul(positionPrevious).xyz; 9051 } 9052 /** 9053 * Creates a node representing the instance matrix data. 9054 * 9055 * @private 9056 * @param {boolean} assignBuffer - Whether the created interleaved buffer should be assigned to the `buffer` member or not. 9057 * @param {NodeBuilder} builder - A reference to the current node builder. 9058 * @return {Node} The instance matrix node. 9059 */ 9060 _createInstanceMatrixNode(assignBuffer, builder) { 9061 let instanceMatrixNode; 9062 const { instanceMatrix } = this; 9063 const { count } = instanceMatrix; 9064 if (this.isStorageMatrix) { 9065 instanceMatrixNode = storage(instanceMatrix, "mat4", Math.max(count, 1)).element(instanceIndex); 9066 } else { 9067 const uniformBufferSize = count * 16 * 4; 9068 if (uniformBufferSize <= builder.getUniformBufferLimit()) { 9069 instanceMatrixNode = buffer(instanceMatrix.array, "mat4", Math.max(count, 1)).element(instanceIndex); 9070 } else { 9071 const interleaved = new InstancedInterleavedBuffer(instanceMatrix.array, 16, 1); 9072 if (assignBuffer === true) this.buffer = interleaved; 9073 const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute; 9074 const instanceBuffers = [ 9075 bufferFn(interleaved, "vec4", 16, 0), 9076 bufferFn(interleaved, "vec4", 16, 4), 9077 bufferFn(interleaved, "vec4", 16, 8), 9078 bufferFn(interleaved, "vec4", 16, 12) 9079 ]; 9080 instanceMatrixNode = mat4(...instanceBuffers); 9081 } 9082 } 9083 return instanceMatrixNode; 9084 } 9085}; 9086var instance = /* @__PURE__ */ nodeProxy(InstanceNode).setParameterLength(2, 3); 9087var InstancedMeshNode = class extends InstanceNode { 9088 static get type() { 9089 return "InstancedMeshNode"; 9090 } 9091 /** 9092 * Constructs a new instanced mesh node. 9093 * 9094 * @param {InstancedMesh} instancedMesh - The instanced mesh. 9095 */ 9096 constructor(instancedMesh3) { 9097 const { count, instanceMatrix, instanceColor } = instancedMesh3; 9098 super(count, instanceMatrix, instanceColor); 9099 this.instancedMesh = instancedMesh3; 9100 } 9101}; 9102var instancedMesh = /* @__PURE__ */ nodeProxy(InstancedMeshNode).setParameterLength(1); 9103var BatchNode = class extends Node2 { 9104 static get type() { 9105 return "BatchNode"; 9106 } 9107 /** 9108 * Constructs a new batch node. 9109 * 9110 * @param {BatchedMesh} batchMesh - A reference to batched mesh. 9111 */ 9112 constructor(batchMesh) { 9113 super("void"); 9114 this.batchMesh = batchMesh; 9115 this.batchingIdNode = null; 9116 } 9117 /** 9118 * Setups the internal buffers and nodes and assigns the transformed vertex data 9119 * to predefined node variables for accumulation. That follows the same patterns 9120 * like with morph and skinning nodes. 9121 * 9122 * @param {NodeBuilder} builder - The current node builder. 9123 */ 9124 setup(builder) { 9125 if (this.batchingIdNode === null) { 9126 if (builder.getDrawIndex() === null) { 9127 this.batchingIdNode = instanceIndex; 9128 } else { 9129 this.batchingIdNode = drawIndex; 9130 } 9131 } 9132 const getIndirectIndex = Fn(([id]) => { 9133 const size4 = int(textureSize(textureLoad(this.batchMesh._indirectTexture), 0).x).toConst(); 9134 const x2 = int(id).mod(size4).toConst(); 9135 const y2 = int(id).div(size4).toConst(); 9136 return textureLoad(this.batchMesh._indirectTexture, ivec2(x2, y2)).x; 9137 }).setLayout({ 9138 name: "getIndirectIndex", 9139 type: "uint", 9140 inputs: [ 9141 { name: "id", type: "int" } 9142 ] 9143 }); 9144 const indirectId = getIndirectIndex(int(this.batchingIdNode)); 9145 const matricesTexture = this.batchMesh._matricesTexture; 9146 const size3 = int(textureSize(textureLoad(matricesTexture), 0).x).toConst(); 9147 const j = float(indirectId).mul(4).toInt().toConst(); 9148 const x = j.mod(size3).toConst(); 9149 const y = j.div(size3).toConst(); 9150 const batchingMatrix = mat4( 9151 textureLoad(matricesTexture, ivec2(x, y)), 9152 textureLoad(matricesTexture, ivec2(x.add(1), y)), 9153 textureLoad(matricesTexture, ivec2(x.add(2), y)), 9154 textureLoad(matricesTexture, ivec2(x.add(3), y)) 9155 ); 9156 const colorsTexture = this.batchMesh._colorsTexture; 9157 if (colorsTexture !== null) { 9158 const getBatchingColor = Fn(([id]) => { 9159 const size4 = int(textureSize(textureLoad(colorsTexture), 0).x).toConst(); 9160 const j2 = id; 9161 const x2 = j2.mod(size4).toConst(); 9162 const y2 = j2.div(size4).toConst(); 9163 return textureLoad(colorsTexture, ivec2(x2, y2)).rgb; 9164 }).setLayout({ 9165 name: "getBatchingColor", 9166 type: "vec3", 9167 inputs: [ 9168 { name: "id", type: "int" } 9169 ] 9170 }); 9171 const color3 = getBatchingColor(indirectId); 9172 varyingProperty("vec3", "vBatchColor").assign(color3); 9173 } 9174 const bm = mat3(batchingMatrix); 9175 positionLocal.assign(batchingMatrix.mul(positionLocal)); 9176 const transformedNormal = normalLocal.div(vec3(bm[0].dot(bm[0]), bm[1].dot(bm[1]), bm[2].dot(bm[2]))); 9177 const batchingNormal = bm.mul(transformedNormal).xyz; 9178 normalLocal.assign(batchingNormal); 9179 if (builder.hasGeometryAttribute("tangent")) { 9180 tangentLocal.mulAssign(bm); 9181 } 9182 } 9183}; 9184var batch2 = /* @__PURE__ */ nodeProxy(BatchNode).setParameterLength(1); 9185var _frameId = /* @__PURE__ */ new WeakMap(); 9186var SkinningNode = class extends Node2 { 9187 static get type() { 9188 return "SkinningNode"; 9189 } 9190 /** 9191 * Constructs a new skinning node. 9192 * 9193 * @param {SkinnedMesh} skinnedMesh - The skinned mesh. 9194 */ 9195 constructor(skinnedMesh) { 9196 super("void"); 9197 this.skinnedMesh = skinnedMesh; 9198 this.updateType = NodeUpdateType.OBJECT; 9199 this.skinIndexNode = attribute("skinIndex", "uvec4"); 9200 this.skinWeightNode = attribute("skinWeight", "vec4"); 9201 this.bindMatrixNode = reference("bindMatrix", "mat4"); 9202 this.bindMatrixInverseNode = reference("bindMatrixInverse", "mat4"); 9203 this.boneMatricesNode = referenceBuffer("skeleton.boneMatrices", "mat4", skinnedMesh.skeleton.bones.length); 9204 this.positionNode = positionLocal; 9205 this.toPositionNode = positionLocal; 9206 this.previousBoneMatricesNode = null; 9207 } 9208 /** 9209 * Transforms the given vertex position via skinning. 9210 * 9211 * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices 9212 * @param {Node<vec3>} [position=this.positionNode] - The vertex position in local space. 9213 * @return {Node<vec3>} The transformed vertex position. 9214 */ 9215 getSkinnedPosition(boneMatrices = this.boneMatricesNode, position = this.positionNode) { 9216 const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; 9217 const boneMatX = boneMatrices.element(skinIndexNode.x); 9218 const boneMatY = boneMatrices.element(skinIndexNode.y); 9219 const boneMatZ = boneMatrices.element(skinIndexNode.z); 9220 const boneMatW = boneMatrices.element(skinIndexNode.w); 9221 const skinVertex = bindMatrixNode.mul(position); 9222 const skinned = add( 9223 boneMatX.mul(skinWeightNode.x).mul(skinVertex), 9224 boneMatY.mul(skinWeightNode.y).mul(skinVertex), 9225 boneMatZ.mul(skinWeightNode.z).mul(skinVertex), 9226 boneMatW.mul(skinWeightNode.w).mul(skinVertex) 9227 ); 9228 return bindMatrixInverseNode.mul(skinned).xyz; 9229 } 9230 /** 9231 * Transforms the given vertex normal and tangent via skinning. 9232 * 9233 * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices 9234 * @param {Node<vec3>} [normal=normalLocal] - The vertex normal in local space. 9235 * @param {Node<vec3>} [tangent=tangentLocal] - The vertex tangent in local space. 9236 * @return {{skinNormal: Node<vec3>, skinTangent:Node<vec3>}} The transformed vertex normal and tangent. 9237 */ 9238 getSkinnedNormalAndTangent(boneMatrices = this.boneMatricesNode, normal2 = normalLocal, tangent = tangentLocal) { 9239 const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; 9240 const boneMatX = boneMatrices.element(skinIndexNode.x); 9241 const boneMatY = boneMatrices.element(skinIndexNode.y); 9242 const boneMatZ = boneMatrices.element(skinIndexNode.z); 9243 const boneMatW = boneMatrices.element(skinIndexNode.w); 9244 let skinMatrix = add( 9245 skinWeightNode.x.mul(boneMatX), 9246 skinWeightNode.y.mul(boneMatY), 9247 skinWeightNode.z.mul(boneMatZ), 9248 skinWeightNode.w.mul(boneMatW) 9249 ); 9250 skinMatrix = bindMatrixInverseNode.mul(skinMatrix).mul(bindMatrixNode); 9251 const skinNormal = skinMatrix.transformDirection(normal2).xyz; 9252 const skinTangent = skinMatrix.transformDirection(tangent).xyz; 9253 return { skinNormal, skinTangent }; 9254 } 9255 /** 9256 * Computes the transformed/skinned vertex position of the previous frame. 9257 * 9258 * @param {NodeBuilder} builder - The current node builder. 9259 * @return {Node<vec3>} The skinned position from the previous frame. 9260 */ 9261 getPreviousSkinnedPosition(builder) { 9262 const skinnedMesh = builder.object; 9263 if (this.previousBoneMatricesNode === null) { 9264 skinnedMesh.skeleton.previousBoneMatrices = new Float32Array(skinnedMesh.skeleton.boneMatrices); 9265 this.previousBoneMatricesNode = referenceBuffer("skeleton.previousBoneMatrices", "mat4", skinnedMesh.skeleton.bones.length); 9266 } 9267 return this.getSkinnedPosition(this.previousBoneMatricesNode, positionPrevious); 9268 } 9269 /** 9270 * Setups the skinning node by assigning the transformed vertex data to predefined node variables. 9271 * 9272 * @param {NodeBuilder} builder - The current node builder. 9273 * @return {Node<vec3>} The transformed vertex position. 9274 */ 9275 setup(builder) { 9276 if (builder.needsPreviousData()) { 9277 positionPrevious.assign(this.getPreviousSkinnedPosition(builder)); 9278 } 9279 const skinPosition = this.getSkinnedPosition(); 9280 if (this.toPositionNode) this.toPositionNode.assign(skinPosition); 9281 if (builder.hasGeometryAttribute("normal")) { 9282 const { skinNormal, skinTangent } = this.getSkinnedNormalAndTangent(); 9283 normalLocal.assign(skinNormal); 9284 if (builder.hasGeometryAttribute("tangent")) { 9285 tangentLocal.assign(skinTangent); 9286 } 9287 } 9288 return skinPosition; 9289 } 9290 /** 9291 * Generates the code snippet of the skinning node. 9292 * 9293 * @param {NodeBuilder} builder - The current node builder. 9294 * @param {string} output - The current output. 9295 * @return {string} The generated code snippet. 9296 */ 9297 generate(builder, output3) { 9298 if (output3 !== "void") { 9299 return super.generate(builder, output3); 9300 } 9301 } 9302 /** 9303 * Updates the state of the skinned mesh by updating the skeleton once per frame. 9304 * 9305 * @param {NodeFrame} frame - The current node frame. 9306 */ 9307 update(frame) { 9308 const skeleton = frame.object && frame.object.skeleton ? frame.object.skeleton : this.skinnedMesh.skeleton; 9309 if (_frameId.get(skeleton) === frame.frameId) return; 9310 _frameId.set(skeleton, frame.frameId); 9311 if (this.previousBoneMatricesNode !== null) { 9312 if (skeleton.previousBoneMatrices === null) { 9313 skeleton.previousBoneMatrices = new Float32Array(skeleton.boneMatrices); 9314 } 9315 skeleton.previousBoneMatrices.set(skeleton.boneMatrices); 9316 } 9317 skeleton.update(); 9318 } 9319}; 9320var skinning = (skinnedMesh) => new SkinningNode(skinnedMesh); 9321var computeSkinning = (skinnedMesh, toPosition = null) => { 9322 const node = new SkinningNode(skinnedMesh); 9323 node.positionNode = storage(new InstancedBufferAttribute(skinnedMesh.geometry.getAttribute("position").array, 3), "vec3").setPBO(true).toReadOnly().element(instanceIndex).toVar(); 9324 node.skinIndexNode = storage(new InstancedBufferAttribute(new Uint32Array(skinnedMesh.geometry.getAttribute("skinIndex").array), 4), "uvec4").setPBO(true).toReadOnly().element(instanceIndex).toVar(); 9325 node.skinWeightNode = storage(new InstancedBufferAttribute(skinnedMesh.geometry.getAttribute("skinWeight").array, 4), "vec4").setPBO(true).toReadOnly().element(instanceIndex).toVar(); 9326 node.bindMatrixNode = uniform(skinnedMesh.bindMatrix, "mat4"); 9327 node.bindMatrixInverseNode = uniform(skinnedMesh.bindMatrixInverse, "mat4"); 9328 node.boneMatricesNode = buffer(skinnedMesh.skeleton.boneMatrices, "mat4", skinnedMesh.skeleton.bones.length); 9329 node.toPositionNode = toPosition; 9330 return nodeObject(node); 9331}; 9332var LoopNode = class extends Node2 { 9333 static get type() { 9334 return "LoopNode"; 9335 } 9336 /** 9337 * Constructs a new loop node. 9338 * 9339 * @param {Array<any>} params - Depending on the loop type, array holds different parameterization values for the loop. 9340 */ 9341 constructor(params = []) { 9342 super("void"); 9343 this.params = params; 9344 } 9345 /** 9346 * Returns a loop variable name based on an index. The pattern is 9347 * `0` = `i`, `1`= `j`, `2`= `k` and so on. 9348 * 9349 * @param {number} index - The index. 9350 * @return {string} The loop variable name. 9351 */ 9352 getVarName(index) { 9353 return String.fromCharCode("i".charCodeAt(0) + index); 9354 } 9355 /** 9356 * Returns properties about this node. 9357 * 9358 * @param {NodeBuilder} builder - The current node builder. 9359 * @return {Object} The node properties. 9360 */ 9361 getProperties(builder) { 9362 const properties = builder.getNodeProperties(this); 9363 if (properties.stackNode !== void 0) return properties; 9364 const inputs = {}; 9365 for (let i = 0, l = this.params.length - 1; i < l; i++) { 9366 const param = this.params[i]; 9367 const name = param.isNode !== true && param.name || this.getVarName(i); 9368 const type = param.isNode !== true && param.type || "int"; 9369 inputs[name] = expression(name, type); 9370 } 9371 const stack3 = builder.addStack(); 9372 const fnCall = this.params[this.params.length - 1](inputs); 9373 properties.returnsNode = fnCall.context({ nodeLoop: fnCall }); 9374 properties.stackNode = stack3; 9375 const baseParam = this.params[0]; 9376 if (baseParam.isNode !== true && typeof baseParam.update === "function") { 9377 const fnUpdateCall = Fn(this.params[0].update)(inputs); 9378 properties.updateNode = fnUpdateCall.context({ nodeLoop: fnUpdateCall }); 9379 } 9380 builder.removeStack(); 9381 return properties; 9382 } 9383 setup(builder) { 9384 this.getProperties(builder); 9385 if (builder.fnCall) { 9386 const shaderNodeData = builder.getDataFromNode(builder.fnCall.shaderNode); 9387 shaderNodeData.hasLoop = true; 9388 } 9389 } 9390 generate(builder) { 9391 const properties = this.getProperties(builder); 9392 const params = this.params; 9393 const stackNode = properties.stackNode; 9394 for (let i = 0, l = params.length - 1; i < l; i++) { 9395 const param = params[i]; 9396 let isWhile = false, start = null, end = null, name = null, type = null, condition = null, update = null; 9397 if (param.isNode) { 9398 if (param.getNodeType(builder) === "bool") { 9399 isWhile = true; 9400 type = "bool"; 9401 end = param.build(builder, type); 9402 } else { 9403 type = "int"; 9404 name = this.getVarName(i); 9405 start = "0"; 9406 end = param.build(builder, type); 9407 condition = "<"; 9408 } 9409 } else { 9410 type = param.type || "int"; 9411 name = param.name || this.getVarName(i); 9412 start = param.start; 9413 end = param.end; 9414 condition = param.condition; 9415 update = param.update; 9416 if (typeof start === "number") start = builder.generateConst(type, start); 9417 else if (start && start.isNode) start = start.build(builder, type); 9418 if (typeof end === "number") end = builder.generateConst(type, end); 9419 else if (end && end.isNode) end = end.build(builder, type); 9420 if (start !== void 0 && end === void 0) { 9421 start = start + " - 1"; 9422 end = "0"; 9423 condition = ">="; 9424 } else if (end !== void 0 && start === void 0) { 9425 start = "0"; 9426 condition = "<"; 9427 } 9428 if (condition === void 0) { 9429 if (Number(start) > Number(end)) { 9430 condition = ">="; 9431 } else { 9432 condition = "<"; 9433 } 9434 } 9435 } 9436 let loopSnippet; 9437 if (isWhile) { 9438 loopSnippet = `while ( ${end} )`; 9439 } else { 9440 const internalParam = { start, end }; 9441 const startSnippet = internalParam.start; 9442 const endSnippet = internalParam.end; 9443 let updateSnippet; 9444 const deltaOperator = () => condition.includes("<") ? "+=" : "-="; 9445 if (update !== void 0 && update !== null) { 9446 switch (typeof update) { 9447 case "function": 9448 const flow = builder.flowStagesNode(properties.updateNode, "void"); 9449 const snippet = flow.code.replace(/\t|;/g, ""); 9450 updateSnippet = snippet; 9451 break; 9452 case "number": 9453 updateSnippet = name + " " + deltaOperator() + " " + builder.generateConst(type, update); 9454 break; 9455 case "string": 9456 updateSnippet = name + " " + update; 9457 break; 9458 default: 9459 if (update.isNode) { 9460 updateSnippet = name + " " + deltaOperator() + " " + update.build(builder); 9461 } else { 9462 error("TSL: 'Loop( { update: ... } )' is not a function, string or number.", this.stackTrace); 9463 updateSnippet = "break /* invalid update */"; 9464 } 9465 } 9466 } else { 9467 if (type === "int" || type === "uint") { 9468 update = condition.includes("<") ? "++" : "--"; 9469 } else { 9470 update = deltaOperator() + " 1."; 9471 } 9472 updateSnippet = name + " " + update; 9473 } 9474 const declarationSnippet = builder.getVar(type, name) + " = " + startSnippet; 9475 const conditionalSnippet = name + " " + condition + " " + endSnippet; 9476 loopSnippet = `for ( ${declarationSnippet}; ${conditionalSnippet}; ${updateSnippet} )`; 9477 } 9478 builder.addFlowCode((i === 0 ? "\n" : "") + builder.tab + loopSnippet + " {\n\n").addFlowTab(); 9479 } 9480 const stackSnippet = stackNode.build(builder, "void"); 9481 properties.returnsNode.build(builder, "void"); 9482 builder.removeFlowTab().addFlowCode("\n" + builder.tab + stackSnippet); 9483 for (let i = 0, l = this.params.length - 1; i < l; i++) { 9484 builder.addFlowCode((i === 0 ? "" : builder.tab) + "}\n\n").removeFlowTab(); 9485 } 9486 builder.addFlowTab(); 9487 } 9488}; 9489var Loop = (...params) => new LoopNode(nodeArray(params, "int")).toStack(); 9490var Continue = () => expression("continue").toStack(); 9491var Break = () => expression("break").toStack(); 9492var _morphTextures = /* @__PURE__ */ new WeakMap(); 9493var _morphVec4 = /* @__PURE__ */ new Vector4(); 9494var getMorph = /* @__PURE__ */ Fn(({ bufferMap, influence, stride, width, depth: depth3, offset: offset3 }) => { 9495 const texelIndex = int(vertexIndex).mul(stride).add(offset3); 9496 const y = texelIndex.div(width); 9497 const x = texelIndex.sub(y.mul(width)); 9498 const bufferAttrib = textureLoad(bufferMap, ivec2(x, y)).depth(depth3).xyz; 9499 return bufferAttrib.mul(influence); 9500}); 9501function getEntry(geometry) { 9502 const hasMorphPosition = geometry.morphAttributes.position !== void 0; 9503 const hasMorphNormals = geometry.morphAttributes.normal !== void 0; 9504 const hasMorphColors = geometry.morphAttributes.color !== void 0; 9505 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 9506 const morphTargetsCount = morphAttribute !== void 0 ? morphAttribute.length : 0; 9507 let entry = _morphTextures.get(geometry); 9508 if (entry === void 0 || entry.count !== morphTargetsCount) { 9509 let disposeTexture = function() { 9510 bufferTexture.dispose(); 9511 _morphTextures.delete(geometry); 9512 geometry.removeEventListener("dispose", disposeTexture); 9513 }; 9514 if (entry !== void 0) entry.texture.dispose(); 9515 const morphTargets = geometry.morphAttributes.position || []; 9516 const morphNormals = geometry.morphAttributes.normal || []; 9517 const morphColors = geometry.morphAttributes.color || []; 9518 let vertexDataCount = 0; 9519 if (hasMorphPosition === true) vertexDataCount = 1; 9520 if (hasMorphNormals === true) vertexDataCount = 2; 9521 if (hasMorphColors === true) vertexDataCount = 3; 9522 let width = geometry.attributes.position.count * vertexDataCount; 9523 let height = 1; 9524 const maxTextureSize = 4096; 9525 if (width > maxTextureSize) { 9526 height = Math.ceil(width / maxTextureSize); 9527 width = maxTextureSize; 9528 } 9529 const buffer3 = new Float32Array(width * height * 4 * morphTargetsCount); 9530 const bufferTexture = new DataArrayTexture(buffer3, width, height, morphTargetsCount); 9531 bufferTexture.type = FloatType; 9532 bufferTexture.needsUpdate = true; 9533 const vertexDataStride = vertexDataCount * 4; 9534 for (let i = 0; i < morphTargetsCount; i++) { 9535 const morphTarget = morphTargets[i]; 9536 const morphNormal = morphNormals[i]; 9537 const morphColor = morphColors[i]; 9538 const offset3 = width * height * 4 * i; 9539 for (let j = 0; j < morphTarget.count; j++) { 9540 const stride = j * vertexDataStride; 9541 if (hasMorphPosition === true) { 9542 _morphVec4.fromBufferAttribute(morphTarget, j); 9543 buffer3[offset3 + stride + 0] = _morphVec4.x; 9544 buffer3[offset3 + stride + 1] = _morphVec4.y; 9545 buffer3[offset3 + stride + 2] = _morphVec4.z; 9546 buffer3[offset3 + stride + 3] = 0; 9547 } 9548 if (hasMorphNormals === true) { 9549 _morphVec4.fromBufferAttribute(morphNormal, j); 9550 buffer3[offset3 + stride + 4] = _morphVec4.x; 9551 buffer3[offset3 + stride + 5] = _morphVec4.y; 9552 buffer3[offset3 + stride + 6] = _morphVec4.z; 9553 buffer3[offset3 + stride + 7] = 0; 9554 } 9555 if (hasMorphColors === true) { 9556 _morphVec4.fromBufferAttribute(morphColor, j); 9557 buffer3[offset3 + stride + 8] = _morphVec4.x; 9558 buffer3[offset3 + stride + 9] = _morphVec4.y; 9559 buffer3[offset3 + stride + 10] = _morphVec4.z; 9560 buffer3[offset3 + stride + 11] = morphColor.itemSize === 4 ? _morphVec4.w : 1; 9561 } 9562 } 9563 } 9564 entry = { 9565 count: morphTargetsCount, 9566 texture: bufferTexture, 9567 stride: vertexDataCount, 9568 size: new Vector2(width, height) 9569 }; 9570 _morphTextures.set(geometry, entry); 9571 geometry.addEventListener("dispose", disposeTexture); 9572 } 9573 return entry; 9574} 9575var MorphNode = class extends Node2 { 9576 static get type() { 9577 return "MorphNode"; 9578 } 9579 /** 9580 * Constructs a new morph node. 9581 * 9582 * @param {Mesh} mesh - The mesh holding the morph targets. 9583 */ 9584 constructor(mesh) { 9585 super("void"); 9586 this.mesh = mesh; 9587 this.morphBaseInfluence = uniform(1); 9588 this.updateType = NodeUpdateType.OBJECT; 9589 } 9590 /** 9591 * Setups the morph node by assigning the transformed vertex data to predefined node variables. 9592 * 9593 * @param {NodeBuilder} builder - The current node builder. 9594 */ 9595 setup(builder) { 9596 const { geometry } = builder; 9597 const hasMorphPosition = geometry.morphAttributes.position !== void 0; 9598 const hasMorphNormals = geometry.hasAttribute("normal") && geometry.morphAttributes.normal !== void 0; 9599 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 9600 const morphTargetsCount = morphAttribute !== void 0 ? morphAttribute.length : 0; 9601 const { texture: bufferMap, stride, size: size3 } = getEntry(geometry); 9602 if (hasMorphPosition === true) positionLocal.mulAssign(this.morphBaseInfluence); 9603 if (hasMorphNormals === true) normalLocal.mulAssign(this.morphBaseInfluence); 9604 const width = int(size3.width); 9605 Loop(morphTargetsCount, ({ i }) => { 9606 const influence = float(0).toVar(); 9607 if (this.mesh.count > 1 && (this.mesh.morphTexture !== null && this.mesh.morphTexture !== void 0)) { 9608 influence.assign(textureLoad(this.mesh.morphTexture, ivec2(int(i).add(1), int(instanceIndex))).r); 9609 } else { 9610 influence.assign(reference("morphTargetInfluences", "float").element(i).toVar()); 9611 } 9612 If(influence.notEqual(0), () => { 9613 if (hasMorphPosition === true) { 9614 positionLocal.addAssign(getMorph({ 9615 bufferMap, 9616 influence, 9617 stride, 9618 width, 9619 depth: i, 9620 offset: int(0) 9621 })); 9622 } 9623 if (hasMorphNormals === true) { 9624 normalLocal.addAssign(getMorph({ 9625 bufferMap, 9626 influence, 9627 stride, 9628 width, 9629 depth: i, 9630 offset: int(1) 9631 })); 9632 } 9633 }); 9634 }); 9635 } 9636 /** 9637 * Updates the state of the morphed mesh by updating the base influence. 9638 * 9639 * @param {NodeFrame} frame - The current node frame. 9640 */ 9641 update() { 9642 const morphBaseInfluence = this.morphBaseInfluence; 9643 if (this.mesh.geometry.morphTargetsRelative) { 9644 morphBaseInfluence.value = 1; 9645 } else { 9646 morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce((a, b) => a + b, 0); 9647 } 9648 } 9649}; 9650var morphReference = /* @__PURE__ */ nodeProxy(MorphNode).setParameterLength(1); 9651var LightingNode = class extends Node2 { 9652 static get type() { 9653 return "LightingNode"; 9654 } 9655 /** 9656 * Constructs a new lighting node. 9657 */ 9658 constructor() { 9659 super("vec3"); 9660 this.isLightingNode = true; 9661 } 9662}; 9663var AONode = class extends LightingNode { 9664 static get type() { 9665 return "AONode"; 9666 } 9667 /** 9668 * Constructs a new AO node. 9669 * 9670 * @param {?Node<float>} [aoNode=null] - The ambient occlusion node. 9671 */ 9672 constructor(aoNode = null) { 9673 super(); 9674 this.aoNode = aoNode; 9675 } 9676 setup(builder) { 9677 builder.context.ambientOcclusion.mulAssign(this.aoNode); 9678 } 9679}; 9680var LightingContextNode = class extends ContextNode { 9681 static get type() { 9682 return "LightingContextNode"; 9683 } 9684 /** 9685 * Constructs a new lighting context node. 9686 * 9687 * @param {LightsNode} lightsNode - The lights node. 9688 * @param {?LightingModel} [lightingModel=null] - The current lighting model. 9689 * @param {?Node<vec3>} [backdropNode=null] - A backdrop node. 9690 * @param {?Node<float>} [backdropAlphaNode=null] - A backdrop alpha node. 9691 */ 9692 constructor(lightsNode, lightingModel = null, backdropNode = null, backdropAlphaNode = null) { 9693 super(lightsNode); 9694 this.lightingModel = lightingModel; 9695 this.backdropNode = backdropNode; 9696 this.backdropAlphaNode = backdropAlphaNode; 9697 this._value = null; 9698 } 9699 /** 9700 * Returns a lighting context object. 9701 * 9702 * @return {{ 9703 * radiance: Node<vec3>, 9704 * irradiance: Node<vec3>, 9705 * iblIrradiance: Node<vec3>, 9706 * ambientOcclusion: Node<float>, 9707 * reflectedLight: {directDiffuse: Node<vec3>, directSpecular: Node<vec3>, indirectDiffuse: Node<vec3>, indirectSpecular: Node<vec3>}, 9708 * backdrop: Node<vec3>, 9709 * backdropAlpha: Node<float> 9710 * }} The lighting context object. 9711 */ 9712 getContext() { 9713 const { backdropNode, backdropAlphaNode } = this; 9714 const directDiffuse = vec3().toVar("directDiffuse"), directSpecular = vec3().toVar("directSpecular"), indirectDiffuse = vec3().toVar("indirectDiffuse"), indirectSpecular = vec3().toVar("indirectSpecular"); 9715 const reflectedLight = { 9716 directDiffuse, 9717 directSpecular, 9718 indirectDiffuse, 9719 indirectSpecular 9720 }; 9721 const context3 = { 9722 radiance: vec3().toVar("radiance"), 9723 irradiance: vec3().toVar("irradiance"), 9724 iblIrradiance: vec3().toVar("iblIrradiance"), 9725 ambientOcclusion: float(1).toVar("ambientOcclusion"), 9726 reflectedLight, 9727 backdrop: backdropNode, 9728 backdropAlpha: backdropAlphaNode 9729 }; 9730 return context3; 9731 } 9732 setup(builder) { 9733 this.value = this._value || (this._value = this.getContext()); 9734 this.value.lightingModel = this.lightingModel || builder.context.lightingModel; 9735 return super.setup(builder); 9736 } 9737}; 9738var lightingContext = /* @__PURE__ */ nodeProxy(LightingContextNode); 9739var IrradianceNode = class extends LightingNode { 9740 static get type() { 9741 return "IrradianceNode"; 9742 } 9743 /** 9744 * Constructs a new irradiance node. 9745 * 9746 * @param {Node<vec3>} node - A node contributing irradiance. 9747 */ 9748 constructor(node) { 9749 super(); 9750 this.node = node; 9751 } 9752 setup(builder) { 9753 builder.context.irradiance.addAssign(this.node); 9754 } 9755}; 9756var _size$5 = /* @__PURE__ */ new Vector2(); 9757var ViewportTextureNode = class extends TextureNode { 9758 static get type() { 9759 return "ViewportTextureNode"; 9760 } 9761 /** 9762 * Constructs a new viewport texture node. 9763 * 9764 * @param {Node} [uvNode=screenUV] - The uv node. 9765 * @param {?Node} [levelNode=null] - The level node. 9766 * @param {?Texture} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. 9767 */ 9768 constructor(uvNode = screenUV, levelNode = null, framebufferTexture = null) { 9769 let defaultFramebuffer = null; 9770 if (framebufferTexture === null) { 9771 defaultFramebuffer = new FramebufferTexture(); 9772 defaultFramebuffer.minFilter = LinearMipmapLinearFilter; 9773 framebufferTexture = defaultFramebuffer; 9774 } else { 9775 defaultFramebuffer = framebufferTexture; 9776 } 9777 super(framebufferTexture, uvNode, levelNode); 9778 this.generateMipmaps = false; 9779 this.defaultFramebuffer = defaultFramebuffer; 9780 this.isOutputTextureNode = true; 9781 this.updateBeforeType = NodeUpdateType.RENDER; 9782 this._cacheTextures = /* @__PURE__ */ new WeakMap(); 9783 } 9784 /** 9785 * This methods returns a texture for the given render target or canvas target reference. 9786 * 9787 * To avoid rendering errors, `ViewportTextureNode` must use unique framebuffer textures 9788 * for different render contexts. 9789 * 9790 * @param {?(RenderTarget|CanvasTarget)} [reference=null] - The render target or canvas target reference. 9791 * @return {Texture} The framebuffer texture. 9792 */ 9793 getTextureForReference(reference3 = null) { 9794 let defaultFramebuffer; 9795 let cacheTextures; 9796 if (this.referenceNode) { 9797 defaultFramebuffer = this.referenceNode.defaultFramebuffer; 9798 cacheTextures = this.referenceNode._cacheTextures; 9799 } else { 9800 defaultFramebuffer = this.defaultFramebuffer; 9801 cacheTextures = this._cacheTextures; 9802 } 9803 if (reference3 === null) { 9804 return defaultFramebuffer; 9805 } 9806 if (cacheTextures.has(reference3) === false) { 9807 const framebufferTexture = defaultFramebuffer.clone(); 9808 cacheTextures.set(reference3, framebufferTexture); 9809 } 9810 return cacheTextures.get(reference3); 9811 } 9812 updateReference(frame) { 9813 const renderer = frame.renderer; 9814 const renderTarget = renderer.getRenderTarget(); 9815 const canvasTarget = renderer.getCanvasTarget(); 9816 const reference3 = renderTarget ? renderTarget : canvasTarget; 9817 this.value = this.getTextureForReference(reference3); 9818 return this.value; 9819 } 9820 updateBefore(frame) { 9821 const renderer = frame.renderer; 9822 const renderTarget = renderer.getRenderTarget(); 9823 const canvasTarget = renderer.getCanvasTarget(); 9824 const reference3 = renderTarget ? renderTarget : canvasTarget; 9825 if (reference3 === null) { 9826 renderer.getDrawingBufferSize(_size$5); 9827 } else if (reference3.getDrawingBufferSize) { 9828 reference3.getDrawingBufferSize(_size$5); 9829 } else { 9830 _size$5.set(reference3.width, reference3.height); 9831 } 9832 const framebufferTexture = this.getTextureForReference(reference3); 9833 if (framebufferTexture.image.width !== _size$5.width || framebufferTexture.image.height !== _size$5.height) { 9834 framebufferTexture.image.width = _size$5.width; 9835 framebufferTexture.image.height = _size$5.height; 9836 framebufferTexture.needsUpdate = true; 9837 } 9838 const currentGenerateMipmaps = framebufferTexture.generateMipmaps; 9839 framebufferTexture.generateMipmaps = this.generateMipmaps; 9840 renderer.copyFramebufferToTexture(framebufferTexture); 9841 framebufferTexture.generateMipmaps = currentGenerateMipmaps; 9842 } 9843 clone() { 9844 const viewportTextureNode = new this.constructor(this.uvNode, this.levelNode, this.value); 9845 viewportTextureNode.generateMipmaps = this.generateMipmaps; 9846 return viewportTextureNode; 9847 } 9848}; 9849var viewportTexture = /* @__PURE__ */ nodeProxy(ViewportTextureNode).setParameterLength(0, 3); 9850var viewportMipTexture = /* @__PURE__ */ nodeProxy(ViewportTextureNode, null, null, { generateMipmaps: true }).setParameterLength(0, 3); 9851var _singletonOpaqueViewportTextureNode = /* @__PURE__ */ viewportMipTexture(); 9852var viewportOpaqueMipTexture = (uv3 = screenUV, level = null) => _singletonOpaqueViewportTextureNode.sample(uv3, level); 9853var _sharedDepthbuffer = null; 9854var ViewportDepthTextureNode = class extends ViewportTextureNode { 9855 static get type() { 9856 return "ViewportDepthTextureNode"; 9857 } 9858 /** 9859 * Constructs a new viewport depth texture node. 9860 * 9861 * @param {Node} [uvNode=screenUV] - The uv node. 9862 * @param {?Node} [levelNode=null] - The level node. 9863 * @param {?DepthTexture} [depthTexture=null] - A depth texture. If not provided, uses a shared depth texture. 9864 */ 9865 constructor(uvNode = screenUV, levelNode = null, depthTexture = null) { 9866 if (depthTexture === null) { 9867 if (_sharedDepthbuffer === null) { 9868 _sharedDepthbuffer = new DepthTexture(); 9869 } 9870 depthTexture = _sharedDepthbuffer; 9871 } 9872 super(uvNode, levelNode, depthTexture); 9873 } 9874}; 9875var viewportDepthTexture = /* @__PURE__ */ nodeProxy(ViewportDepthTextureNode).setParameterLength(0, 3); 9876var ViewportDepthNode = class _ViewportDepthNode extends Node2 { 9877 static get type() { 9878 return "ViewportDepthNode"; 9879 } 9880 /** 9881 * Constructs a new viewport depth node. 9882 * 9883 * @param {('depth'|'depthBase'|'linearDepth')} scope - The node's scope. 9884 * @param {?Node} [valueNode=null] - The value node. 9885 */ 9886 constructor(scope, valueNode = null) { 9887 super("float"); 9888 this.scope = scope; 9889 this.valueNode = valueNode; 9890 this.isViewportDepthNode = true; 9891 } 9892 generate(builder) { 9893 const { scope } = this; 9894 if (scope === _ViewportDepthNode.DEPTH_BASE) { 9895 return builder.getFragDepth(); 9896 } 9897 return super.generate(builder); 9898 } 9899 setup({ camera }) { 9900 const { scope } = this; 9901 const value = this.valueNode; 9902 let node = null; 9903 if (scope === _ViewportDepthNode.DEPTH_BASE) { 9904 if (value !== null) { 9905 node = depthBase().assign(value); 9906 } 9907 } else if (scope === _ViewportDepthNode.DEPTH) { 9908 if (camera.isPerspectiveCamera) { 9909 node = viewZToPerspectiveDepth(positionView.z, cameraNear, cameraFar); 9910 } else { 9911 node = viewZToOrthographicDepth(positionView.z, cameraNear, cameraFar); 9912 } 9913 } else if (scope === _ViewportDepthNode.LINEAR_DEPTH) { 9914 if (value !== null) { 9915 if (camera.isPerspectiveCamera) { 9916 const viewZ = perspectiveDepthToViewZ(value, cameraNear, cameraFar); 9917 node = viewZToOrthographicDepth(viewZ, cameraNear, cameraFar); 9918 } else { 9919 node = value; 9920 } 9921 } else { 9922 node = viewZToOrthographicDepth(positionView.z, cameraNear, cameraFar); 9923 } 9924 } 9925 return node; 9926 } 9927}; 9928ViewportDepthNode.DEPTH_BASE = "depthBase"; 9929ViewportDepthNode.DEPTH = "depth"; 9930ViewportDepthNode.LINEAR_DEPTH = "linearDepth"; 9931var viewZToOrthographicDepth = (viewZ, near, far) => viewZ.add(near).div(near.sub(far)); 9932var viewZToReversedOrthographicDepth = (viewZ, near, far) => viewZ.add(far).div(far.sub(near)); 9933var orthographicDepthToViewZ = /* @__PURE__ */ Fn(([depth3, near, far], builder) => { 9934 if (builder.renderer.reversedDepthBuffer === true) { 9935 return far.sub(near).mul(depth3).sub(far); 9936 } else { 9937 return near.sub(far).mul(depth3).sub(near); 9938 } 9939}); 9940var viewZToPerspectiveDepth = (viewZ, near, far) => near.add(viewZ).mul(far).div(far.sub(near).mul(viewZ)); 9941var viewZToReversedPerspectiveDepth = (viewZ, near, far) => near.mul(viewZ.add(far)).div(viewZ.mul(near.sub(far))); 9942var perspectiveDepthToViewZ = /* @__PURE__ */ Fn(([depth3, near, far], builder) => { 9943 if (builder.renderer.reversedDepthBuffer === true) { 9944 return near.mul(far).div(near.sub(far).mul(depth3).sub(near)); 9945 } else { 9946 return near.mul(far).div(far.sub(near).mul(depth3).sub(far)); 9947 } 9948}); 9949var viewZToLogarithmicDepth = (viewZ, near, far) => { 9950 near = near.max(1e-6).toVar(); 9951 const numerator = log22(viewZ.negate().div(near)); 9952 const denominator = log22(far.div(near)); 9953 return numerator.div(denominator); 9954}; 9955var logarithmicDepthToViewZ = (depth3, near, far) => { 9956 const exponent = depth3.mul(log2(far.div(near))); 9957 return float(Math.E).pow(exponent).mul(near).negate(); 9958}; 9959var depthBase = /* @__PURE__ */ nodeProxy(ViewportDepthNode, ViewportDepthNode.DEPTH_BASE); 9960var depth = /* @__PURE__ */ nodeImmutable(ViewportDepthNode, ViewportDepthNode.DEPTH); 9961var linearDepth = /* @__PURE__ */ nodeProxy(ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH).setParameterLength(0, 1); 9962var viewportLinearDepth = /* @__PURE__ */ linearDepth(viewportDepthTexture()); 9963depth.assign = (value) => depthBase(value); 9964var ClippingNode = class _ClippingNode extends Node2 { 9965 static get type() { 9966 return "ClippingNode"; 9967 } 9968 /** 9969 * Constructs a new clipping node. 9970 * 9971 * @param {('default'|'hardware'|'alphaToCoverage')} [scope='default'] - The node's scope. Similar to other nodes, 9972 * the selected scope influences the behavior of the node and what type of code is generated. 9973 */ 9974 constructor(scope = _ClippingNode.DEFAULT) { 9975 super(); 9976 this.scope = scope; 9977 } 9978 /** 9979 * Setups the node depending on the selected scope. 9980 * 9981 * @param {NodeBuilder} builder - The current node builder. 9982 * @return {Node} The result node. 9983 */ 9984 setup(builder) { 9985 super.setup(builder); 9986 const clippingContext = builder.clippingContext; 9987 const { intersectionPlanes, unionPlanes } = clippingContext; 9988 this.hardwareClipping = builder.material.hardwareClipping; 9989 if (this.scope === _ClippingNode.ALPHA_TO_COVERAGE) { 9990 return this.setupAlphaToCoverage(intersectionPlanes, unionPlanes); 9991 } else if (this.scope === _ClippingNode.HARDWARE) { 9992 return this.setupHardwareClipping(unionPlanes, builder); 9993 } else { 9994 return this.setupDefault(intersectionPlanes, unionPlanes); 9995 } 9996 } 9997 /** 9998 * Setups alpha to coverage. 9999 * 10000 * @param {Array<Vector4>} intersectionPlanes - The intersection planes. 10001 * @param {Array<Vector4>} unionPlanes - The union planes. 10002 * @return {Node} The result node. 10003 */ 10004 setupAlphaToCoverage(intersectionPlanes, unionPlanes) { 10005 return Fn(() => { 10006 const distanceToPlane = float().toVar("distanceToPlane"); 10007 const distanceGradient = float().toVar("distanceToGradient"); 10008 const clipOpacity = float(1).toVar("clipOpacity"); 10009 const numUnionPlanes = unionPlanes.length; 10010 if (this.hardwareClipping === false && numUnionPlanes > 0) { 10011 const clippingPlanes = uniformArray(unionPlanes).setGroup(renderGroup); 10012 Loop(numUnionPlanes, ({ i }) => { 10013 const plane = clippingPlanes.element(i); 10014 distanceToPlane.assign(positionView.dot(plane.xyz).negate().add(plane.w)); 10015 distanceGradient.assign(distanceToPlane.fwidth().div(2)); 10016 clipOpacity.mulAssign(smoothstep(distanceGradient.negate(), distanceGradient, distanceToPlane)); 10017 }); 10018 } 10019 const numIntersectionPlanes = intersectionPlanes.length; 10020 if (numIntersectionPlanes > 0) { 10021 const clippingPlanes = uniformArray(intersectionPlanes).setGroup(renderGroup); 10022 const intersectionClipOpacity = float(1).toVar("intersectionClipOpacity"); 10023 Loop(numIntersectionPlanes, ({ i }) => { 10024 const plane = clippingPlanes.element(i); 10025 distanceToPlane.assign(positionView.dot(plane.xyz).negate().add(plane.w)); 10026 distanceGradient.assign(distanceToPlane.fwidth().div(2)); 10027 intersectionClipOpacity.mulAssign(smoothstep(distanceGradient.negate(), distanceGradient, distanceToPlane).oneMinus()); 10028 }); 10029 clipOpacity.mulAssign(intersectionClipOpacity.oneMinus()); 10030 } 10031 diffuseColor.a.mulAssign(clipOpacity); 10032 diffuseColor.a.equal(0).discard(); 10033 })(); 10034 } 10035 /** 10036 * Setups the default clipping. 10037 * 10038 * @param {Array<Vector4>} intersectionPlanes - The intersection planes. 10039 * @param {Array<Vector4>} unionPlanes - The union planes. 10040 * @return {Node} The result node. 10041 */ 10042 setupDefault(intersectionPlanes, unionPlanes) { 10043 return Fn(() => { 10044 const numUnionPlanes = unionPlanes.length; 10045 if (this.hardwareClipping === false && numUnionPlanes > 0) { 10046 const clippingPlanes = uniformArray(unionPlanes).setGroup(renderGroup); 10047 Loop(numUnionPlanes, ({ i }) => { 10048 const plane = clippingPlanes.element(i); 10049 positionView.dot(plane.xyz).greaterThan(plane.w).discard(); 10050 }); 10051 } 10052 const numIntersectionPlanes = intersectionPlanes.length; 10053 if (numIntersectionPlanes > 0) { 10054 const clippingPlanes = uniformArray(intersectionPlanes).setGroup(renderGroup); 10055 const clipped = bool(true).toVar("clipped"); 10056 Loop(numIntersectionPlanes, ({ i }) => { 10057 const plane = clippingPlanes.element(i); 10058 clipped.assign(positionView.dot(plane.xyz).greaterThan(plane.w).and(clipped)); 10059 }); 10060 clipped.discard(); 10061 } 10062 })(); 10063 } 10064 /** 10065 * Setups hardware clipping. 10066 * 10067 * @param {Array<Vector4>} unionPlanes - The union planes. 10068 * @param {NodeBuilder} builder - The current node builder. 10069 * @return {Node} The result node. 10070 */ 10071 setupHardwareClipping(unionPlanes, builder) { 10072 const numUnionPlanes = unionPlanes.length; 10073 builder.enableHardwareClipping(numUnionPlanes); 10074 return Fn(() => { 10075 const clippingPlanes = uniformArray(unionPlanes).setGroup(renderGroup); 10076 const hw_clip_distances = builtin(builder.getClipDistance()); 10077 Loop(numUnionPlanes, ({ i }) => { 10078 const plane = clippingPlanes.element(i); 10079 const distance3 = positionView.dot(plane.xyz).sub(plane.w).negate(); 10080 hw_clip_distances.element(i).assign(distance3); 10081 }); 10082 })(); 10083 } 10084}; 10085ClippingNode.ALPHA_TO_COVERAGE = "alphaToCoverage"; 10086ClippingNode.DEFAULT = "default"; 10087ClippingNode.HARDWARE = "hardware"; 10088var clipping = () => new ClippingNode(); 10089var clippingAlpha = () => new ClippingNode(ClippingNode.ALPHA_TO_COVERAGE); 10090var hardwareClipping = () => new ClippingNode(ClippingNode.HARDWARE); 10091var ALPHA_HASH_SCALE = 0.05; 10092var hash2D = /* @__PURE__ */ Fn(([value]) => { 10093 return fract(mul(1e4, sin(mul(17, value.x).add(mul(0.1, value.y)))).mul(add(0.1, abs(sin(mul(13, value.y).add(value.x)))))); 10094}); 10095var hash3D = /* @__PURE__ */ Fn(([value]) => { 10096 return hash2D(vec2(hash2D(value.xy), value.z)); 10097}); 10098var getAlphaHashThreshold = /* @__PURE__ */ Fn(([position]) => { 10099 const maxDeriv = max$1( 10100 length(dFdx(position.xyz)), 10101 length(dFdy(position.xyz)) 10102 ); 10103 const pixScale = float(1).div(float(ALPHA_HASH_SCALE).mul(maxDeriv)).toVar("pixScale"); 10104 const pixScales = vec2( 10105 exp2(floor(log22(pixScale))), 10106 exp2(ceil(log22(pixScale))) 10107 ); 10108 const alpha = vec2( 10109 hash3D(floor(pixScales.x.mul(position.xyz))), 10110 hash3D(floor(pixScales.y.mul(position.xyz))) 10111 ); 10112 const lerpFactor = fract(log22(pixScale)); 10113 const x = add(mul(lerpFactor.oneMinus(), alpha.x), mul(lerpFactor, alpha.y)); 10114 const a = min$1(lerpFactor, lerpFactor.oneMinus()); 10115 const cases = vec3( 10116 x.mul(x).div(mul(2, a).mul(sub(1, a))), 10117 x.sub(mul(0.5, a)).div(sub(1, a)), 10118 sub(1, sub(1, x).mul(sub(1, x)).div(mul(2, a).mul(sub(1, a)))) 10119 ); 10120 const threshold = x.lessThan(a.oneMinus()).select(x.lessThan(a).select(cases.x, cases.y), cases.z); 10121 return clamp(threshold, 1e-6, 1); 10122}).setLayout({ 10123 name: "getAlphaHashThreshold", 10124 type: "float", 10125 inputs: [ 10126 { name: "position", type: "vec3" } 10127 ] 10128}); 10129var VertexColorNode = class extends AttributeNode { 10130 static get type() { 10131 return "VertexColorNode"; 10132 } 10133 /** 10134 * Constructs a new vertex color node. 10135 * 10136 * @param {number} index - The attribute index. 10137 */ 10138 constructor(index) { 10139 super(null, "vec4"); 10140 this.isVertexColorNode = true; 10141 this.index = index; 10142 } 10143 /** 10144 * Overwrites the default implementation by honoring the attribute index. 10145 * 10146 * @param {NodeBuilder} builder - The current node builder. 10147 * @return {string} The attribute name. 10148 */ 10149 getAttributeName() { 10150 const index = this.index; 10151 return "color" + (index > 0 ? index : ""); 10152 } 10153 generate(builder) { 10154 const attributeName = this.getAttributeName(builder); 10155 const geometryAttribute = builder.hasGeometryAttribute(attributeName); 10156 let result; 10157 if (geometryAttribute === true) { 10158 result = super.generate(builder); 10159 } else { 10160 result = builder.generateConst(this.nodeType, new Vector4(1, 1, 1, 1)); 10161 } 10162 return result; 10163 } 10164 serialize(data) { 10165 super.serialize(data); 10166 data.index = this.index; 10167 } 10168 deserialize(data) { 10169 super.deserialize(data); 10170 this.index = data.index; 10171 } 10172}; 10173var vertexColor = (index = 0) => new VertexColorNode(index); 10174var blendBurn = /* @__PURE__ */ Fn(([base, blend]) => { 10175 return min$1(1, base.oneMinus().div(blend)).oneMinus(); 10176}).setLayout({ 10177 name: "blendBurn", 10178 type: "vec3", 10179 inputs: [ 10180 { name: "base", type: "vec3" }, 10181 { name: "blend", type: "vec3" } 10182 ] 10183}); 10184var blendDodge = /* @__PURE__ */ Fn(([base, blend]) => { 10185 return min$1(base.div(blend.oneMinus()), 1); 10186}).setLayout({ 10187 name: "blendDodge", 10188 type: "vec3", 10189 inputs: [ 10190 { name: "base", type: "vec3" }, 10191 { name: "blend", type: "vec3" } 10192 ] 10193}); 10194var blendScreen = /* @__PURE__ */ Fn(([base, blend]) => { 10195 return base.oneMinus().mul(blend.oneMinus()).oneMinus(); 10196}).setLayout({ 10197 name: "blendScreen", 10198 type: "vec3", 10199 inputs: [ 10200 { name: "base", type: "vec3" }, 10201 { name: "blend", type: "vec3" } 10202 ] 10203}); 10204var blendOverlay = /* @__PURE__ */ Fn(([base, blend]) => { 10205 return mix(base.mul(2).mul(blend), base.oneMinus().mul(2).mul(blend.oneMinus()).oneMinus(), step(0.5, base)); 10206}).setLayout({ 10207 name: "blendOverlay", 10208 type: "vec3", 10209 inputs: [ 10210 { name: "base", type: "vec3" }, 10211 { name: "blend", type: "vec3" } 10212 ] 10213}); 10214var blendColor = /* @__PURE__ */ Fn(([base, blend]) => { 10215 const outAlpha = blend.a.add(base.a.mul(blend.a.oneMinus())); 10216 return vec4(blend.rgb.mul(blend.a).add(base.rgb.mul(base.a).mul(blend.a.oneMinus())).div(outAlpha), outAlpha); 10217}).setLayout({ 10218 name: "blendColor", 10219 type: "vec4", 10220 inputs: [ 10221 { name: "base", type: "vec4" }, 10222 { name: "blend", type: "vec4" } 10223 ] 10224}); 10225var premultiplyAlpha = /* @__PURE__ */ Fn(([color3]) => { 10226 return vec4(color3.rgb.mul(color3.a), color3.a); 10227}, { color: "vec4", return: "vec4" }); 10228var unpremultiplyAlpha = /* @__PURE__ */ Fn(([color3]) => { 10229 If(color3.a.equal(0), () => vec4(0)); 10230 return vec4(color3.rgb.div(color3.a), color3.a); 10231}, { color: "vec4", return: "vec4" }); 10232var NodeMaterial = class extends Material { 10233 static get type() { 10234 return "NodeMaterial"; 10235 } 10236 /** 10237 * Represents the type of the node material. 10238 * 10239 * @type {string} 10240 */ 10241 get type() { 10242 return this.constructor.type; 10243 } 10244 set type(_value) { 10245 } 10246 /** 10247 * Constructs a new node material. 10248 */ 10249 constructor() { 10250 super(); 10251 this.isNodeMaterial = true; 10252 this.fog = true; 10253 this.lights = false; 10254 this.hardwareClipping = false; 10255 this.lightsNode = null; 10256 this.envNode = null; 10257 this.aoNode = null; 10258 this.colorNode = null; 10259 this.normalNode = null; 10260 this.opacityNode = null; 10261 this.backdropNode = null; 10262 this.backdropAlphaNode = null; 10263 this.alphaTestNode = null; 10264 this.maskNode = null; 10265 this.maskShadowNode = null; 10266 this.positionNode = null; 10267 this.geometryNode = null; 10268 this.depthNode = null; 10269 this.receivedShadowPositionNode = null; 10270 this.castShadowPositionNode = null; 10271 this.receivedShadowNode = null; 10272 this.castShadowNode = null; 10273 this.outputNode = null; 10274 this.mrtNode = null; 10275 this.fragmentNode = null; 10276 this.vertexNode = null; 10277 this.contextNode = null; 10278 } 10279 /** 10280 * Returns an array of child nodes for this material. 10281 * 10282 * @private 10283 * @returns {Array<{property: string, childNode: Node}>} 10284 */ 10285 _getNodeChildren() { 10286 const children2 = []; 10287 for (const property3 of Object.getOwnPropertyNames(this)) { 10288 if (property3.startsWith("_") === true) continue; 10289 const object = this[property3]; 10290 if (object && object.isNode === true) { 10291 children2.push({ property: property3, childNode: object }); 10292 } 10293 } 10294 return children2; 10295 } 10296 /** 10297 * Allows to define a custom cache key that influence the material key computation 10298 * for render objects. 10299 * 10300 * @return {string} The custom cache key. 10301 */ 10302 customProgramCacheKey() { 10303 const values = []; 10304 for (const { property: property3, childNode } of this._getNodeChildren()) { 10305 values.push(hashString(property3.slice(0, -4)), childNode.getCacheKey()); 10306 } 10307 return this.type + hashArray(values); 10308 } 10309 /** 10310 * Builds this material with the given node builder. 10311 * 10312 * @param {NodeBuilder} builder - The current node builder. 10313 */ 10314 build(builder) { 10315 this.setup(builder); 10316 } 10317 /** 10318 * Setups a node material observer with the given builder. 10319 * 10320 * @param {NodeBuilder} builder - The current node builder. 10321 * @return {NodeMaterialObserver} The node material observer. 10322 */ 10323 setupObserver(builder) { 10324 return new NodeMaterialObserver(builder); 10325 } 10326 /** 10327 * Setups the vertex and fragment stage of this node material. 10328 * 10329 * @param {NodeBuilder} builder - The current node builder. 10330 */ 10331 setup(builder) { 10332 builder.context.setupNormal = () => subBuild(this.setupNormal(builder), "NORMAL", "vec3"); 10333 builder.context.setupPositionView = () => this.setupPositionView(builder); 10334 builder.context.setupModelViewProjection = () => this.setupModelViewProjection(builder); 10335 const renderer = builder.renderer; 10336 const renderTarget = renderer.getRenderTarget(); 10337 builder.addStack(); 10338 const mvp = this.setupVertex(builder); 10339 const vertexNode = subBuild(this.vertexNode || mvp, "VERTEX"); 10340 builder.context.clipSpace = vertexNode; 10341 builder.stack.outputNode = vertexNode; 10342 this.setupHardwareClipping(builder); 10343 if (this.geometryNode !== null) { 10344 builder.stack.outputNode = builder.stack.outputNode.bypass(this.geometryNode); 10345 } 10346 builder.addFlow("vertex", builder.removeStack()); 10347 builder.addStack(); 10348 let resultNode; 10349 const clippingNode = this.setupClipping(builder); 10350 if (this.depthWrite === true || this.depthTest === true) { 10351 if (renderTarget !== null) { 10352 if (renderTarget.depthBuffer === true) this.setupDepth(builder); 10353 } else { 10354 if (renderer.depth === true) this.setupDepth(builder); 10355 } 10356 } 10357 if (this.fragmentNode === null) { 10358 this.setupDiffuseColor(builder); 10359 this.setupVariants(builder); 10360 const outgoingLightNode = this.setupLighting(builder); 10361 if (clippingNode !== null) builder.stack.addToStack(clippingNode); 10362 const basicOutput = vec4(outgoingLightNode, diffuseColor.a).max(0); 10363 resultNode = this.setupOutput(builder, basicOutput); 10364 output.assign(resultNode); 10365 const isCustomOutput = this.outputNode !== null; 10366 if (isCustomOutput) resultNode = this.outputNode; 10367 if (builder.context.getOutput) { 10368 resultNode = builder.context.getOutput(resultNode, builder); 10369 } 10370 if (renderTarget !== null) { 10371 const mrt3 = renderer.getMRT(); 10372 const materialMRT = this.mrtNode; 10373 if (mrt3 !== null) { 10374 if (isCustomOutput) output.assign(resultNode); 10375 resultNode = mrt3; 10376 if (materialMRT !== null) { 10377 resultNode = mrt3.merge(materialMRT); 10378 } 10379 } else if (materialMRT !== null) { 10380 resultNode = materialMRT; 10381 } 10382 } 10383 } else { 10384 let fragmentNode = this.fragmentNode; 10385 if (fragmentNode.isOutputStructNode !== true) { 10386 fragmentNode = vec4(fragmentNode); 10387 } 10388 resultNode = this.setupOutput(builder, fragmentNode); 10389 } 10390 builder.stack.outputNode = resultNode; 10391 builder.addFlow("fragment", builder.removeStack()); 10392 builder.observer = this.setupObserver(builder); 10393 } 10394 /** 10395 * Setups the clipping node. 10396 * 10397 * @param {NodeBuilder} builder - The current node builder. 10398 * @return {ClippingNode} The clipping node. 10399 */ 10400 setupClipping(builder) { 10401 if (builder.clippingContext === null) return null; 10402 const { unionPlanes, intersectionPlanes } = builder.clippingContext; 10403 let result = null; 10404 if (unionPlanes.length > 0 || intersectionPlanes.length > 0) { 10405 const samples = builder.renderer.currentSamples; 10406 if (this.alphaToCoverage && samples > 1) { 10407 result = clippingAlpha(); 10408 } else { 10409 builder.stack.addToStack(clipping()); 10410 } 10411 } 10412 return result; 10413 } 10414 /** 10415 * Setups the hardware clipping if available on the current device. 10416 * 10417 * @param {NodeBuilder} builder - The current node builder. 10418 */ 10419 setupHardwareClipping(builder) { 10420 this.hardwareClipping = false; 10421 if (builder.clippingContext === null) return; 10422 const candidateCount = builder.clippingContext.unionPlanes.length; 10423 if (candidateCount > 0 && candidateCount <= 8 && builder.isAvailable("clipDistance")) { 10424 builder.stack.addToStack(hardwareClipping()); 10425 this.hardwareClipping = true; 10426 } 10427 return; 10428 } 10429 /** 10430 * Setups the depth of this material. 10431 * 10432 * @param {NodeBuilder} builder - The current node builder. 10433 */ 10434 setupDepth(builder) { 10435 const { renderer, camera } = builder; 10436 let depthNode = this.depthNode; 10437 if (depthNode === null) { 10438 const mrt3 = renderer.getMRT(); 10439 if (mrt3 && mrt3.has("depth")) { 10440 depthNode = mrt3.get("depth"); 10441 } else if (renderer.logarithmicDepthBuffer === true) { 10442 if (camera.isPerspectiveCamera) { 10443 depthNode = viewZToLogarithmicDepth(positionView.z, cameraNear, cameraFar); 10444 } else { 10445 depthNode = viewZToOrthographicDepth(positionView.z, cameraNear, cameraFar); 10446 } 10447 } 10448 } 10449 if (depthNode !== null) { 10450 depth.assign(depthNode).toStack(); 10451 } 10452 } 10453 /** 10454 * Setups the position node in view space. This method exists 10455 * so derived node materials can modify the implementation e.g. sprite materials. 10456 * 10457 * @param {NodeBuilder} builder - The current node builder. 10458 * @return {Node<vec3>} The position in view space. 10459 */ 10460 setupPositionView() { 10461 return modelViewMatrix.mul(positionLocal).xyz; 10462 } 10463 /** 10464 * Setups the position in clip space. 10465 * 10466 * @param {NodeBuilder} builder - The current node builder. 10467 * @return {Node<vec4>} The position in view space. 10468 */ 10469 setupModelViewProjection() { 10470 return cameraProjectionMatrix.mul(positionView); 10471 } 10472 /** 10473 * Setups the logic for the vertex stage. 10474 * 10475 * @param {NodeBuilder} builder - The current node builder. 10476 * @return {Node<vec4>} The position in clip space. 10477 */ 10478 setupVertex(builder) { 10479 builder.addStack(); 10480 this.setupPosition(builder); 10481 builder.context.position = builder.removeStack(); 10482 return modelViewProjection; 10483 } 10484 /** 10485 * Setups the computation of the position in local space. 10486 * 10487 * @param {NodeBuilder} builder - The current node builder. 10488 * @return {Node<vec3>} The position in local space. 10489 */ 10490 setupPosition(builder) { 10491 const { object, geometry } = builder; 10492 if (geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color) { 10493 morphReference(object).toStack(); 10494 } 10495 if (object.isSkinnedMesh === true) { 10496 skinning(object).toStack(); 10497 } 10498 if (this.displacementMap) { 10499 const displacementMap = materialReference("displacementMap", "texture"); 10500 const displacementScale = materialReference("displacementScale", "float"); 10501 const displacementBias = materialReference("displacementBias", "float"); 10502 positionLocal.addAssign(normalLocal.normalize().mul(displacementMap.x.mul(displacementScale).add(displacementBias))); 10503 } 10504 if (object.isBatchedMesh) { 10505 batch2(object).toStack(); 10506 } 10507 if (object.isInstancedMesh && object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true) { 10508 instancedMesh(object).toStack(); 10509 } 10510 if (this.positionNode !== null) { 10511 positionLocal.assign(subBuild(this.positionNode, "POSITION", "vec3")); 10512 } 10513 return positionLocal; 10514 } 10515 /** 10516 * Setups the computation of the material's diffuse color. 10517 * 10518 * @param {NodeBuilder} builder - The current node builder. 10519 * @param {BufferGeometry} geometry - The geometry. 10520 */ 10521 setupDiffuseColor(builder) { 10522 const { object, geometry } = builder; 10523 if (this.maskNode !== null) { 10524 bool(this.maskNode).not().discard(); 10525 } 10526 let colorNode = this.colorNode ? vec4(this.colorNode) : materialColor; 10527 if (this.vertexColors === true && geometry.hasAttribute("color")) { 10528 colorNode = colorNode.mul(vertexColor()); 10529 } 10530 if (object.instanceColor) { 10531 const instanceColor = varyingProperty("vec3", "vInstanceColor"); 10532 colorNode = instanceColor.mul(colorNode); 10533 } 10534 if (object.isBatchedMesh && object._colorsTexture) { 10535 const batchColor = varyingProperty("vec3", "vBatchColor"); 10536 colorNode = batchColor.mul(colorNode); 10537 } 10538 diffuseColor.assign(colorNode); 10539 const opacityNode = this.opacityNode ? float(this.opacityNode) : materialOpacity; 10540 diffuseColor.a.assign(diffuseColor.a.mul(opacityNode)); 10541 let alphaTestNode = null; 10542 if (this.alphaTestNode !== null || this.alphaTest > 0) { 10543 alphaTestNode = this.alphaTestNode !== null ? float(this.alphaTestNode) : materialAlphaTest; 10544 if (this.alphaToCoverage === true) { 10545 diffuseColor.a = smoothstep(alphaTestNode, alphaTestNode.add(fwidth(diffuseColor.a)), diffuseColor.a); 10546 diffuseColor.a.lessThanEqual(0).discard(); 10547 } else { 10548 diffuseColor.a.lessThanEqual(alphaTestNode).discard(); 10549 } 10550 } 10551 if (this.alphaHash === true) { 10552 diffuseColor.a.lessThan(getAlphaHashThreshold(positionLocal)).discard(); 10553 } 10554 if (builder.isOpaque()) { 10555 diffuseColor.a.assign(1); 10556 } 10557 } 10558 /** 10559 * Abstract interface method that can be implemented by derived materials 10560 * to setup material-specific node variables. 10561 * 10562 * @abstract 10563 * @param {NodeBuilder} builder - The current node builder. 10564 */ 10565 setupVariants() { 10566 } 10567 /** 10568 * Setups the outgoing light node variable 10569 * 10570 * @return {Node<vec3>} The outgoing light node. 10571 */ 10572 setupOutgoingLight() { 10573 return this.lights === true ? vec3(0) : diffuseColor.rgb; 10574 } 10575 /** 10576 * Setups the normal node from the material. 10577 * 10578 * @return {Node<vec3>} The normal node. 10579 */ 10580 setupNormal() { 10581 return this.normalNode ? vec3(this.normalNode) : materialNormal; 10582 } 10583 /** 10584 * Setups the environment node from the material. 10585 * 10586 * @param {NodeBuilder} builder - The current node builder. 10587 * @return {Node<vec4>} The environment node. 10588 */ 10589 setupEnvironment() { 10590 let node = null; 10591 if (this.envNode) { 10592 node = this.envNode; 10593 } else if (this.envMap) { 10594 node = this.envMap.isCubeTexture ? materialReference("envMap", "cubeTexture") : materialReference("envMap", "texture"); 10595 } 10596 return node; 10597 } 10598 /** 10599 * Setups the light map node from the material. 10600 * 10601 * @param {NodeBuilder} builder - The current node builder. 10602 * @return {Node<vec3>} The light map node. 10603 */ 10604 setupLightMap(builder) { 10605 let node = null; 10606 if (builder.material.lightMap) { 10607 node = new IrradianceNode(materialLightMap); 10608 } 10609 return node; 10610 } 10611 /** 10612 * Setups the lights node based on the scene, environment and material. 10613 * 10614 * @param {NodeBuilder} builder - The current node builder. 10615 * @return {LightsNode} The lights node. 10616 */ 10617 setupLights(builder) { 10618 const materialLightsNode = []; 10619 const envNode = this.setupEnvironment(builder); 10620 if (envNode && envNode.isLightingNode) { 10621 materialLightsNode.push(envNode); 10622 } 10623 const lightMapNode = this.setupLightMap(builder); 10624 if (lightMapNode && lightMapNode.isLightingNode) { 10625 materialLightsNode.push(lightMapNode); 10626 } 10627 let aoNode = this.aoNode; 10628 if (aoNode === null && builder.material.aoMap) { 10629 aoNode = materialAO; 10630 } 10631 if (builder.context.getAO) { 10632 aoNode = builder.context.getAO(aoNode, builder); 10633 } 10634 if (aoNode) { 10635 materialLightsNode.push(new AONode(aoNode)); 10636 } 10637 let lightsN = this.lightsNode || builder.lightsNode; 10638 if (materialLightsNode.length > 0) { 10639 lightsN = builder.renderer.lighting.createNode([...lightsN.getLights(), ...materialLightsNode]); 10640 } 10641 return lightsN; 10642 } 10643 /** 10644 * This method should be implemented by most derived materials 10645 * since it defines the material's lighting model. 10646 * 10647 * @abstract 10648 * @param {NodeBuilder} builder - The current node builder. 10649 * @return {LightingModel} The lighting model. 10650 */ 10651 setupLightingModel() { 10652 } 10653 /** 10654 * Setups the outgoing light node. 10655 * 10656 * @param {NodeBuilder} builder - The current node builder. 10657 * @return {Node<vec3>} The outgoing light node. 10658 */ 10659 setupLighting(builder) { 10660 const { material } = builder; 10661 const { backdropNode, backdropAlphaNode, emissiveNode } = this; 10662 const lights3 = this.lights === true || this.lightsNode !== null; 10663 const lightsNode = lights3 ? this.setupLights(builder) : null; 10664 let outgoingLightNode = this.setupOutgoingLight(builder); 10665 if (lightsNode && lightsNode.getScope().hasLights) { 10666 const lightingModel = this.setupLightingModel(builder) || null; 10667 outgoingLightNode = lightingContext(lightsNode, lightingModel, backdropNode, backdropAlphaNode); 10668 } else if (backdropNode !== null) { 10669 outgoingLightNode = vec3(backdropAlphaNode !== null ? mix(outgoingLightNode, backdropNode, backdropAlphaNode) : backdropNode); 10670 } 10671 if (emissiveNode && emissiveNode.isNode === true || material.emissive && material.emissive.isColor === true) { 10672 emissive.assign(vec3(emissiveNode ? emissiveNode : materialEmissive)); 10673 outgoingLightNode = outgoingLightNode.add(emissive); 10674 } 10675 return outgoingLightNode; 10676 } 10677 /** 10678 * Setup the fog. 10679 * 10680 * @param {NodeBuilder} builder - The current node builder. 10681 * @param {Node<vec4>} outputNode - The existing output node. 10682 * @return {Node<vec4>} The output node. 10683 */ 10684 setupFog(builder, outputNode) { 10685 const fogNode = builder.fogNode; 10686 if (fogNode) { 10687 output.assign(outputNode); 10688 outputNode = vec4(fogNode.toVar()); 10689 } 10690 return outputNode; 10691 } 10692 /** 10693 * Setups premultiplied alpha. 10694 * 10695 * @param {NodeBuilder} builder - The current node builder. 10696 * @param {Node<vec4>} outputNode - The existing output node. 10697 * @return {Node<vec4>} The output node. 10698 */ 10699 setupPremultipliedAlpha(builder, outputNode) { 10700 return premultiplyAlpha(outputNode); 10701 } 10702 /** 10703 * Setups the output node. 10704 * 10705 * @param {NodeBuilder} builder - The current node builder. 10706 * @param {Node<vec4>} outputNode - The existing output node. 10707 * @return {Node<vec4>} The output node. 10708 */ 10709 setupOutput(builder, outputNode) { 10710 if (this.fog === true) { 10711 outputNode = this.setupFog(builder, outputNode); 10712 } 10713 if (this.premultipliedAlpha === true) { 10714 outputNode = this.setupPremultipliedAlpha(builder, outputNode); 10715 } 10716 return outputNode; 10717 } 10718 /** 10719 * Most classic material types have a node pendant e.g. for `MeshBasicMaterial` 10720 * there is `MeshBasicNodeMaterial`. This utility method is intended for 10721 * defining all material properties of the classic type in the node type. 10722 * 10723 * @param {Material} material - The material to copy properties with their values to this node material. 10724 */ 10725 setDefaultValues(material) { 10726 for (const property3 in material) { 10727 const value = material[property3]; 10728 if (this[property3] === void 0) { 10729 this[property3] = value; 10730 if (value && value.clone) this[property3] = value.clone(); 10731 } 10732 } 10733 const descriptors = Object.getOwnPropertyDescriptors(material.constructor.prototype); 10734 for (const key in descriptors) { 10735 if (Object.getOwnPropertyDescriptor(this.constructor.prototype, key) === void 0 && descriptors[key].get !== void 0) { 10736 Object.defineProperty(this.constructor.prototype, key, descriptors[key]); 10737 } 10738 } 10739 } 10740 /** 10741 * Serializes this material to JSON. 10742 * 10743 * @param {?(Object|string)} meta - The meta information for serialization. 10744 * @return {Object} The serialized node. 10745 */ 10746 toJSON(meta) { 10747 const isRoot = meta === void 0 || typeof meta === "string"; 10748 if (isRoot) { 10749 meta = { 10750 textures: {}, 10751 images: {}, 10752 nodes: {} 10753 }; 10754 } 10755 const data = Material.prototype.toJSON.call(this, meta); 10756 data.inputNodes = {}; 10757 for (const { property: property3, childNode } of this._getNodeChildren()) { 10758 data.inputNodes[property3] = childNode.toJSON(meta).uuid; 10759 } 10760 function extractFromCache(cache4) { 10761 const values = []; 10762 for (const key in cache4) { 10763 const data2 = cache4[key]; 10764 delete data2.metadata; 10765 values.push(data2); 10766 } 10767 return values; 10768 } 10769 if (isRoot) { 10770 const textures = extractFromCache(meta.textures); 10771 const images = extractFromCache(meta.images); 10772 const nodes = extractFromCache(meta.nodes); 10773 if (textures.length > 0) data.textures = textures; 10774 if (images.length > 0) data.images = images; 10775 if (nodes.length > 0) data.nodes = nodes; 10776 } 10777 return data; 10778 } 10779 /** 10780 * Copies the properties of the given node material to this instance. 10781 * 10782 * @param {NodeMaterial} source - The material to copy. 10783 * @return {NodeMaterial} A reference to this node material. 10784 */ 10785 copy(source) { 10786 this.lightsNode = source.lightsNode; 10787 this.envNode = source.envNode; 10788 this.aoNode = source.aoNode; 10789 this.colorNode = source.colorNode; 10790 this.normalNode = source.normalNode; 10791 this.opacityNode = source.opacityNode; 10792 this.backdropNode = source.backdropNode; 10793 this.backdropAlphaNode = source.backdropAlphaNode; 10794 this.alphaTestNode = source.alphaTestNode; 10795 this.maskNode = source.maskNode; 10796 this.maskShadowNode = source.maskShadowNode; 10797 this.positionNode = source.positionNode; 10798 this.geometryNode = source.geometryNode; 10799 this.depthNode = source.depthNode; 10800 this.receivedShadowPositionNode = source.receivedShadowPositionNode; 10801 this.castShadowPositionNode = source.castShadowPositionNode; 10802 this.receivedShadowNode = source.receivedShadowNode; 10803 this.castShadowNode = source.castShadowNode; 10804 this.outputNode = source.outputNode; 10805 this.mrtNode = source.mrtNode; 10806 this.fragmentNode = source.fragmentNode; 10807 this.vertexNode = source.vertexNode; 10808 this.contextNode = source.contextNode; 10809 return super.copy(source); 10810 } 10811}; 10812var _defaultValues$d = /* @__PURE__ */ new LineBasicMaterial(); 10813var LineBasicNodeMaterial = class extends NodeMaterial { 10814 static get type() { 10815 return "LineBasicNodeMaterial"; 10816 } 10817 /** 10818 * Constructs a new line basic node material. 10819 * 10820 * @param {Object} [parameters] - The configuration parameter. 10821 */ 10822 constructor(parameters) { 10823 super(); 10824 this.isLineBasicNodeMaterial = true; 10825 this.setDefaultValues(_defaultValues$d); 10826 this.setValues(parameters); 10827 } 10828}; 10829var _defaultValues$c = /* @__PURE__ */ new LineDashedMaterial(); 10830var LineDashedNodeMaterial = class extends NodeMaterial { 10831 static get type() { 10832 return "LineDashedNodeMaterial"; 10833 } 10834 /** 10835 * Constructs a new line dashed node material. 10836 * 10837 * @param {Object} [parameters] - The configuration parameter. 10838 */ 10839 constructor(parameters) { 10840 super(); 10841 this.isLineDashedNodeMaterial = true; 10842 this.setDefaultValues(_defaultValues$c); 10843 this.dashOffset = 0; 10844 this.offsetNode = null; 10845 this.dashScaleNode = null; 10846 this.dashSizeNode = null; 10847 this.gapSizeNode = null; 10848 this.setValues(parameters); 10849 } 10850 /** 10851 * Setups the dash specific node variables. 10852 * 10853 * @param {NodeBuilder} builder - The current node builder. 10854 */ 10855 setupVariants() { 10856 const offsetNode = this.offsetNode ? float(this.offsetNode) : materialLineDashOffset; 10857 const dashScaleNode = this.dashScaleNode ? float(this.dashScaleNode) : materialLineScale; 10858 const dashSizeNode = this.dashSizeNode ? float(this.dashSizeNode) : materialLineDashSize; 10859 const gapSizeNode = this.gapSizeNode ? float(this.gapSizeNode) : materialLineGapSize; 10860 dashSize.assign(dashSizeNode); 10861 gapSize.assign(gapSizeNode); 10862 const vLineDistance = varying(attribute("lineDistance").mul(dashScaleNode)); 10863 const vLineDistanceOffset = offsetNode ? vLineDistance.add(offsetNode) : vLineDistance; 10864 vLineDistanceOffset.mod(dashSize.add(gapSize)).greaterThan(dashSize).discard(); 10865 } 10866}; 10867var _defaultValues$a = /* @__PURE__ */ new MeshNormalMaterial(); 10868var MeshNormalNodeMaterial = class extends NodeMaterial { 10869 static get type() { 10870 return "MeshNormalNodeMaterial"; 10871 } 10872 /** 10873 * Constructs a new mesh normal node material. 10874 * 10875 * @param {Object} [parameters] - The configuration parameter. 10876 */ 10877 constructor(parameters) { 10878 super(); 10879 this.isMeshNormalNodeMaterial = true; 10880 this.setDefaultValues(_defaultValues$a); 10881 this.setValues(parameters); 10882 } 10883 /** 10884 * Overwrites the default implementation by computing the diffuse color 10885 * based on the normal data. 10886 */ 10887 setupDiffuseColor() { 10888 const opacityNode = this.opacityNode ? float(this.opacityNode) : materialOpacity; 10889 diffuseColor.assign(colorSpaceToWorking(vec4(directionToColor(normalView), opacityNode), SRGBColorSpace)); 10890 } 10891}; 10892var equirectUV = /* @__PURE__ */ Fn(([dir = positionWorldDirection]) => { 10893 const u = dir.z.atan(dir.x).mul(1 / (Math.PI * 2)).add(0.5); 10894 const v = dir.y.clamp(-1, 1).asin().mul(1 / Math.PI).add(0.5); 10895 return vec2(u, v); 10896}); 10897var CubeRenderTarget = class extends RenderTarget { 10898 /** 10899 * Constructs a new cube render target. 10900 * 10901 * @param {number} [size=1] - The size of the render target. 10902 * @param {RenderTarget~Options} [options] - The configuration object. 10903 */ 10904 constructor(size3 = 1, options = {}) { 10905 super(size3, size3, options); 10906 this.isCubeRenderTarget = true; 10907 const image = { width: size3, height: size3, depth: 1 }; 10908 const images = [image, image, image, image, image, image]; 10909 this.texture = new CubeTexture(images); 10910 this._setTextureOptions(options); 10911 this.texture.isRenderTargetTexture = true; 10912 } 10913 /** 10914 * Converts the given equirectangular texture to a cube map. 10915 * 10916 * @param {Renderer} renderer - The renderer. 10917 * @param {Texture} texture - The equirectangular texture. 10918 * @return {CubeRenderTarget} A reference to this cube render target. 10919 */ 10920 fromEquirectangularTexture(renderer, texture$1) { 10921 const currentMinFilter = texture$1.minFilter; 10922 const currentGenerateMipmaps = texture$1.generateMipmaps; 10923 texture$1.generateMipmaps = true; 10924 this.texture.type = texture$1.type; 10925 this.texture.colorSpace = texture$1.colorSpace; 10926 this.texture.generateMipmaps = texture$1.generateMipmaps; 10927 this.texture.minFilter = texture$1.minFilter; 10928 this.texture.magFilter = texture$1.magFilter; 10929 const geometry = new BoxGeometry(5, 5, 5); 10930 const uvNode = equirectUV(positionWorldDirection); 10931 const material = new NodeMaterial(); 10932 material.colorNode = texture(texture$1, uvNode, 0); 10933 material.side = BackSide; 10934 material.blending = NoBlending; 10935 const mesh = new Mesh(geometry, material); 10936 const scene = new Scene(); 10937 scene.add(mesh); 10938 if (texture$1.minFilter === LinearMipmapLinearFilter) texture$1.minFilter = LinearFilter; 10939 const camera = new CubeCamera(1, 10, this); 10940 const currentMRT = renderer.getMRT(); 10941 renderer.setMRT(null); 10942 camera.update(renderer, scene); 10943 renderer.setMRT(currentMRT); 10944 texture$1.minFilter = currentMinFilter; 10945 texture$1.generateMipmaps = currentGenerateMipmaps; 10946 mesh.geometry.dispose(); 10947 mesh.material.dispose(); 10948 return this; 10949 } 10950 /** 10951 * Clears this cube render target. 10952 * 10953 * @param {Renderer} renderer - The renderer. 10954 * @param {boolean} [color=true] - Whether the color buffer should be cleared or not. 10955 * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not. 10956 * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. 10957 */ 10958 clear(renderer, color3 = true, depth3 = true, stencil = true) { 10959 const currentRenderTarget = renderer.getRenderTarget(); 10960 for (let i = 0; i < 6; i++) { 10961 renderer.setRenderTarget(this, i); 10962 renderer.clear(color3, depth3, stencil); 10963 } 10964 renderer.setRenderTarget(currentRenderTarget); 10965 } 10966}; 10967var _cache$1 = /* @__PURE__ */ new WeakMap(); 10968var CubeMapNode = class extends TempNode { 10969 static get type() { 10970 return "CubeMapNode"; 10971 } 10972 /** 10973 * Constructs a new cube map node. 10974 * 10975 * @param {Node} envNode - The node representing the environment map. 10976 */ 10977 constructor(envNode) { 10978 super("vec3"); 10979 this.envNode = envNode; 10980 this._cubeTexture = null; 10981 this._cubeTextureNode = cubeTexture(null); 10982 const defaultTexture = new CubeTexture(); 10983 defaultTexture.isRenderTargetTexture = true; 10984 this._defaultTexture = defaultTexture; 10985 this.updateBeforeType = NodeUpdateType.RENDER; 10986 } 10987 updateBefore(frame) { 10988 const { renderer, material } = frame; 10989 const envNode = this.envNode; 10990 if (envNode.isTextureNode || envNode.isMaterialReferenceNode) { 10991 const texture3 = envNode.isTextureNode ? envNode.value : material[envNode.property]; 10992 if (texture3 && texture3.isTexture) { 10993 const mapping = texture3.mapping; 10994 if (mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping) { 10995 if (_cache$1.has(texture3)) { 10996 const cubeMap = _cache$1.get(texture3); 10997 mapTextureMapping(cubeMap, texture3.mapping); 10998 this._cubeTexture = cubeMap; 10999 } else { 11000 const image = texture3.image; 11001 if (isEquirectangularMapReady$1(image)) { 11002 const renderTarget = new CubeRenderTarget(image.height); 11003 renderTarget.fromEquirectangularTexture(renderer, texture3); 11004 mapTextureMapping(renderTarget.texture, texture3.mapping); 11005 this._cubeTexture = renderTarget.texture; 11006 _cache$1.set(texture3, renderTarget.texture); 11007 texture3.addEventListener("dispose", onTextureDispose); 11008 } else { 11009 this._cubeTexture = this._defaultTexture; 11010 } 11011 } 11012 this._cubeTextureNode.value = this._cubeTexture; 11013 } else { 11014 this._cubeTextureNode = this.envNode; 11015 } 11016 } 11017 } 11018 } 11019 setup(builder) { 11020 this.updateBefore(builder); 11021 return this._cubeTextureNode; 11022 } 11023}; 11024function isEquirectangularMapReady$1(image) { 11025 if (image === null || image === void 0) return false; 11026 return image.height > 0; 11027} 11028function onTextureDispose(event) { 11029 const texture3 = event.target; 11030 texture3.removeEventListener("dispose", onTextureDispose); 11031 const renderTarget = _cache$1.get(texture3); 11032 if (renderTarget !== void 0) { 11033 _cache$1.delete(texture3); 11034 renderTarget.dispose(); 11035 } 11036} 11037function mapTextureMapping(texture3, mapping) { 11038 if (mapping === EquirectangularReflectionMapping) { 11039 texture3.mapping = CubeReflectionMapping; 11040 } else if (mapping === EquirectangularRefractionMapping) { 11041 texture3.mapping = CubeRefractionMapping; 11042 } 11043} 11044var cubeMapNode = /* @__PURE__ */ nodeProxy(CubeMapNode).setParameterLength(1); 11045var BasicEnvironmentNode = class extends LightingNode { 11046 static get type() { 11047 return "BasicEnvironmentNode"; 11048 } 11049 /** 11050 * Constructs a new basic environment node. 11051 * 11052 * @param {Node} [envNode=null] - A node representing the environment. 11053 */ 11054 constructor(envNode = null) { 11055 super(); 11056 this.envNode = envNode; 11057 } 11058 setup(builder) { 11059 builder.context.environment = cubeMapNode(this.envNode); 11060 } 11061}; 11062var BasicLightMapNode = class extends LightingNode { 11063 static get type() { 11064 return "BasicLightMapNode"; 11065 } 11066 /** 11067 * Constructs a new basic light map node. 11068 * 11069 * @param {?Node<vec3>} [lightMapNode=null] - The light map node. 11070 */ 11071 constructor(lightMapNode = null) { 11072 super(); 11073 this.lightMapNode = lightMapNode; 11074 } 11075 setup(builder) { 11076 const RECIPROCAL_PI2 = float(1 / Math.PI); 11077 builder.context.irradianceLightMap = this.lightMapNode.mul(RECIPROCAL_PI2); 11078 } 11079}; 11080var LightingModel = class { 11081 /** 11082 * This method is intended for setting up lighting model and context data 11083 * which are later used in the evaluation process. 11084 * 11085 * @abstract 11086 * @param {NodeBuilder} builder - The current node builder. 11087 */ 11088 start(builder) { 11089 builder.lightsNode.setupLights(builder, builder.lightsNode.getLightNodes(builder)); 11090 this.indirect(builder); 11091 } 11092 /** 11093 * This method is intended for executing final tasks like final updates 11094 * to the outgoing light. 11095 * 11096 * @abstract 11097 * @param {NodeBuilder} builder - The current node builder. 11098 */ 11099 finish() { 11100 } 11101 /** 11102 * This method is intended for implementing the direct light term and 11103 * executed during the build process of directional, point and spot light nodes. 11104 * 11105 * @abstract 11106 * @param {Object} lightData - The light data. 11107 * @param {NodeBuilder} builder - The current node builder. 11108 */ 11109 direct() { 11110 } 11111 /** 11112 * This method is intended for implementing the direct light term for 11113 * rect area light nodes. 11114 * 11115 * @abstract 11116 * @param {Object} lightData - The light data. 11117 * @param {NodeBuilder} builder - The current node builder. 11118 */ 11119 directRectArea() { 11120 } 11121 /** 11122 * This method is intended for implementing the indirect light term. 11123 * 11124 * @abstract 11125 * @param {NodeBuilder} builder - The current node builder. 11126 */ 11127 indirect() { 11128 } 11129 /** 11130 * This method is intended for implementing the ambient occlusion term. 11131 * Unlike other methods, this method must be called manually by the lighting 11132 * model in its indirect term. 11133 * 11134 * @abstract 11135 * @param {NodeBuilder} builder - The current node builder. 11136 */ 11137 ambientOcclusion() { 11138 } 11139}; 11140var BasicLightingModel = class extends LightingModel { 11141 /** 11142 * Constructs a new basic lighting model. 11143 */ 11144 constructor() { 11145 super(); 11146 } 11147 /** 11148 * Implements the baked indirect lighting with its modulation. 11149 * 11150 * @param {NodeBuilder} builder - The current node builder. 11151 */ 11152 indirect({ context: context3 }) { 11153 const ambientOcclusion = context3.ambientOcclusion; 11154 const reflectedLight = context3.reflectedLight; 11155 const irradianceLightMap = context3.irradianceLightMap; 11156 reflectedLight.indirectDiffuse.assign(vec4(0)); 11157 if (irradianceLightMap) { 11158 reflectedLight.indirectDiffuse.addAssign(irradianceLightMap); 11159 } else { 11160 reflectedLight.indirectDiffuse.addAssign(vec4(1, 1, 1, 0)); 11161 } 11162 reflectedLight.indirectDiffuse.mulAssign(ambientOcclusion); 11163 reflectedLight.indirectDiffuse.mulAssign(diffuseColor.rgb); 11164 } 11165 /** 11166 * Implements the environment mapping. 11167 * 11168 * @param {NodeBuilder} builder - The current node builder. 11169 */ 11170 finish(builder) { 11171 const { material, context: context3 } = builder; 11172 const outgoingLight = context3.outgoingLight; 11173 const envNode = builder.context.environment; 11174 if (envNode) { 11175 switch (material.combine) { 11176 case MultiplyOperation: 11177 outgoingLight.rgb.assign(mix(outgoingLight.rgb, outgoingLight.rgb.mul(envNode.rgb), materialSpecularStrength.mul(materialReflectivity))); 11178 break; 11179 case MixOperation: 11180 outgoingLight.rgb.assign(mix(outgoingLight.rgb, envNode.rgb, materialSpecularStrength.mul(materialReflectivity))); 11181 break; 11182 case AddOperation: 11183 outgoingLight.rgb.addAssign(envNode.rgb.mul(materialSpecularStrength.mul(materialReflectivity))); 11184 break; 11185 default: 11186 warn("BasicLightingModel: Unsupported .combine value:", material.combine); 11187 break; 11188 } 11189 } 11190 } 11191}; 11192var _defaultValues$9 = /* @__PURE__ */ new MeshBasicMaterial(); 11193var MeshBasicNodeMaterial = class extends NodeMaterial { 11194 static get type() { 11195 return "MeshBasicNodeMaterial"; 11196 } 11197 /** 11198 * Constructs a new mesh basic node material. 11199 * 11200 * @param {Object} [parameters] - The configuration parameter. 11201 */ 11202 constructor(parameters) { 11203 super(); 11204 this.isMeshBasicNodeMaterial = true; 11205 this.lights = true; 11206 this.setDefaultValues(_defaultValues$9); 11207 this.setValues(parameters); 11208 } 11209 /** 11210 * Basic materials are not affected by normal and bump maps so we 11211 * return by default {@link normalViewGeometry}. 11212 * 11213 * @return {Node<vec3>} The normal node. 11214 */ 11215 setupNormal() { 11216 return directionToFaceDirection(normalViewGeometry); 11217 } 11218 /** 11219 * Overwritten since this type of material uses {@link BasicEnvironmentNode} 11220 * to implement the default environment mapping. 11221 * 11222 * @param {NodeBuilder} builder - The current node builder. 11223 * @return {?BasicEnvironmentNode<vec3>} The environment node. 11224 */ 11225 setupEnvironment(builder) { 11226 const envNode = super.setupEnvironment(builder); 11227 return envNode ? new BasicEnvironmentNode(envNode) : null; 11228 } 11229 /** 11230 * This method must be overwritten since light maps are evaluated 11231 * with a special scaling factor for basic materials. 11232 * 11233 * @param {NodeBuilder} builder - The current node builder. 11234 * @return {?BasicLightMapNode<vec3>} The light map node. 11235 */ 11236 setupLightMap(builder) { 11237 let node = null; 11238 if (builder.material.lightMap) { 11239 node = new BasicLightMapNode(materialLightMap); 11240 } 11241 return node; 11242 } 11243 /** 11244 * The material overwrites this method because `lights` is set to `true` but 11245 * we still want to return the diffuse color as the outgoing light. 11246 * 11247 * @return {Node<vec3>} The outgoing light node. 11248 */ 11249 setupOutgoingLight() { 11250 return diffuseColor.rgb; 11251 } 11252 /** 11253 * Setups the lighting model. 11254 * 11255 * @return {BasicLightingModel} The lighting model. 11256 */ 11257 setupLightingModel() { 11258 return new BasicLightingModel(); 11259 } 11260}; 11261var F_Schlick = /* @__PURE__ */ Fn(({ f0, f90, dotVH }) => { 11262 const fresnel = dotVH.mul(-5.55473).sub(6.98316).mul(dotVH).exp2(); 11263 return f0.mul(fresnel.oneMinus()).add(f90.mul(fresnel)); 11264}); 11265var BRDF_Lambert = /* @__PURE__ */ Fn((inputs) => { 11266 return inputs.diffuseColor.mul(1 / Math.PI); 11267}); 11268var G_BlinnPhong_Implicit = () => float(0.25); 11269var D_BlinnPhong = /* @__PURE__ */ Fn(({ dotNH }) => { 11270 return shininess.mul(float(0.5)).add(1).mul(float(1 / Math.PI)).mul(dotNH.pow(shininess)); 11271}); 11272var BRDF_BlinnPhong = /* @__PURE__ */ Fn(({ lightDirection }) => { 11273 const halfDir = lightDirection.add(positionViewDirection).normalize(); 11274 const dotNH = normalView.dot(halfDir).clamp(); 11275 const dotVH = positionViewDirection.dot(halfDir).clamp(); 11276 const F = F_Schlick({ f0: specularColor, f90: 1, dotVH }); 11277 const G = G_BlinnPhong_Implicit(); 11278 const D = D_BlinnPhong({ dotNH }); 11279 return F.mul(G).mul(D); 11280}); 11281var PhongLightingModel = class extends BasicLightingModel { 11282 /** 11283 * Constructs a new phong lighting model. 11284 * 11285 * @param {boolean} [specular=true] - Whether specular is supported or not. 11286 */ 11287 constructor(specular = true) { 11288 super(); 11289 this.specular = specular; 11290 } 11291 /** 11292 * Implements the direct lighting. The specular portion is optional an can be controlled 11293 * with the {@link PhongLightingModel#specular} flag. 11294 * 11295 * @param {Object} lightData - The light data. 11296 */ 11297 direct({ lightDirection, lightColor, reflectedLight }) { 11298 const dotNL = normalView.dot(lightDirection).clamp(); 11299 const irradiance = dotNL.mul(lightColor); 11300 reflectedLight.directDiffuse.addAssign(irradiance.mul(BRDF_Lambert({ diffuseColor: diffuseColor.rgb }))); 11301 if (this.specular === true) { 11302 reflectedLight.directSpecular.addAssign(irradiance.mul(BRDF_BlinnPhong({ lightDirection })).mul(materialSpecularStrength)); 11303 } 11304 } 11305 /** 11306 * Implements the indirect lighting. 11307 * 11308 * @param {NodeBuilder} builder - The current node builder. 11309 */ 11310 indirect(builder) { 11311 const { ambientOcclusion, irradiance, reflectedLight } = builder.context; 11312 reflectedLight.indirectDiffuse.addAssign(irradiance.mul(BRDF_Lambert({ diffuseColor }))); 11313 reflectedLight.indirectDiffuse.mulAssign(ambientOcclusion); 11314 } 11315}; 11316var _defaultValues$8 = /* @__PURE__ */ new MeshLambertMaterial(); 11317var MeshLambertNodeMaterial = class extends NodeMaterial { 11318 static get type() { 11319 return "MeshLambertNodeMaterial"; 11320 } 11321 /** 11322 * Constructs a new mesh lambert node material. 11323 * 11324 * @param {Object} [parameters] - The configuration parameter. 11325 */ 11326 constructor(parameters) { 11327 super(); 11328 this.isMeshLambertNodeMaterial = true; 11329 this.lights = true; 11330 this.setDefaultValues(_defaultValues$8); 11331 this.setValues(parameters); 11332 } 11333 /** 11334 * Overwritten since this type of material uses {@link BasicEnvironmentNode} 11335 * to implement the default environment mapping. 11336 * 11337 * @param {NodeBuilder} builder - The current node builder. 11338 * @return {?BasicEnvironmentNode<vec3>} The environment node. 11339 */ 11340 setupEnvironment(builder) { 11341 const envNode = super.setupEnvironment(builder); 11342 return envNode ? new BasicEnvironmentNode(envNode) : null; 11343 } 11344 /** 11345 * Setups the lighting model. 11346 * 11347 * @return {PhongLightingModel} The lighting model. 11348 */ 11349 setupLightingModel() { 11350 return new PhongLightingModel(false); 11351 } 11352}; 11353var _defaultValues$7 = /* @__PURE__ */ new MeshPhongMaterial(); 11354var MeshPhongNodeMaterial = class extends NodeMaterial { 11355 static get type() { 11356 return "MeshPhongNodeMaterial"; 11357 } 11358 /** 11359 * Constructs a new mesh lambert node material. 11360 * 11361 * @param {Object} [parameters] - The configuration parameter. 11362 */ 11363 constructor(parameters) { 11364 super(); 11365 this.isMeshPhongNodeMaterial = true; 11366 this.lights = true; 11367 this.shininessNode = null; 11368 this.specularNode = null; 11369 this.setDefaultValues(_defaultValues$7); 11370 this.setValues(parameters); 11371 } 11372 /** 11373 * Overwritten since this type of material uses {@link BasicEnvironmentNode} 11374 * to implement the default environment mapping. 11375 * 11376 * @param {NodeBuilder} builder - The current node builder. 11377 * @return {?BasicEnvironmentNode<vec3>} The environment node. 11378 */ 11379 setupEnvironment(builder) { 11380 const envNode = super.setupEnvironment(builder); 11381 return envNode ? new BasicEnvironmentNode(envNode) : null; 11382 } 11383 /** 11384 * Setups the lighting model. 11385 * 11386 * @return {PhongLightingModel} The lighting model. 11387 */ 11388 setupLightingModel() { 11389 return new PhongLightingModel(); 11390 } 11391 /** 11392 * Setups the phong specific node variables. 11393 * 11394 * @param {NodeBuilder} builder - The current node builder. 11395 */ 11396 setupVariants() { 11397 const shininessNode = (this.shininessNode ? float(this.shininessNode) : materialShininess).max(1e-4); 11398 shininess.assign(shininessNode); 11399 const specularNode = this.specularNode || materialSpecular; 11400 specularColor.assign(specularNode); 11401 } 11402 copy(source) { 11403 this.shininessNode = source.shininessNode; 11404 this.specularNode = source.specularNode; 11405 return super.copy(source); 11406 } 11407}; 11408var getGeometryRoughness = /* @__PURE__ */ Fn((builder) => { 11409 if (builder.geometry.hasAttribute("normal") === false) { 11410 return float(0); 11411 } 11412 const dxy = normalViewGeometry.dFdx().abs().max(normalViewGeometry.dFdy().abs()); 11413 const geometryRoughness = dxy.x.max(dxy.y).max(dxy.z); 11414 return geometryRoughness; 11415}); 11416var getRoughness = /* @__PURE__ */ Fn((inputs) => { 11417 const { roughness: roughness3 } = inputs; 11418 const geometryRoughness = getGeometryRoughness(); 11419 let roughnessFactor = roughness3.max(0.0525); 11420 roughnessFactor = roughnessFactor.add(geometryRoughness); 11421 roughnessFactor = roughnessFactor.min(1); 11422 return roughnessFactor; 11423}); 11424var V_GGX_SmithCorrelated = /* @__PURE__ */ Fn(({ alpha, dotNL, dotNV }) => { 11425 const a2 = alpha.pow2(); 11426 const gv = dotNL.mul(a2.add(a2.oneMinus().mul(dotNV.pow2())).sqrt()); 11427 const gl = dotNV.mul(a2.add(a2.oneMinus().mul(dotNL.pow2())).sqrt()); 11428 return div(0.5, gv.add(gl).max(EPSILON)); 11429}).setLayout({ 11430 name: "V_GGX_SmithCorrelated", 11431 type: "float", 11432 inputs: [ 11433 { name: "alpha", type: "float" }, 11434 { name: "dotNL", type: "float" }, 11435 { name: "dotNV", type: "float" } 11436 ] 11437}); 11438var V_GGX_SmithCorrelated_Anisotropic = /* @__PURE__ */ Fn(({ alphaT: alphaT3, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL }) => { 11439 const gv = dotNL.mul(vec3(alphaT3.mul(dotTV), alphaB.mul(dotBV), dotNV).length()); 11440 const gl = dotNV.mul(vec3(alphaT3.mul(dotTL), alphaB.mul(dotBL), dotNL).length()); 11441 return div(0.5, gv.add(gl).max(EPSILON)); 11442}).setLayout({ 11443 name: "V_GGX_SmithCorrelated_Anisotropic", 11444 type: "float", 11445 inputs: [ 11446 { name: "alphaT", type: "float", qualifier: "in" }, 11447 { name: "alphaB", type: "float", qualifier: "in" }, 11448 { name: "dotTV", type: "float", qualifier: "in" }, 11449 { name: "dotBV", type: "float", qualifier: "in" }, 11450 { name: "dotTL", type: "float", qualifier: "in" }, 11451 { name: "dotBL", type: "float", qualifier: "in" }, 11452 { name: "dotNV", type: "float", qualifier: "in" }, 11453 { name: "dotNL", type: "float", qualifier: "in" } 11454 ] 11455}); 11456var D_GGX = /* @__PURE__ */ Fn(({ alpha, dotNH }) => { 11457 const a2 = alpha.pow2(); 11458 const denom = dotNH.pow2().mul(a2.oneMinus()).oneMinus(); 11459 return a2.div(denom.pow2()).mul(1 / Math.PI); 11460}).setLayout({ 11461 name: "D_GGX", 11462 type: "float", 11463 inputs: [ 11464 { name: "alpha", type: "float" }, 11465 { name: "dotNH", type: "float" } 11466 ] 11467}); 11468var RECIPROCAL_PI = /* @__PURE__ */ float(1 / Math.PI); 11469var D_GGX_Anisotropic = /* @__PURE__ */ Fn(({ alphaT: alphaT3, alphaB, dotNH, dotTH, dotBH }) => { 11470 const a2 = alphaT3.mul(alphaB); 11471 const v = vec3(alphaB.mul(dotTH), alphaT3.mul(dotBH), a2.mul(dotNH)); 11472 const v2 = v.dot(v); 11473 const w22 = a2.div(v2); 11474 return RECIPROCAL_PI.mul(a2.mul(w22.pow2())); 11475}).setLayout({ 11476 name: "D_GGX_Anisotropic", 11477 type: "float", 11478 inputs: [ 11479 { name: "alphaT", type: "float", qualifier: "in" }, 11480 { name: "alphaB", type: "float", qualifier: "in" }, 11481 { name: "dotNH", type: "float", qualifier: "in" }, 11482 { name: "dotTH", type: "float", qualifier: "in" }, 11483 { name: "dotBH", type: "float", qualifier: "in" } 11484 ] 11485}); 11486var BRDF_GGX = /* @__PURE__ */ Fn(({ lightDirection, f0, f90, roughness: roughness3, f, normalView: normalView$1 = normalView, USE_IRIDESCENCE, USE_ANISOTROPY }) => { 11487 const alpha = roughness3.pow2(); 11488 const halfDir = lightDirection.add(positionViewDirection).normalize(); 11489 const dotNL = normalView$1.dot(lightDirection).clamp(); 11490 const dotNV = normalView$1.dot(positionViewDirection).clamp(); 11491 const dotNH = normalView$1.dot(halfDir).clamp(); 11492 const dotVH = positionViewDirection.dot(halfDir).clamp(); 11493 let F = F_Schlick({ f0, f90, dotVH }); 11494 let V, D; 11495 if (defined(USE_IRIDESCENCE)) { 11496 F = iridescence.mix(F, f); 11497 } 11498 if (defined(USE_ANISOTROPY)) { 11499 const dotTL = anisotropyT.dot(lightDirection); 11500 const dotTV = anisotropyT.dot(positionViewDirection); 11501 const dotTH = anisotropyT.dot(halfDir); 11502 const dotBL = anisotropyB.dot(lightDirection); 11503 const dotBV = anisotropyB.dot(positionViewDirection); 11504 const dotBH = anisotropyB.dot(halfDir); 11505 V = V_GGX_SmithCorrelated_Anisotropic({ alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL }); 11506 D = D_GGX_Anisotropic({ alphaT, alphaB: alpha, dotNH, dotTH, dotBH }); 11507 } else { 11508 V = V_GGX_SmithCorrelated({ alpha, dotNL, dotNV }); 11509 D = D_GGX({ alpha, dotNH }); 11510 } 11511 return F.mul(V).mul(D); 11512}); 11513var DATA = new Uint16Array([ 11514 12469, 11515 15057, 11516 12620, 11517 14925, 11518 13266, 11519 14620, 11520 13807, 11521 14376, 11522 14323, 11523 13990, 11524 14545, 11525 13625, 11526 14713, 11527 13328, 11528 14840, 11529 12882, 11530 14931, 11531 12528, 11532 14996, 11533 12233, 11534 15039, 11535 11829, 11536 15066, 11537 11525, 11538 15080, 11539 11295, 11540 15085, 11541 10976, 11542 15082, 11543 10705, 11544 15073, 11545 10495, 11546 13880, 11547 14564, 11548 13898, 11549 14542, 11550 13977, 11551 14430, 11552 14158, 11553 14124, 11554 14393, 11555 13732, 11556 14556, 11557 13410, 11558 14702, 11559 12996, 11560 14814, 11561 12596, 11562 14891, 11563 12291, 11564 14937, 11565 11834, 11566 14957, 11567 11489, 11568 14958, 11569 11194, 11570 14943, 11571 10803, 11572 14921, 11573 10506, 11574 14893, 11575 10278, 11576 14858, 11577 9960, 11578 14484, 11579 14039, 11580 14487, 11581 14025, 11582 14499, 11583 13941, 11584 14524, 11585 13740, 11586 14574, 11587 13468, 11588 14654, 11589 13106, 11590 14743, 11591 12678, 11592 14818, 11593 12344, 11594 14867, 11595 11893, 11596 14889, 11597 11509, 11598 14893, 11599 11180, 11600 14881, 11601 10751, 11602 14852, 11603 10428, 11604 14812, 11605 10128, 11606 14765, 11607 9754, 11608 14712, 11609 9466, 11610 14764, 11611 13480, 11612 14764, 11613 13475, 11614 14766, 11615 13440, 11616 14766, 11617 13347, 11618 14769, 11619 13070, 11620 14786, 11621 12713, 11622 14816, 11623 12387, 11624 14844, 11625 11957, 11626 14860, 11627 11549, 11628 14868, 11629 11215, 11630 14855, 11631 10751, 11632 14825, 11633 10403, 11634 14782, 11635 10044, 11636 14729, 11637 9651, 11638 14666, 11639 9352, 11640 14599, 11641 9029, 11642 14967, 11643 12835, 11644 14966, 11645 12831, 11646 14963, 11647 12804, 11648 14954, 11649 12723, 11650 14936, 11651 12564, 11652 14917, 11653 12347, 11654 14900, 11655 11958, 11656 14886, 11657 11569, 11658 14878, 11659 11247, 11660 14859, 11661 10765, 11662 14828, 11663 10401, 11664 14784, 11665 10011, 11666 14727, 11667 9600, 11668 14660, 11669 9289, 11670 14586, 11671 8893, 11672 14508, 11673 8533, 11674 15111, 11675 12234, 11676 15110, 11677 12234, 11678 15104, 11679 12216, 11680 15092, 11681 12156, 11682 15067, 11683 12010, 11684 15028, 11685 11776, 11686 14981, 11687 11500, 11688 14942, 11689 11205, 11690 14902, 11691 10752, 11692 14861, 11693 10393, 11694 14812, 11695 9991, 11696 14752, 11697 9570, 11698 14682, 11699 9252, 11700 14603, 11701 8808, 11702 14519, 11703 8445, 11704 14431, 11705 8145, 11706 15209, 11707 11449, 11708 15208, 11709 11451, 11710 15202, 11711 11451, 11712 15190, 11713 11438, 11714 15163, 11715 11384, 11716 15117, 11717 11274, 11718 15055, 11719 10979, 11720 14994, 11721 10648, 11722 14932, 11723 10343, 11724 14871, 11725 9936, 11726 14803, 11727 9532, 11728 14729, 11729 9218, 11730 14645, 11731 8742, 11732 14556, 11733 8381, 11734 14461, 11735 8020, 11736 14365, 11737 7603, 11738 15273, 11739 10603, 11740 15272, 11741 10607, 11742 15267, 11743 10619, 11744 15256, 11745 10631, 11746 15231, 11747 10614, 11748 15182, 11749 10535, 11750 15118, 11751 10389, 11752 15042, 11753 10167, 11754 14963, 11755 9787, 11756 14883, 11757 9447, 11758 14800, 11759 9115, 11760 14710, 11761 8665, 11762 14615, 11763 8318, 11764 14514, 11765 7911, 11766 14411, 11767 7507, 11768 14279, 11769 7198, 11770 15314, 11771 9675, 11772 15313, 11773 9683, 11774 15309, 11775 9712, 11776 15298, 11777 9759, 11778 15277, 11779 9797, 11780 15229, 11781 9773, 11782 15166, 11783 9668, 11784 15084, 11785 9487, 11786 14995, 11787 9274, 11788 14898, 11789 8910, 11790 14800, 11791 8539, 11792 14697, 11793 8234, 11794 14590, 11795 7790, 11796 14479, 11797 7409, 11798 14367, 11799 7067, 11800 14178, 11801 6621, 11802 15337, 11803 8619, 11804 15337, 11805 8631, 11806 15333, 11807 8677, 11808 15325, 11809 8769, 11810 15305, 11811 8871, 11812 15264, 11813 8940, 11814 15202, 11815 8909, 11816 15119, 11817 8775, 11818 15022, 11819 8565, 11820 14916, 11821 8328, 11822 14804, 11823 8009, 11824 14688, 11825 7614, 11826 14569, 11827 7287, 11828 14448, 11829 6888, 11830 14321, 11831 6483, 11832 14088, 11833 6171, 11834 15350, 11835 7402, 11836 15350, 11837 7419, 11838 15347, 11839 7480, 11840 15340, 11841 7613, 11842 15322, 11843 7804, 11844 15287, 11845 7973, 11846 15229, 11847 8057, 11848 15148, 11849 8012, 11850 15046, 11851 7846, 11852 14933, 11853 7611, 11854 14810, 11855 7357, 11856 14682, 11857 7069, 11858 14552, 11859 6656, 11860 14421, 11861 6316, 11862 14251, 11863 5948, 11864 14007, 11865 5528, 11866 15356, 11867 5942, 11868 15356, 11869 5977, 11870 15353, 11871 6119, 11872 15348, 11873 6294, 11874 15332, 11875 6551, 11876 15302, 11877 6824, 11878 15249, 11879 7044, 11880 15171, 11881 7122, 11882 15070, 11883 7050, 11884 14949, 11885 6861, 11886 14818, 11887 6611, 11888 14679, 11889 6349, 11890 14538, 11891 6067, 11892 14398, 11893 5651, 11894 14189, 11895 5311, 11896 13935, 11897 4958, 11898 15359, 11899 4123, 11900 15359, 11901 4153, 11902 15356, 11903 4296, 11904 15353, 11905 4646, 11906 15338, 11907 5160, 11908 15311, 11909 5508, 11910 15263, 11911 5829, 11912 15188, 11913 6042, 11914 15088, 11915 6094, 11916 14966, 11917 6001, 11918 14826, 11919 5796, 11920 14678, 11921 5543, 11922 14527, 11923 5287, 11924 14377, 11925 4985, 11926 14133, 11927 4586, 11928 13869, 11929 4257, 11930 15360, 11931 1563, 11932 15360, 11933 1642, 11934 15358, 11935 2076, 11936 15354, 11937 2636, 11938 15341, 11939 3350, 11940 15317, 11941 4019, 11942 15273, 11943 4429, 11944 15203, 11945 4732, 11946 15105, 11947 4911, 11948 14981, 11949 4932, 11950 14836, 11951 4818, 11952 14679, 11953 4621, 11954 14517, 11955 4386, 11956 14359, 11957 4156, 11958 14083, 11959 3795, 11960 13808, 11961 3437, 11962 15360, 11963 122, 11964 15360, 11965 137, 11966 15358, 11967 285, 11968 15355, 11969 636, 11970 15344, 11971 1274, 11972 15322, 11973 2177, 11974 15281, 11975 2765, 11976 15215, 11977 3223, 11978 15120, 11979 3451, 11980 14995, 11981 3569, 11982 14846, 11983 3567, 11984 14681, 11985 3466, 11986 14511, 11987 3305, 11988 14344, 11989 3121, 11990 14037, 11991 2800, 11992 13753, 11993 2467, 11994 15360, 11995 0, 11996 15360, 11997 1, 11998 15359, 11999 21, 12000 15355, 12001 89, 12002 15346, 12003 253, 12004 15325, 12005 479, 12006 15287, 12007 796, 12008 15225, 12009 1148, 12010 15133, 12011 1492, 12012 15008, 12013 1749, 12014 14856, 12015 1882, 12016 14685, 12017 1886, 12018 14506, 12019 1783, 12020 14324, 12021 1608, 12022 13996, 12023 1398, 12024 13702, 12025 1183 12026]); 12027var lut = null; 12028var DFGLUT = /* @__PURE__ */ Fn(({ roughness: roughness3, dotNV }) => { 12029 if (lut === null) { 12030 lut = new DataTexture(DATA, 16, 16, RGFormat, HalfFloatType); 12031 lut.name = "DFG_LUT"; 12032 lut.minFilter = LinearFilter; 12033 lut.magFilter = LinearFilter; 12034 lut.wrapS = ClampToEdgeWrapping; 12035 lut.wrapT = ClampToEdgeWrapping; 12036 lut.generateMipmaps = false; 12037 lut.needsUpdate = true; 12038 } 12039 const uv3 = vec2(roughness3, dotNV); 12040 return texture(lut, uv3).rg; 12041}); 12042var BRDF_GGX_Multiscatter = /* @__PURE__ */ Fn(({ lightDirection, f0, f90, roughness: _roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY }) => { 12043 const singleScatter = BRDF_GGX({ lightDirection, f0, f90, roughness: _roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY }); 12044 const dotNL = normalView.dot(lightDirection).clamp(); 12045 const dotNV = normalView.dot(positionViewDirection).clamp(); 12046 const dfgV = DFGLUT({ roughness: _roughness, dotNV }); 12047 const dfgL = DFGLUT({ roughness: _roughness, dotNV: dotNL }); 12048 const FssEss_V = f0.mul(dfgV.x).add(f90.mul(dfgV.y)); 12049 const FssEss_L = f0.mul(dfgL.x).add(f90.mul(dfgL.y)); 12050 const Ess_V = dfgV.x.add(dfgV.y); 12051 const Ess_L = dfgL.x.add(dfgL.y); 12052 const Ems_V = float(1).sub(Ess_V); 12053 const Ems_L = float(1).sub(Ess_L); 12054 const Favg = f0.add(f0.oneMinus().mul(0.047619)); 12055 const Fms = FssEss_V.mul(FssEss_L).mul(Favg).div(float(1).sub(Ems_V.mul(Ems_L).mul(Favg).mul(Favg)).add(EPSILON)); 12056 const compensationFactor = Ems_V.mul(Ems_L); 12057 const multiScatter = Fms.mul(compensationFactor); 12058 return singleScatter.add(multiScatter); 12059}); 12060var EnvironmentBRDF = /* @__PURE__ */ Fn((inputs) => { 12061 const { dotNV, specularColor: specularColor3, specularF90: specularF903, roughness: roughness3 } = inputs; 12062 const fab = DFGLUT({ dotNV, roughness: roughness3 }); 12063 return specularColor3.mul(fab.x).add(specularF903.mul(fab.y)); 12064}); 12065var Schlick_to_F0 = /* @__PURE__ */ Fn(({ f, f90, dotVH }) => { 12066 const x = dotVH.oneMinus().saturate(); 12067 const x2 = x.mul(x); 12068 const x5 = x.mul(x2, x2).clamp(0, 0.9999); 12069 return f.sub(vec3(f90).mul(x5)).div(x5.oneMinus()); 12070}).setLayout({ 12071 name: "Schlick_to_F0", 12072 type: "vec3", 12073 inputs: [ 12074 { name: "f", type: "vec3" }, 12075 { name: "f90", type: "float" }, 12076 { name: "dotVH", type: "float" } 12077 ] 12078}); 12079var D_Charlie = /* @__PURE__ */ Fn(({ roughness: roughness3, dotNH }) => { 12080 const alpha = roughness3.pow2(); 12081 const invAlpha = float(1).div(alpha); 12082 const cos2h = dotNH.pow2(); 12083 const sin2h = cos2h.oneMinus().max(78125e-7); 12084 return float(2).add(invAlpha).mul(sin2h.pow(invAlpha.mul(0.5))).div(2 * Math.PI); 12085}).setLayout({ 12086 name: "D_Charlie", 12087 type: "float", 12088 inputs: [ 12089 { name: "roughness", type: "float" }, 12090 { name: "dotNH", type: "float" } 12091 ] 12092}); 12093var V_Neubelt = /* @__PURE__ */ Fn(({ dotNV, dotNL }) => { 12094 return float(1).div(float(4).mul(dotNL.add(dotNV).sub(dotNL.mul(dotNV)))); 12095}).setLayout({ 12096 name: "V_Neubelt", 12097 type: "float", 12098 inputs: [ 12099 { name: "dotNV", type: "float" }, 12100 { name: "dotNL", type: "float" } 12101 ] 12102}); 12103var BRDF_Sheen = /* @__PURE__ */ Fn(({ lightDirection }) => { 12104 const halfDir = lightDirection.add(positionViewDirection).normalize(); 12105 const dotNL = normalView.dot(lightDirection).clamp(); 12106 const dotNV = normalView.dot(positionViewDirection).clamp(); 12107 const dotNH = normalView.dot(halfDir).clamp(); 12108 const D = D_Charlie({ roughness: sheenRoughness, dotNH }); 12109 const V = V_Neubelt({ dotNV, dotNL }); 12110 return sheen.mul(D).mul(V); 12111}); 12112var LTC_Uv = /* @__PURE__ */ Fn(({ N: N2, V, roughness: roughness3 }) => { 12113 const LUT_SIZE = 64; 12114 const LUT_SCALE = (LUT_SIZE - 1) / LUT_SIZE; 12115 const LUT_BIAS = 0.5 / LUT_SIZE; 12116 const dotNV = N2.dot(V).saturate(); 12117 const uv3 = vec2(roughness3, dotNV.oneMinus().sqrt()); 12118 uv3.assign(uv3.mul(LUT_SCALE).add(LUT_BIAS)); 12119 return uv3; 12120}).setLayout({ 12121 name: "LTC_Uv", 12122 type: "vec2", 12123 inputs: [ 12124 { name: "N", type: "vec3" }, 12125 { name: "V", type: "vec3" }, 12126 { name: "roughness", type: "float" } 12127 ] 12128}); 12129var LTC_ClippedSphereFormFactor = /* @__PURE__ */ Fn(({ f }) => { 12130 const l = f.length(); 12131 return max$1(l.mul(l).add(f.z).div(l.add(1)), 0); 12132}).setLayout({ 12133 name: "LTC_ClippedSphereFormFactor", 12134 type: "float", 12135 inputs: [ 12136 { name: "f", type: "vec3" } 12137 ] 12138}); 12139var LTC_EdgeVectorFormFactor = /* @__PURE__ */ Fn(({ v1, v2 }) => { 12140 const x = v1.dot(v2); 12141 const y = x.abs().toVar(); 12142 const a = y.mul(0.0145206).add(0.4965155).mul(y).add(0.8543985).toVar(); 12143 const b = y.add(4.1616724).mul(y).add(3.417594).toVar(); 12144 const v = a.div(b); 12145 const theta_sintheta = x.greaterThan(0).select(v, max$1(x.mul(x).oneMinus(), 1e-7).inverseSqrt().mul(0.5).sub(v)); 12146 return v1.cross(v2).mul(theta_sintheta); 12147}).setLayout({ 12148 name: "LTC_EdgeVectorFormFactor", 12149 type: "vec3", 12150 inputs: [ 12151 { name: "v1", type: "vec3" }, 12152 { name: "v2", type: "vec3" } 12153 ] 12154}); 12155var LTC_Evaluate = /* @__PURE__ */ Fn(({ N: N2, V, P, mInv, p0, p1, p2, p3 }) => { 12156 const v1 = p1.sub(p0).toVar(); 12157 const v2 = p3.sub(p0).toVar(); 12158 const lightNormal = v1.cross(v2); 12159 const result = vec3().toVar(); 12160 If(lightNormal.dot(P.sub(p0)).greaterThanEqual(0), () => { 12161 const T1 = V.sub(N2.mul(V.dot(N2))).normalize(); 12162 const T22 = N2.cross(T1).negate(); 12163 const mat = mInv.mul(mat3(T1, T22, N2).transpose()).toVar(); 12164 const coords0 = mat.mul(p0.sub(P)).normalize().toVar(); 12165 const coords1 = mat.mul(p1.sub(P)).normalize().toVar(); 12166 const coords2 = mat.mul(p2.sub(P)).normalize().toVar(); 12167 const coords3 = mat.mul(p3.sub(P)).normalize().toVar(); 12168 const vectorFormFactor = vec3(0).toVar(); 12169 vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({ v1: coords0, v2: coords1 })); 12170 vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({ v1: coords1, v2: coords2 })); 12171 vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({ v1: coords2, v2: coords3 })); 12172 vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({ v1: coords3, v2: coords0 })); 12173 result.assign(vec3(LTC_ClippedSphereFormFactor({ f: vectorFormFactor }))); 12174 }); 12175 return result; 12176}).setLayout({ 12177 name: "LTC_Evaluate", 12178 type: "vec3", 12179 inputs: [ 12180 { name: "N", type: "vec3" }, 12181 { name: "V", type: "vec3" }, 12182 { name: "P", type: "vec3" }, 12183 { name: "mInv", type: "mat3" }, 12184 { name: "p0", type: "vec3" }, 12185 { name: "p1", type: "vec3" }, 12186 { name: "p2", type: "vec3" }, 12187 { name: "p3", type: "vec3" } 12188 ] 12189}); 12190var bC = 1 / 6; 12191var w0 = (a) => mul(bC, mul(a, mul(a, a.negate().add(3)).sub(3)).add(1)); 12192var w1 = (a) => mul(bC, mul(a, mul(a, mul(3, a).sub(6))).add(4)); 12193var w2 = (a) => mul(bC, mul(a, mul(a, mul(-3, a).add(3)).add(3)).add(1)); 12194var w3 = (a) => mul(bC, pow(a, 3)); 12195var g0 = (a) => w0(a).add(w1(a)); 12196var g1 = (a) => w2(a).add(w3(a)); 12197var h0 = (a) => add(-1, w1(a).div(w0(a).add(w1(a)))); 12198var h1 = (a) => add(1, w3(a).div(w2(a).add(w3(a)))); 12199var bicubic = (textureNode, texelSize, lod) => { 12200 const uv3 = textureNode.uvNode; 12201 const uvScaled = mul(uv3, texelSize.zw).add(0.5); 12202 const iuv = floor(uvScaled); 12203 const fuv = fract(uvScaled); 12204 const g0x = g0(fuv.x); 12205 const g1x = g1(fuv.x); 12206 const h0x = h0(fuv.x); 12207 const h1x = h1(fuv.x); 12208 const h0y = h0(fuv.y); 12209 const h1y = h1(fuv.y); 12210 const p0 = vec2(iuv.x.add(h0x), iuv.y.add(h0y)).sub(0.5).mul(texelSize.xy); 12211 const p1 = vec2(iuv.x.add(h1x), iuv.y.add(h0y)).sub(0.5).mul(texelSize.xy); 12212 const p2 = vec2(iuv.x.add(h0x), iuv.y.add(h1y)).sub(0.5).mul(texelSize.xy); 12213 const p3 = vec2(iuv.x.add(h1x), iuv.y.add(h1y)).sub(0.5).mul(texelSize.xy); 12214 const a = g0(fuv.y).mul(add(g0x.mul(textureNode.sample(p0).level(lod)), g1x.mul(textureNode.sample(p1).level(lod)))); 12215 const b = g1(fuv.y).mul(add(g0x.mul(textureNode.sample(p2).level(lod)), g1x.mul(textureNode.sample(p3).level(lod)))); 12216 return a.add(b); 12217}; 12218var textureBicubicLevel = /* @__PURE__ */ Fn(([textureNode, lodNode]) => { 12219 const fLodSize = vec2(textureNode.size(int(lodNode))); 12220 const cLodSize = vec2(textureNode.size(int(lodNode.add(1)))); 12221 const fLodSizeInv = div(1, fLodSize); 12222 const cLodSizeInv = div(1, cLodSize); 12223 const fSample = bicubic(textureNode, vec4(fLodSizeInv, fLodSize), floor(lodNode)); 12224 const cSample = bicubic(textureNode, vec4(cLodSizeInv, cLodSize), ceil(lodNode)); 12225 return fract(lodNode).mix(fSample, cSample); 12226}); 12227var textureBicubic = /* @__PURE__ */ Fn(([textureNode, strength]) => { 12228 const lod = strength.mul(maxMipLevel(textureNode)); 12229 return textureBicubicLevel(textureNode, lod); 12230}); 12231var getVolumeTransmissionRay = /* @__PURE__ */ Fn(([n, v, thickness3, ior3, modelMatrix]) => { 12232 const refractionVector = vec3(refract(v.negate(), normalize(n), div(1, ior3))); 12233 const modelScale3 = vec3( 12234 length(modelMatrix[0].xyz), 12235 length(modelMatrix[1].xyz), 12236 length(modelMatrix[2].xyz) 12237 ); 12238 return normalize(refractionVector).mul(thickness3.mul(modelScale3)); 12239}).setLayout({ 12240 name: "getVolumeTransmissionRay", 12241 type: "vec3", 12242 inputs: [ 12243 { name: "n", type: "vec3" }, 12244 { name: "v", type: "vec3" }, 12245 { name: "thickness", type: "float" }, 12246 { name: "ior", type: "float" }, 12247 { name: "modelMatrix", type: "mat4" } 12248 ] 12249}); 12250var applyIorToRoughness = /* @__PURE__ */ Fn(([roughness3, ior3]) => { 12251 return roughness3.mul(clamp(ior3.mul(2).sub(2), 0, 1)); 12252}).setLayout({ 12253 name: "applyIorToRoughness", 12254 type: "float", 12255 inputs: [ 12256 { name: "roughness", type: "float" }, 12257 { name: "ior", type: "float" } 12258 ] 12259}); 12260var viewportBackSideTexture = /* @__PURE__ */ viewportMipTexture(); 12261var viewportFrontSideTexture = /* @__PURE__ */ viewportOpaqueMipTexture(); 12262var getTransmissionSample = /* @__PURE__ */ Fn(([fragCoord, roughness3, ior3], { material }) => { 12263 const vTexture = material.side === BackSide ? viewportBackSideTexture : viewportFrontSideTexture; 12264 const transmissionSample = vTexture.sample(fragCoord); 12265 const lod = log22(screenSize.x).mul(applyIorToRoughness(roughness3, ior3)); 12266 return textureBicubicLevel(transmissionSample, lod); 12267}); 12268var volumeAttenuation = /* @__PURE__ */ Fn(([transmissionDistance, attenuationColor3, attenuationDistance3]) => { 12269 If(attenuationDistance3.notEqual(0), () => { 12270 const attenuationCoefficient = log2(attenuationColor3).negate().div(attenuationDistance3); 12271 const transmittance = exp(attenuationCoefficient.negate().mul(transmissionDistance)); 12272 return transmittance; 12273 }); 12274 return vec3(1); 12275}).setLayout({ 12276 name: "volumeAttenuation", 12277 type: "vec3", 12278 inputs: [ 12279 { name: "transmissionDistance", type: "float" }, 12280 { name: "attenuationColor", type: "vec3" }, 12281 { name: "attenuationDistance", type: "float" } 12282 ] 12283}); 12284var getIBLVolumeRefraction = /* @__PURE__ */ Fn(([n, v, roughness3, diffuseColor3, specularColor3, specularF903, position, modelMatrix, viewMatrix, projMatrix, ior3, thickness3, attenuationColor3, attenuationDistance3, dispersion3]) => { 12285 let transmittedLight, transmittance; 12286 if (dispersion3) { 12287 transmittedLight = vec4().toVar(); 12288 transmittance = vec3().toVar(); 12289 const halfSpread = ior3.sub(1).mul(dispersion3.mul(0.025)); 12290 const iors = vec3(ior3.sub(halfSpread), ior3, ior3.add(halfSpread)); 12291 Loop({ start: 0, end: 3 }, ({ i }) => { 12292 const ior4 = iors.element(i); 12293 const transmissionRay = getVolumeTransmissionRay(n, v, thickness3, ior4, modelMatrix); 12294 const refractedRayExit = position.add(transmissionRay); 12295 const ndcPos = projMatrix.mul(viewMatrix.mul(vec4(refractedRayExit, 1))); 12296 const refractionCoords = vec2(ndcPos.xy.div(ndcPos.w)).toVar(); 12297 refractionCoords.addAssign(1); 12298 refractionCoords.divAssign(2); 12299 refractionCoords.assign(vec2(refractionCoords.x, refractionCoords.y.oneMinus())); 12300 const transmissionSample = getTransmissionSample(refractionCoords, roughness3, ior4); 12301 transmittedLight.element(i).assign(transmissionSample.element(i)); 12302 transmittedLight.a.addAssign(transmissionSample.a); 12303 transmittance.element(i).assign(diffuseColor3.element(i).mul(volumeAttenuation(length(transmissionRay), attenuationColor3, attenuationDistance3).element(i))); 12304 }); 12305 transmittedLight.a.divAssign(3); 12306 } else { 12307 const transmissionRay = getVolumeTransmissionRay(n, v, thickness3, ior3, modelMatrix); 12308 const refractedRayExit = position.add(transmissionRay); 12309 const ndcPos = projMatrix.mul(viewMatrix.mul(vec4(refractedRayExit, 1))); 12310 const refractionCoords = vec2(ndcPos.xy.div(ndcPos.w)).toVar(); 12311 refractionCoords.addAssign(1); 12312 refractionCoords.divAssign(2); 12313 refractionCoords.assign(vec2(refractionCoords.x, refractionCoords.y.oneMinus())); 12314 transmittedLight = getTransmissionSample(refractionCoords, roughness3, ior3); 12315 transmittance = diffuseColor3.mul(volumeAttenuation(length(transmissionRay), attenuationColor3, attenuationDistance3)); 12316 } 12317 const attenuatedColor = transmittance.rgb.mul(transmittedLight.rgb); 12318 const dotNV = n.dot(v).clamp(); 12319 const F = vec3(EnvironmentBRDF({ 12320 // n, v, specularColor, specularF90, roughness 12321 dotNV, 12322 specularColor: specularColor3, 12323 specularF90: specularF903, 12324 roughness: roughness3 12325 })); 12326 const transmittanceFactor = transmittance.r.add(transmittance.g, transmittance.b).div(3); 12327 return vec4(F.oneMinus().mul(attenuatedColor), transmittedLight.a.oneMinus().mul(transmittanceFactor).oneMinus()); 12328}); 12329var XYZ_TO_REC709 = /* @__PURE__ */ mat3( 12330 3.2404542, 12331 -0.969266, 12332 0.0556434, 12333 -1.5371385, 12334 1.8760108, 12335 -0.2040259, 12336 -0.4985314, 12337 0.041556, 12338 1.0572252 12339); 12340var Fresnel0ToIor = (fresnel0) => { 12341 const sqrtF0 = fresnel0.sqrt(); 12342 return vec3(1).add(sqrtF0).div(vec3(1).sub(sqrtF0)); 12343}; 12344var IorToFresnel0 = (transmittedIor, incidentIor) => { 12345 return transmittedIor.sub(incidentIor).div(transmittedIor.add(incidentIor)).pow2(); 12346}; 12347var evalSensitivity = (OPD, shift3) => { 12348 const phase = OPD.mul(2 * Math.PI * 1e-9); 12349 const val = vec3(54856e-17, 44201e-17, 52481e-17); 12350 const pos = vec3(1681e3, 1795300, 2208400); 12351 const VAR = vec3(43278e5, 93046e5, 66121e5); 12352 const x = float(9747e-17 * Math.sqrt(2 * Math.PI * 45282e5)).mul(phase.mul(2239900).add(shift3.x).cos()).mul(phase.pow2().mul(-45282e5).exp()); 12353 let xyz = val.mul(VAR.mul(2 * Math.PI).sqrt()).mul(pos.mul(phase).add(shift3).cos()).mul(phase.pow2().negate().mul(VAR).exp()); 12354 xyz = vec3(xyz.x.add(x), xyz.y, xyz.z).div(10685e-11); 12355 const rgb = XYZ_TO_REC709.mul(xyz); 12356 return rgb; 12357}; 12358var evalIridescence = /* @__PURE__ */ Fn(({ outsideIOR, eta2, cosTheta1, thinFilmThickness, baseF0 }) => { 12359 const iridescenceIOR3 = mix(outsideIOR, eta2, smoothstep(0, 0.03, thinFilmThickness)); 12360 const sinTheta2Sq = outsideIOR.div(iridescenceIOR3).pow2().mul(cosTheta1.pow2().oneMinus()); 12361 const cosTheta2Sq = sinTheta2Sq.oneMinus(); 12362 If(cosTheta2Sq.lessThan(0), () => { 12363 return vec3(1); 12364 }); 12365 const cosTheta2 = cosTheta2Sq.sqrt(); 12366 const R0 = IorToFresnel0(iridescenceIOR3, outsideIOR); 12367 const R12 = F_Schlick({ f0: R0, f90: 1, dotVH: cosTheta1 }); 12368 const T121 = R12.oneMinus(); 12369 const phi12 = iridescenceIOR3.lessThan(outsideIOR).select(Math.PI, 0); 12370 const phi21 = float(Math.PI).sub(phi12); 12371 const baseIOR = Fresnel0ToIor(baseF0.clamp(0, 0.9999)); 12372 const R1 = IorToFresnel0(baseIOR, iridescenceIOR3.toVec3()); 12373 const R23 = F_Schlick({ f0: R1, f90: 1, dotVH: cosTheta2 }); 12374 const phi23 = vec3( 12375 baseIOR.x.lessThan(iridescenceIOR3).select(Math.PI, 0), 12376 baseIOR.y.lessThan(iridescenceIOR3).select(Math.PI, 0), 12377 baseIOR.z.lessThan(iridescenceIOR3).select(Math.PI, 0) 12378 ); 12379 const OPD = iridescenceIOR3.mul(thinFilmThickness, cosTheta2, 2); 12380 const phi = vec3(phi21).add(phi23); 12381 const R123 = R12.mul(R23).clamp(1e-5, 0.9999); 12382 const r123 = R123.sqrt(); 12383 const Rs = T121.pow2().mul(R23).div(vec3(1).sub(R123)); 12384 const C0 = R12.add(Rs); 12385 const I = C0.toVar(); 12386 const Cm = Rs.sub(T121).toVar(); 12387 Loop({ start: 1, end: 2, condition: "<=", name: "m" }, ({ m }) => { 12388 Cm.mulAssign(r123); 12389 const Sm = evalSensitivity(float(m).mul(OPD), float(m).mul(phi)).mul(2); 12390 I.addAssign(Cm.mul(Sm)); 12391 }); 12392 return I.max(vec3(0)); 12393}).setLayout({ 12394 name: "evalIridescence", 12395 type: "vec3", 12396 inputs: [ 12397 { name: "outsideIOR", type: "float" }, 12398 { name: "eta2", type: "float" }, 12399 { name: "cosTheta1", type: "float" }, 12400 { name: "thinFilmThickness", type: "float" }, 12401 { name: "baseF0", type: "vec3" } 12402 ] 12403}); 12404var IBLSheenBRDF = /* @__PURE__ */ Fn(({ normal: normal2, viewDir, roughness: roughness3 }) => { 12405 const dotNV = normal2.dot(viewDir).saturate(); 12406 const r2 = roughness3.mul(roughness3); 12407 const rInv = roughness3.add(0.1).reciprocal(); 12408 const a = float(-1.9362).add(roughness3.mul(1.0678)).add(r2.mul(0.4573)).sub(rInv.mul(0.8469)); 12409 const b = float(-0.6014).add(roughness3.mul(0.5538)).sub(r2.mul(0.467)).sub(rInv.mul(0.1255)); 12410 const DG = a.mul(dotNV).add(b).exp(); 12411 return DG.saturate(); 12412}); 12413var clearcoatF0 = vec3(0.04); 12414var clearcoatF90 = float(1); 12415var PhysicalLightingModel = class extends LightingModel { 12416 /** 12417 * Constructs a new physical lighting model. 12418 * 12419 * @param {boolean} [clearcoat=false] - Whether clearcoat is supported or not. 12420 * @param {boolean} [sheen=false] - Whether sheen is supported or not. 12421 * @param {boolean} [iridescence=false] - Whether iridescence is supported or not. 12422 * @param {boolean} [anisotropy=false] - Whether anisotropy is supported or not. 12423 * @param {boolean} [transmission=false] - Whether transmission is supported or not. 12424 * @param {boolean} [dispersion=false] - Whether dispersion is supported or not. 12425 */ 12426 constructor(clearcoat3 = false, sheen3 = false, iridescence3 = false, anisotropy3 = false, transmission3 = false, dispersion3 = false) { 12427 super(); 12428 this.clearcoat = clearcoat3; 12429 this.sheen = sheen3; 12430 this.iridescence = iridescence3; 12431 this.anisotropy = anisotropy3; 12432 this.transmission = transmission3; 12433 this.dispersion = dispersion3; 12434 this.clearcoatRadiance = null; 12435 this.clearcoatSpecularDirect = null; 12436 this.clearcoatSpecularIndirect = null; 12437 this.sheenSpecularDirect = null; 12438 this.sheenSpecularIndirect = null; 12439 this.iridescenceFresnel = null; 12440 this.iridescenceF0 = null; 12441 this.iridescenceF0Dielectric = null; 12442 this.iridescenceF0Metallic = null; 12443 } 12444 /** 12445 * Depending on what features are requested, the method prepares certain node variables 12446 * which are later used for lighting computations. 12447 * 12448 * @param {NodeBuilder} builder - The current node builder. 12449 */ 12450 start(builder) { 12451 if (this.clearcoat === true) { 12452 this.clearcoatRadiance = vec3().toVar("clearcoatRadiance"); 12453 this.clearcoatSpecularDirect = vec3().toVar("clearcoatSpecularDirect"); 12454 this.clearcoatSpecularIndirect = vec3().toVar("clearcoatSpecularIndirect"); 12455 } 12456 if (this.sheen === true) { 12457 this.sheenSpecularDirect = vec3().toVar("sheenSpecularDirect"); 12458 this.sheenSpecularIndirect = vec3().toVar("sheenSpecularIndirect"); 12459 } 12460 if (this.iridescence === true) { 12461 const dotNVi = normalView.dot(positionViewDirection).clamp(); 12462 const iridescenceFresnelDielectric = evalIridescence({ 12463 outsideIOR: float(1), 12464 eta2: iridescenceIOR, 12465 cosTheta1: dotNVi, 12466 thinFilmThickness: iridescenceThickness, 12467 baseF0: specularColor 12468 }); 12469 const iridescenceFresnelMetallic = evalIridescence({ 12470 outsideIOR: float(1), 12471 eta2: iridescenceIOR, 12472 cosTheta1: dotNVi, 12473 thinFilmThickness: iridescenceThickness, 12474 baseF0: diffuseColor.rgb 12475 }); 12476 this.iridescenceFresnel = mix(iridescenceFresnelDielectric, iridescenceFresnelMetallic, metalness); 12477 this.iridescenceF0Dielectric = Schlick_to_F0({ f: iridescenceFresnelDielectric, f90: 1, dotVH: dotNVi }); 12478 this.iridescenceF0Metallic = Schlick_to_F0({ f: iridescenceFresnelMetallic, f90: 1, dotVH: dotNVi }); 12479 this.iridescenceF0 = mix(this.iridescenceF0Dielectric, this.iridescenceF0Metallic, metalness); 12480 } 12481 if (this.transmission === true) { 12482 const position = positionWorld; 12483 const v = cameraPosition.sub(positionWorld).normalize(); 12484 const n = normalWorld; 12485 const context3 = builder.context; 12486 context3.backdrop = getIBLVolumeRefraction( 12487 n, 12488 v, 12489 roughness, 12490 diffuseContribution, 12491 specularColorBlended, 12492 specularF90, 12493 // specularF90 12494 position, 12495 // positionWorld 12496 modelWorldMatrix, 12497 // modelMatrix 12498 cameraViewMatrix, 12499 // viewMatrix 12500 cameraProjectionMatrix, 12501 // projMatrix 12502 ior, 12503 thickness, 12504 attenuationColor, 12505 attenuationDistance, 12506 this.dispersion ? dispersion : null 12507 ); 12508 context3.backdropAlpha = transmission; 12509 diffuseColor.a.mulAssign(mix(1, context3.backdrop.a, transmission)); 12510 } 12511 super.start(builder); 12512 } 12513 // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" 12514 // Approximates multi-scattering in order to preserve energy. 12515 // http://www.jcgt.org/published/0008/01/03/ 12516 computeMultiscattering(singleScatter, multiScatter, specularF903, f0, iridescenceF0 = null) { 12517 const dotNV = normalView.dot(positionViewDirection).clamp(); 12518 const fab = DFGLUT({ roughness, dotNV }); 12519 const Fr = iridescenceF0 ? iridescence.mix(f0, iridescenceF0) : f0; 12520 const FssEss = Fr.mul(fab.x).add(specularF903.mul(fab.y)); 12521 const Ess = fab.x.add(fab.y); 12522 const Ems = Ess.oneMinus(); 12523 const Favg = Fr.add(Fr.oneMinus().mul(0.047619)); 12524 const Fms = FssEss.mul(Favg).div(Ems.mul(Favg).oneMinus()); 12525 singleScatter.addAssign(FssEss); 12526 multiScatter.addAssign(Fms.mul(Ems)); 12527 } 12528 /** 12529 * Implements the direct light. 12530 * 12531 * @param {Object} lightData - The light data. 12532 * @param {NodeBuilder} builder - The current node builder. 12533 */ 12534 direct({ lightDirection, lightColor, reflectedLight }) { 12535 const dotNL = normalView.dot(lightDirection).clamp(); 12536 const irradiance = dotNL.mul(lightColor).toVar(); 12537 if (this.sheen === true) { 12538 this.sheenSpecularDirect.addAssign(irradiance.mul(BRDF_Sheen({ lightDirection }))); 12539 const sheenAlbedoV = IBLSheenBRDF({ normal: normalView, viewDir: positionViewDirection, roughness: sheenRoughness }); 12540 const sheenAlbedoL = IBLSheenBRDF({ normal: normalView, viewDir: lightDirection, roughness: sheenRoughness }); 12541 const sheenEnergyComp = sheen.r.max(sheen.g).max(sheen.b).mul(sheenAlbedoV.max(sheenAlbedoL)).oneMinus(); 12542 irradiance.mulAssign(sheenEnergyComp); 12543 } 12544 if (this.clearcoat === true) { 12545 const dotNLcc = clearcoatNormalView.dot(lightDirection).clamp(); 12546 const ccIrradiance = dotNLcc.mul(lightColor); 12547 this.clearcoatSpecularDirect.addAssign(ccIrradiance.mul(BRDF_GGX({ lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: clearcoatNormalView }))); 12548 } 12549 reflectedLight.directDiffuse.addAssign(irradiance.mul(BRDF_Lambert({ diffuseColor: diffuseContribution }))); 12550 reflectedLight.directSpecular.addAssign(irradiance.mul(BRDF_GGX_Multiscatter({ lightDirection, f0: specularColorBlended, f90: 1, roughness, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy }))); 12551 } 12552 /** 12553 * This method is intended for implementing the direct light term for 12554 * rect area light nodes. 12555 * 12556 * @param {Object} input - The input data. 12557 * @param {NodeBuilder} builder - The current node builder. 12558 */ 12559 directRectArea({ lightColor, lightPosition: lightPosition3, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 }) { 12560 const p0 = lightPosition3.add(halfWidth).sub(halfHeight); 12561 const p1 = lightPosition3.sub(halfWidth).sub(halfHeight); 12562 const p2 = lightPosition3.sub(halfWidth).add(halfHeight); 12563 const p3 = lightPosition3.add(halfWidth).add(halfHeight); 12564 const N2 = normalView; 12565 const V = positionViewDirection; 12566 const P = positionView.toVar(); 12567 const uv3 = LTC_Uv({ N: N2, V, roughness }); 12568 const t1 = ltc_1.sample(uv3).toVar(); 12569 const t2 = ltc_2.sample(uv3).toVar(); 12570 const mInv = mat3( 12571 vec3(t1.x, 0, t1.y), 12572 vec3(0, 1, 0), 12573 vec3(t1.z, 0, t1.w) 12574 ).toVar(); 12575 const fresnel = specularColorBlended.mul(t2.x).add(specularF90.sub(specularColorBlended).mul(t2.y)).toVar(); 12576 reflectedLight.directSpecular.addAssign(lightColor.mul(fresnel).mul(LTC_Evaluate({ N: N2, V, P, mInv, p0, p1, p2, p3 }))); 12577 reflectedLight.directDiffuse.addAssign(lightColor.mul(diffuseContribution).mul(LTC_Evaluate({ N: N2, V, P, mInv: mat3(1, 0, 0, 0, 1, 0, 0, 0, 1), p0, p1, p2, p3 }))); 12578 if (this.clearcoat === true) { 12579 const Ncc = clearcoatNormalView; 12580 const uvClearcoat = LTC_Uv({ N: Ncc, V, roughness: clearcoatRoughness }); 12581 const t1Clearcoat = ltc_1.sample(uvClearcoat); 12582 const t2Clearcoat = ltc_2.sample(uvClearcoat); 12583 const mInvClearcoat = mat3( 12584 vec3(t1Clearcoat.x, 0, t1Clearcoat.y), 12585 vec3(0, 1, 0), 12586 vec3(t1Clearcoat.z, 0, t1Clearcoat.w) 12587 ); 12588 const fresnelClearcoat = clearcoatF0.mul(t2Clearcoat.x).add(clearcoatF90.sub(clearcoatF0).mul(t2Clearcoat.y)); 12589 this.clearcoatSpecularDirect.addAssign(lightColor.mul(fresnelClearcoat).mul(LTC_Evaluate({ N: Ncc, V, P, mInv: mInvClearcoat, p0, p1, p2, p3 }))); 12590 } 12591 } 12592 /** 12593 * Implements the indirect lighting. 12594 * 12595 * @param {NodeBuilder} builder - The current node builder. 12596 */ 12597 indirect(builder) { 12598 this.indirectDiffuse(builder); 12599 this.indirectSpecular(builder); 12600 this.ambientOcclusion(builder); 12601 } 12602 /** 12603 * Implements the indirect diffuse term. 12604 * 12605 * @param {NodeBuilder} builder - The current node builder. 12606 */ 12607 indirectDiffuse(builder) { 12608 const { irradiance, reflectedLight } = builder.context; 12609 const diffuse = irradiance.mul(BRDF_Lambert({ diffuseColor: diffuseContribution })).toVar(); 12610 if (this.sheen === true) { 12611 const sheenAlbedo = IBLSheenBRDF({ normal: normalView, viewDir: positionViewDirection, roughness: sheenRoughness }); 12612 const sheenEnergyComp = sheen.r.max(sheen.g).max(sheen.b).mul(sheenAlbedo).oneMinus(); 12613 diffuse.mulAssign(sheenEnergyComp); 12614 } 12615 reflectedLight.indirectDiffuse.addAssign(diffuse); 12616 } 12617 /** 12618 * Implements the indirect specular term. 12619 * 12620 * @param {NodeBuilder} builder - The current node builder. 12621 */ 12622 indirectSpecular(builder) { 12623 const { radiance, iblIrradiance, reflectedLight } = builder.context; 12624 if (this.sheen === true) { 12625 this.sheenSpecularIndirect.addAssign(iblIrradiance.mul( 12626 sheen, 12627 IBLSheenBRDF({ 12628 normal: normalView, 12629 viewDir: positionViewDirection, 12630 roughness: sheenRoughness 12631 }) 12632 )); 12633 } 12634 if (this.clearcoat === true) { 12635 const dotNVcc = clearcoatNormalView.dot(positionViewDirection).clamp(); 12636 const clearcoatEnv = EnvironmentBRDF({ 12637 dotNV: dotNVcc, 12638 specularColor: clearcoatF0, 12639 specularF90: clearcoatF90, 12640 roughness: clearcoatRoughness 12641 }); 12642 this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(clearcoatEnv)); 12643 } 12644 const singleScatteringDielectric = vec3().toVar("singleScatteringDielectric"); 12645 const multiScatteringDielectric = vec3().toVar("multiScatteringDielectric"); 12646 const singleScatteringMetallic = vec3().toVar("singleScatteringMetallic"); 12647 const multiScatteringMetallic = vec3().toVar("multiScatteringMetallic"); 12648 this.computeMultiscattering(singleScatteringDielectric, multiScatteringDielectric, specularF90, specularColor, this.iridescenceF0Dielectric); 12649 this.computeMultiscattering(singleScatteringMetallic, multiScatteringMetallic, specularF90, diffuseColor.rgb, this.iridescenceF0Metallic); 12650 const singleScattering = mix(singleScatteringDielectric, singleScatteringMetallic, metalness); 12651 const multiScattering = mix(multiScatteringDielectric, multiScatteringMetallic, metalness); 12652 const totalScatteringDielectric = singleScatteringDielectric.add(multiScatteringDielectric); 12653 const diffuse = diffuseContribution.mul(totalScatteringDielectric.oneMinus()); 12654 const cosineWeightedIrradiance = iblIrradiance.mul(1 / Math.PI); 12655 const indirectSpecular = radiance.mul(singleScattering).add(multiScattering.mul(cosineWeightedIrradiance)).toVar(); 12656 const indirectDiffuse = diffuse.mul(cosineWeightedIrradiance).toVar(); 12657 if (this.sheen === true) { 12658 const sheenAlbedo = IBLSheenBRDF({ normal: normalView, viewDir: positionViewDirection, roughness: sheenRoughness }); 12659 const sheenEnergyComp = sheen.r.max(sheen.g).max(sheen.b).mul(sheenAlbedo).oneMinus(); 12660 indirectSpecular.mulAssign(sheenEnergyComp); 12661 indirectDiffuse.mulAssign(sheenEnergyComp); 12662 } 12663 reflectedLight.indirectSpecular.addAssign(indirectSpecular); 12664 reflectedLight.indirectDiffuse.addAssign(indirectDiffuse); 12665 } 12666 /** 12667 * Implements the ambient occlusion term. 12668 * 12669 * @param {NodeBuilder} builder - The current node builder. 12670 */ 12671 ambientOcclusion(builder) { 12672 const { ambientOcclusion, reflectedLight } = builder.context; 12673 const dotNV = normalView.dot(positionViewDirection).clamp(); 12674 const aoNV = dotNV.add(ambientOcclusion); 12675 const aoExp = roughness.mul(-16).oneMinus().negate().exp2(); 12676 const aoNode = ambientOcclusion.sub(aoNV.pow(aoExp).oneMinus()).clamp(); 12677 if (this.clearcoat === true) { 12678 this.clearcoatSpecularIndirect.mulAssign(ambientOcclusion); 12679 } 12680 if (this.sheen === true) { 12681 this.sheenSpecularIndirect.mulAssign(ambientOcclusion); 12682 } 12683 reflectedLight.indirectDiffuse.mulAssign(ambientOcclusion); 12684 reflectedLight.indirectSpecular.mulAssign(aoNode); 12685 } 12686 /** 12687 * Used for final lighting accumulations depending on the requested features. 12688 * 12689 * @param {NodeBuilder} builder - The current node builder. 12690 */ 12691 finish({ context: context3 }) { 12692 const { outgoingLight } = context3; 12693 if (this.clearcoat === true) { 12694 const dotNVcc = clearcoatNormalView.dot(positionViewDirection).clamp(); 12695 const Fcc = F_Schlick({ 12696 dotVH: dotNVcc, 12697 f0: clearcoatF0, 12698 f90: clearcoatF90 12699 }); 12700 const clearcoatLight = outgoingLight.mul(clearcoat.mul(Fcc).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(clearcoat)); 12701 outgoingLight.assign(clearcoatLight); 12702 } 12703 if (this.sheen === true) { 12704 const sheenLight = outgoingLight.add(this.sheenSpecularDirect, this.sheenSpecularIndirect.mul(1 / Math.PI)); 12705 outgoingLight.assign(sheenLight); 12706 } 12707 } 12708}; 12709var cubeUV_r0 = /* @__PURE__ */ float(1); 12710var cubeUV_m0 = /* @__PURE__ */ float(-2); 12711var cubeUV_r1 = /* @__PURE__ */ float(0.8); 12712var cubeUV_m1 = /* @__PURE__ */ float(-1); 12713var cubeUV_r4 = /* @__PURE__ */ float(0.4); 12714var cubeUV_m4 = /* @__PURE__ */ float(2); 12715var cubeUV_r5 = /* @__PURE__ */ float(0.305); 12716var cubeUV_m5 = /* @__PURE__ */ float(3); 12717var cubeUV_r6 = /* @__PURE__ */ float(0.21); 12718var cubeUV_m6 = /* @__PURE__ */ float(4); 12719var cubeUV_minMipLevel = /* @__PURE__ */ float(4); 12720var cubeUV_minTileSize = /* @__PURE__ */ float(16); 12721var getFace = /* @__PURE__ */ Fn(([direction]) => { 12722 const absDirection = vec3(abs(direction)).toVar(); 12723 const face = float(-1).toVar(); 12724 If(absDirection.x.greaterThan(absDirection.z), () => { 12725 If(absDirection.x.greaterThan(absDirection.y), () => { 12726 face.assign(select(direction.x.greaterThan(0), 0, 3)); 12727 }).Else(() => { 12728 face.assign(select(direction.y.greaterThan(0), 1, 4)); 12729 }); 12730 }).Else(() => { 12731 If(absDirection.z.greaterThan(absDirection.y), () => { 12732 face.assign(select(direction.z.greaterThan(0), 2, 5)); 12733 }).Else(() => { 12734 face.assign(select(direction.y.greaterThan(0), 1, 4)); 12735 }); 12736 }); 12737 return face; 12738}).setLayout({ 12739 name: "getFace", 12740 type: "float", 12741 inputs: [ 12742 { name: "direction", type: "vec3" } 12743 ] 12744}); 12745var getUV = /* @__PURE__ */ Fn(([direction, face]) => { 12746 const uv3 = vec2().toVar(); 12747 If(face.equal(0), () => { 12748 uv3.assign(vec2(direction.z, direction.y).div(abs(direction.x))); 12749 }).ElseIf(face.equal(1), () => { 12750 uv3.assign(vec2(direction.x.negate(), direction.z.negate()).div(abs(direction.y))); 12751 }).ElseIf(face.equal(2), () => { 12752 uv3.assign(vec2(direction.x.negate(), direction.y).div(abs(direction.z))); 12753 }).ElseIf(face.equal(3), () => { 12754 uv3.assign(vec2(direction.z.negate(), direction.y).div(abs(direction.x))); 12755 }).ElseIf(face.equal(4), () => { 12756 uv3.assign(vec2(direction.x.negate(), direction.z).div(abs(direction.y))); 12757 }).Else(() => { 12758 uv3.assign(vec2(direction.x, direction.y).div(abs(direction.z))); 12759 }); 12760 return mul(0.5, uv3.add(1)); 12761}).setLayout({ 12762 name: "getUV", 12763 type: "vec2", 12764 inputs: [ 12765 { name: "direction", type: "vec3" }, 12766 { name: "face", type: "float" } 12767 ] 12768}); 12769var roughnessToMip = /* @__PURE__ */ Fn(([roughness3]) => { 12770 const mip = float(0).toVar(); 12771 If(roughness3.greaterThanEqual(cubeUV_r1), () => { 12772 mip.assign(cubeUV_r0.sub(roughness3).mul(cubeUV_m1.sub(cubeUV_m0)).div(cubeUV_r0.sub(cubeUV_r1)).add(cubeUV_m0)); 12773 }).ElseIf(roughness3.greaterThanEqual(cubeUV_r4), () => { 12774 mip.assign(cubeUV_r1.sub(roughness3).mul(cubeUV_m4.sub(cubeUV_m1)).div(cubeUV_r1.sub(cubeUV_r4)).add(cubeUV_m1)); 12775 }).ElseIf(roughness3.greaterThanEqual(cubeUV_r5), () => { 12776 mip.assign(cubeUV_r4.sub(roughness3).mul(cubeUV_m5.sub(cubeUV_m4)).div(cubeUV_r4.sub(cubeUV_r5)).add(cubeUV_m4)); 12777 }).ElseIf(roughness3.greaterThanEqual(cubeUV_r6), () => { 12778 mip.assign(cubeUV_r5.sub(roughness3).mul(cubeUV_m6.sub(cubeUV_m5)).div(cubeUV_r5.sub(cubeUV_r6)).add(cubeUV_m5)); 12779 }).Else(() => { 12780 mip.assign(float(-2).mul(log22(mul(1.16, roughness3)))); 12781 }); 12782 return mip; 12783}).setLayout({ 12784 name: "roughnessToMip", 12785 type: "float", 12786 inputs: [ 12787 { name: "roughness", type: "float" } 12788 ] 12789}); 12790var getDirection = /* @__PURE__ */ Fn(([uv_immutable, face]) => { 12791 const uv3 = uv_immutable.toVar(); 12792 uv3.assign(mul(2, uv3).sub(1)); 12793 const direction = vec3(uv3, 1).toVar(); 12794 If(face.equal(0), () => { 12795 direction.assign(direction.zyx); 12796 }).ElseIf(face.equal(1), () => { 12797 direction.assign(direction.xzy); 12798 direction.xz.mulAssign(-1); 12799 }).ElseIf(face.equal(2), () => { 12800 direction.x.mulAssign(-1); 12801 }).ElseIf(face.equal(3), () => { 12802 direction.assign(direction.zyx); 12803 direction.xz.mulAssign(-1); 12804 }).ElseIf(face.equal(4), () => { 12805 direction.assign(direction.xzy); 12806 direction.xy.mulAssign(-1); 12807 }).ElseIf(face.equal(5), () => { 12808 direction.z.mulAssign(-1); 12809 }); 12810 return direction; 12811}).setLayout({ 12812 name: "getDirection", 12813 type: "vec3", 12814 inputs: [ 12815 { name: "uv", type: "vec2" }, 12816 { name: "face", type: "float" } 12817 ] 12818}); 12819var textureCubeUV = /* @__PURE__ */ Fn(([envMap, sampleDir_immutable, roughness_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP]) => { 12820 const roughness3 = float(roughness_immutable); 12821 const sampleDir = vec3(sampleDir_immutable); 12822 const mip = clamp(roughnessToMip(roughness3), cubeUV_m0, CUBEUV_MAX_MIP); 12823 const mipF = fract(mip); 12824 const mipInt = floor(mip); 12825 const color0 = vec3(bilinearCubeUV(envMap, sampleDir, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP)).toVar(); 12826 If(mipF.notEqual(0), () => { 12827 const color1 = vec3(bilinearCubeUV(envMap, sampleDir, mipInt.add(1), CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP)).toVar(); 12828 color0.assign(mix(color0, color1, mipF)); 12829 }); 12830 return color0; 12831}); 12832var bilinearCubeUV = /* @__PURE__ */ Fn(([envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP]) => { 12833 const mipInt = float(mipInt_immutable).toVar(); 12834 const direction = vec3(direction_immutable); 12835 const face = float(getFace(direction)).toVar(); 12836 const filterInt = float(max$1(cubeUV_minMipLevel.sub(mipInt), 0)).toVar(); 12837 mipInt.assign(max$1(mipInt, cubeUV_minMipLevel)); 12838 const faceSize = float(exp2(mipInt)).toVar(); 12839 const uv3 = vec2(getUV(direction, face).mul(faceSize.sub(2)).add(1)).toVar(); 12840 If(face.greaterThan(2), () => { 12841 uv3.y.addAssign(faceSize); 12842 face.subAssign(3); 12843 }); 12844 uv3.x.addAssign(face.mul(faceSize)); 12845 uv3.x.addAssign(filterInt.mul(mul(3, cubeUV_minTileSize))); 12846 uv3.y.addAssign(mul(4, exp2(CUBEUV_MAX_MIP).sub(faceSize))); 12847 uv3.x.mulAssign(CUBEUV_TEXEL_WIDTH); 12848 uv3.y.mulAssign(CUBEUV_TEXEL_HEIGHT); 12849 return envMap.sample(uv3).grad(vec2(), vec2()); 12850}); 12851var getSample = /* @__PURE__ */ Fn(({ envMap, mipInt, outputDirection, theta, axis, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }) => { 12852 const cosTheta = cos(theta); 12853 const sampleDirection = outputDirection.mul(cosTheta).add(axis.cross(outputDirection).mul(sin(theta))).add(axis.mul(axis.dot(outputDirection).mul(cosTheta.oneMinus()))); 12854 return bilinearCubeUV(envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP); 12855}); 12856var blur = /* @__PURE__ */ Fn(({ n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }) => { 12857 const axis = vec3(select(latitudinal, poleAxis, cross(poleAxis, outputDirection))).toVar(); 12858 If(axis.equal(vec3(0)), () => { 12859 axis.assign(vec3(outputDirection.z, 0, outputDirection.x.negate())); 12860 }); 12861 axis.assign(normalize(axis)); 12862 const gl_FragColor = vec3().toVar(); 12863 gl_FragColor.addAssign(weights.element(0).mul(getSample({ theta: 0, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }))); 12864 Loop({ start: int(1), end: n }, ({ i }) => { 12865 If(i.greaterThanEqual(samples), () => { 12866 Break(); 12867 }); 12868 const theta = float(dTheta.mul(float(i))).toVar(); 12869 gl_FragColor.addAssign(weights.element(i).mul(getSample({ theta: theta.mul(-1), axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }))); 12870 gl_FragColor.addAssign(weights.element(i).mul(getSample({ theta, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }))); 12871 }); 12872 return vec4(gl_FragColor, 1); 12873}); 12874var radicalInverse_VdC = /* @__PURE__ */ Fn(([bits_immutable]) => { 12875 const bits = uint(bits_immutable).toVar(); 12876 bits.assign(bits.shiftLeft(uint(16)).bitOr(bits.shiftRight(uint(16)))); 12877 bits.assign(bits.bitAnd(uint(1431655765)).shiftLeft(uint(1)).bitOr(bits.bitAnd(uint(2863311530)).shiftRight(uint(1)))); 12878 bits.assign(bits.bitAnd(uint(858993459)).shiftLeft(uint(2)).bitOr(bits.bitAnd(uint(3435973836)).shiftRight(uint(2)))); 12879 bits.assign(bits.bitAnd(uint(252645135)).shiftLeft(uint(4)).bitOr(bits.bitAnd(uint(4042322160)).shiftRight(uint(4)))); 12880 bits.assign(bits.bitAnd(uint(16711935)).shiftLeft(uint(8)).bitOr(bits.bitAnd(uint(4278255360)).shiftRight(uint(8)))); 12881 return float(bits).mul(23283064365386963e-26); 12882}); 12883var hammersley = /* @__PURE__ */ Fn(([i, N2]) => { 12884 return vec2(float(i).div(float(N2)), radicalInverse_VdC(i)); 12885}); 12886var importanceSampleGGX_VNDF = /* @__PURE__ */ Fn(([Xi, V, roughness3]) => { 12887 const alpha = roughness3.mul(roughness3).toConst(); 12888 const T1 = vec3(1, 0, 0).toConst(); 12889 const T22 = cross(V, T1).toConst(); 12890 const r = sqrt(Xi.x).toConst(); 12891 const phi = mul(2, 3.14159265359).mul(Xi.y).toConst(); 12892 const t1 = r.mul(cos(phi)).toConst(); 12893 const t2 = r.mul(sin(phi)).toVar(); 12894 const s = mul(0.5, V.z.add(1)).toConst(); 12895 t2.assign(s.oneMinus().mul(sqrt(t1.mul(t1).oneMinus())).add(s.mul(t2))); 12896 const Nh = T1.mul(t1).add(T22.mul(t2)).add(V.mul(sqrt(max$1(0, t1.mul(t1).add(t2.mul(t2)).oneMinus())))); 12897 return normalize(vec3(alpha.mul(Nh.x), alpha.mul(Nh.y), max$1(0, Nh.z))); 12898}); 12899var ggxConvolution = /* @__PURE__ */ Fn(({ roughness: roughness3, mipInt, envMap, N_immutable, GGX_SAMPLES: GGX_SAMPLES2, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP }) => { 12900 const N2 = vec3(N_immutable).toVar(); 12901 const prefilteredColor = vec3(0).toVar(); 12902 const totalWeight = float(0).toVar(); 12903 If(roughness3.lessThan(1e-3), () => { 12904 prefilteredColor.assign(bilinearCubeUV(envMap, N2, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP)); 12905 }).Else(() => { 12906 const up = select(abs(N2.z).lessThan(0.999), vec3(0, 0, 1), vec3(1, 0, 0)); 12907 const tangent = normalize(cross(up, N2)).toVar(); 12908 const bitangent = cross(N2, tangent).toVar(); 12909 Loop({ start: uint(0), end: GGX_SAMPLES2 }, ({ i }) => { 12910 const Xi = hammersley(i, GGX_SAMPLES2); 12911 const H_tangent = importanceSampleGGX_VNDF(Xi, vec3(0, 0, 1), roughness3); 12912 const H = normalize(tangent.mul(H_tangent.x).add(bitangent.mul(H_tangent.y)).add(N2.mul(H_tangent.z))); 12913 const L = normalize(H.mul(dot(N2, H).mul(2)).sub(N2)); 12914 const NdotL = max$1(dot(N2, L), 0); 12915 If(NdotL.greaterThan(0), () => { 12916 const sampleColor = bilinearCubeUV(envMap, L, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP); 12917 prefilteredColor.addAssign(sampleColor.mul(NdotL)); 12918 totalWeight.addAssign(NdotL); 12919 }); 12920 }); 12921 If(totalWeight.greaterThan(0), () => { 12922 prefilteredColor.assign(prefilteredColor.div(totalWeight)); 12923 }); 12924 }); 12925 return vec4(prefilteredColor, 1); 12926}); 12927var LOD_MIN = 4; 12928var EXTRA_LOD_SIGMA = [0.125, 0.215, 0.35, 0.446, 0.526, 0.582]; 12929var MAX_SAMPLES = 20; 12930var GGX_SAMPLES = 512; 12931var _flatCamera = /* @__PURE__ */ new OrthographicCamera(-1, 1, 1, -1, 0, 1); 12932var _cubeCamera = /* @__PURE__ */ new PerspectiveCamera(90, 1); 12933var _clearColor$2 = /* @__PURE__ */ new Color(); 12934var _oldTarget = null; 12935var _oldActiveCubeFace = 0; 12936var _oldActiveMipmapLevel = 0; 12937var _origin = /* @__PURE__ */ new Vector3(); 12938var _uniformsMap = /* @__PURE__ */ new WeakMap(); 12939var _faceLib = [ 12940 3, 12941 1, 12942 5, 12943 0, 12944 4, 12945 2 12946]; 12947var _direction = /* @__PURE__ */ getDirection(uv$1(), attribute("faceIndex")).normalize(); 12948var _outputDirection = /* @__PURE__ */ vec3(_direction.x, _direction.y, _direction.z); 12949var PMREMGenerator = class { 12950 /** 12951 * Constructs a new PMREM generator. 12952 * 12953 * @param {Renderer} renderer - The renderer. 12954 */ 12955 constructor(renderer) { 12956 this._renderer = renderer; 12957 this._pingPongRenderTarget = null; 12958 this._lodMax = 0; 12959 this._cubeSize = 0; 12960 this._sizeLods = []; 12961 this._sigmas = []; 12962 this._lodMeshes = []; 12963 this._blurMaterial = null; 12964 this._ggxMaterial = null; 12965 this._cubemapMaterial = null; 12966 this._equirectMaterial = null; 12967 this._backgroundBox = null; 12968 } 12969 get _hasInitialized() { 12970 return this._renderer.hasInitialized(); 12971 } 12972 /** 12973 * Generates a PMREM from a supplied Scene, which can be faster than using an 12974 * image if networking bandwidth is low. Optional sigma specifies a blur radius 12975 * in radians to be applied to the scene before PMREM generation. Optional near 12976 * and far planes ensure the scene is rendered in its entirety. 12977 * 12978 * @param {Scene} scene - The scene to be captured. 12979 * @param {number} [sigma=0] - The blur radius in radians. 12980 * @param {number} [near=0.1] - The near plane distance. 12981 * @param {number} [far=100] - The far plane distance. 12982 * @param {Object} [options={}] - The configuration options. 12983 * @param {number} [options.size=256] - The texture size of the PMREM. 12984 * @param {Vector3} [options.renderTarget=origin] - The position of the internal cube camera that renders the scene. 12985 * @param {?RenderTarget} [options.renderTarget=null] - The render target to use. 12986 * @return {RenderTarget} The resulting PMREM. 12987 * @see {@link PMREMGenerator#fromScene} 12988 */ 12989 fromScene(scene, sigma = 0, near = 0.1, far = 100, options = {}) { 12990 const { 12991 size: size3 = 256, 12992 position = _origin, 12993 renderTarget = null 12994 } = options; 12995 this._setSize(size3); 12996 if (this._hasInitialized === false) { 12997 warn('PMREMGenerator: ".fromScene()" called before the backend is initialized. Try using "await renderer.init()" instead.'); 12998 const cubeUVRenderTarget2 = renderTarget || this._allocateTarget(); 12999 options.renderTarget = cubeUVRenderTarget2; 13000 this.fromSceneAsync(scene, sigma, near, far, options); 13001 return cubeUVRenderTarget2; 13002 } 13003 _oldTarget = this._renderer.getRenderTarget(); 13004 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 13005 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 13006 const cubeUVRenderTarget = renderTarget || this._allocateTarget(); 13007 cubeUVRenderTarget.depthBuffer = true; 13008 this._init(cubeUVRenderTarget); 13009 this._sceneToCubeUV(scene, near, far, cubeUVRenderTarget, position); 13010 if (sigma > 0) { 13011 this._blur(cubeUVRenderTarget, 0, 0, sigma); 13012 } 13013 this._applyPMREM(cubeUVRenderTarget); 13014 this._cleanup(cubeUVRenderTarget); 13015 return cubeUVRenderTarget; 13016 } 13017 /** 13018 * Generates a PMREM from a supplied Scene, which can be faster than using an 13019 * image if networking bandwidth is low. Optional sigma specifies a blur radius 13020 * in radians to be applied to the scene before PMREM generation. Optional near 13021 * and far planes ensure the scene is rendered in its entirety (the cubeCamera 13022 * is placed at the origin). 13023 * 13024 * @deprecated 13025 * @param {Scene} scene - The scene to be captured. 13026 * @param {number} [sigma=0] - The blur radius in radians. 13027 * @param {number} [near=0.1] - The near plane distance. 13028 * @param {number} [far=100] - The far plane distance. 13029 * @param {Object} [options={}] - The configuration options. 13030 * @param {number} [options.size=256] - The texture size of the PMREM. 13031 * @param {Vector3} [options.position=origin] - The position of the internal cube camera that renders the scene. 13032 * @param {?RenderTarget} [options.renderTarget=null] - The render target to use. 13033 * @return {Promise<RenderTarget>} A Promise that resolve with the PMREM when the generation has been finished. 13034 * @see {@link PMREMGenerator#fromScene} 13035 */ 13036 async fromSceneAsync(scene, sigma = 0, near = 0.1, far = 100, options = {}) { 13037 warnOnce('PMREMGenerator: ".fromSceneAsync()" is deprecated. Use "await renderer.init()" instead.'); 13038 await this._renderer.init(); 13039 return this.fromScene(scene, sigma, near, far, options); 13040 } 13041 /** 13042 * Generates a PMREM from an equirectangular texture, which can be either LDR 13043 * or HDR. The ideal input image size is 1k (1024 x 512), 13044 * as this matches best with the 256 x 256 cubemap output. 13045 * 13046 * @param {Texture} equirectangular - The equirectangular texture to be converted. 13047 * @param {?RenderTarget} [renderTarget=null] - The render target to use. 13048 * @return {RenderTarget} The resulting PMREM. 13049 * @see {@link PMREMGenerator#fromEquirectangularAsync} 13050 */ 13051 fromEquirectangular(equirectangular, renderTarget = null) { 13052 if (this._hasInitialized === false) { 13053 warn('PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using "await renderer.init()" instead.'); 13054 this._setSizeFromTexture(equirectangular); 13055 const cubeUVRenderTarget = renderTarget || this._allocateTarget(); 13056 this.fromEquirectangularAsync(equirectangular, cubeUVRenderTarget); 13057 return cubeUVRenderTarget; 13058 } 13059 return this._fromTexture(equirectangular, renderTarget); 13060 } 13061 /** 13062 * Generates a PMREM from an equirectangular texture, which can be either LDR 13063 * or HDR. The ideal input image size is 1k (1024 x 512), 13064 * as this matches best with the 256 x 256 cubemap output. 13065 * 13066 * @deprecated 13067 * @param {Texture} equirectangular - The equirectangular texture to be converted. 13068 * @param {?RenderTarget} [renderTarget=null] - The render target to use. 13069 * @return {Promise<RenderTarget>} The resulting PMREM. 13070 * @see {@link PMREMGenerator#fromEquirectangular} 13071 */ 13072 async fromEquirectangularAsync(equirectangular, renderTarget = null) { 13073 warnOnce('PMREMGenerator: ".fromEquirectangularAsync()" is deprecated. Use "await renderer.init()" instead.'); 13074 await this._renderer.init(); 13075 return this._fromTexture(equirectangular, renderTarget); 13076 } 13077 /** 13078 * Generates a PMREM from an cubemap texture, which can be either LDR 13079 * or HDR. The ideal input cube size is 256 x 256, 13080 * as this matches best with the 256 x 256 cubemap output. 13081 * 13082 * @param {Texture} cubemap - The cubemap texture to be converted. 13083 * @param {?RenderTarget} [renderTarget=null] - The render target to use. 13084 * @return {RenderTarget} The resulting PMREM. 13085 * @see {@link PMREMGenerator#fromCubemapAsync} 13086 */ 13087 fromCubemap(cubemap, renderTarget = null) { 13088 if (this._hasInitialized === false) { 13089 warn("PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead."); 13090 this._setSizeFromTexture(cubemap); 13091 const cubeUVRenderTarget = renderTarget || this._allocateTarget(); 13092 this.fromCubemapAsync(cubemap, renderTarget); 13093 return cubeUVRenderTarget; 13094 } 13095 return this._fromTexture(cubemap, renderTarget); 13096 } 13097 /** 13098 * Generates a PMREM from an cubemap texture, which can be either LDR 13099 * or HDR. The ideal input cube size is 256 x 256, 13100 * with the 256 x 256 cubemap output. 13101 * 13102 * @deprecated 13103 * @param {Texture} cubemap - The cubemap texture to be converted. 13104 * @param {?RenderTarget} [renderTarget=null] - The render target to use. 13105 * @return {Promise<RenderTarget>} The resulting PMREM. 13106 * @see {@link PMREMGenerator#fromCubemap} 13107 */ 13108 async fromCubemapAsync(cubemap, renderTarget = null) { 13109 warnOnce('PMREMGenerator: ".fromCubemapAsync()" is deprecated. Use "await renderer.init()" instead.'); 13110 await this._renderer.init(); 13111 return this._fromTexture(cubemap, renderTarget); 13112 } 13113 /** 13114 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during 13115 * your texture's network fetch for increased concurrency. 13116 * 13117 * @returns {Promise} 13118 */ 13119 async compileCubemapShader() { 13120 if (this._cubemapMaterial === null) { 13121 this._cubemapMaterial = _getCubemapMaterial(); 13122 await this._compileMaterial(this._cubemapMaterial); 13123 } 13124 } 13125 /** 13126 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during 13127 * your texture's network fetch for increased concurrency. 13128 * 13129 * @returns {Promise} 13130 */ 13131 async compileEquirectangularShader() { 13132 if (this._equirectMaterial === null) { 13133 this._equirectMaterial = _getEquirectMaterial(); 13134 await this._compileMaterial(this._equirectMaterial); 13135 } 13136 } 13137 /** 13138 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, 13139 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on 13140 * one of them will cause any others to also become unusable. 13141 */ 13142 dispose() { 13143 this._dispose(); 13144 if (this._cubemapMaterial !== null) this._cubemapMaterial.dispose(); 13145 if (this._equirectMaterial !== null) this._equirectMaterial.dispose(); 13146 if (this._backgroundBox !== null) { 13147 this._backgroundBox.geometry.dispose(); 13148 this._backgroundBox.material.dispose(); 13149 } 13150 } 13151 // private interface 13152 _setSizeFromTexture(texture3) { 13153 if (texture3.mapping === CubeReflectionMapping || texture3.mapping === CubeRefractionMapping) { 13154 this._setSize(texture3.image.length === 0 ? 16 : texture3.image[0].width || texture3.image[0].image.width); 13155 } else { 13156 this._setSize(texture3.image.width / 4); 13157 } 13158 } 13159 _setSize(cubeSize) { 13160 this._lodMax = Math.floor(Math.log2(cubeSize)); 13161 this._cubeSize = Math.pow(2, this._lodMax); 13162 } 13163 _dispose() { 13164 if (this._blurMaterial !== null) this._blurMaterial.dispose(); 13165 if (this._ggxMaterial !== null) this._ggxMaterial.dispose(); 13166 if (this._pingPongRenderTarget !== null) this._pingPongRenderTarget.dispose(); 13167 for (let i = 0; i < this._lodMeshes.length; i++) { 13168 this._lodMeshes[i].geometry.dispose(); 13169 } 13170 } 13171 _cleanup(outputTarget) { 13172 this._renderer.setRenderTarget(_oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel); 13173 outputTarget.scissorTest = false; 13174 this._setViewport(outputTarget, 0, 0, outputTarget.width, outputTarget.height); 13175 } 13176 _fromTexture(texture3, renderTarget) { 13177 this._setSizeFromTexture(texture3); 13178 _oldTarget = this._renderer.getRenderTarget(); 13179 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 13180 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 13181 const cubeUVRenderTarget = renderTarget || this._allocateTarget(); 13182 this._init(cubeUVRenderTarget); 13183 this._textureToCubeUV(texture3, cubeUVRenderTarget); 13184 this._applyPMREM(cubeUVRenderTarget); 13185 this._cleanup(cubeUVRenderTarget); 13186 return cubeUVRenderTarget; 13187 } 13188 _allocateTarget() { 13189 const width = 3 * Math.max(this._cubeSize, 16 * 7); 13190 const height = 4 * this._cubeSize; 13191 const cubeUVRenderTarget = _createRenderTarget(width, height); 13192 return cubeUVRenderTarget; 13193 } 13194 _init(renderTarget) { 13195 if (this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== renderTarget.width || this._pingPongRenderTarget.height !== renderTarget.height) { 13196 if (this._pingPongRenderTarget !== null) { 13197 this._dispose(); 13198 } 13199 this._pingPongRenderTarget = _createRenderTarget(renderTarget.width, renderTarget.height); 13200 const { _lodMax } = this; 13201 ({ lodMeshes: this._lodMeshes, sizeLods: this._sizeLods, sigmas: this._sigmas } = _createPlanes(_lodMax)); 13202 this._blurMaterial = _getBlurShader(_lodMax, renderTarget.width, renderTarget.height); 13203 this._ggxMaterial = _getGGXShader(_lodMax, renderTarget.width, renderTarget.height); 13204 } 13205 } 13206 async _compileMaterial(material) { 13207 const mesh = new Mesh(new BufferGeometry(), material); 13208 await this._renderer.compile(mesh, _flatCamera); 13209 } 13210 _sceneToCubeUV(scene, near, far, cubeUVRenderTarget, position) { 13211 const cubeCamera = _cubeCamera; 13212 cubeCamera.near = near; 13213 cubeCamera.far = far; 13214 const upSign = [1, 1, 1, 1, -1, 1]; 13215 const forwardSign = [1, -1, 1, -1, 1, -1]; 13216 const renderer = this._renderer; 13217 const originalAutoClear = renderer.autoClear; 13218 renderer.getClearColor(_clearColor$2); 13219 renderer.autoClear = false; 13220 if (this._backgroundBox === null) { 13221 this._backgroundBox = new Mesh( 13222 new BoxGeometry(), 13223 new MeshBasicMaterial({ 13224 name: "PMREM.Background", 13225 side: BackSide, 13226 depthWrite: false, 13227 depthTest: false 13228 }) 13229 ); 13230 } 13231 const backgroundBox = this._backgroundBox; 13232 const backgroundMaterial = backgroundBox.material; 13233 let useSolidColor = false; 13234 const background = scene.background; 13235 if (background) { 13236 if (background.isColor) { 13237 backgroundMaterial.color.copy(background); 13238 scene.background = null; 13239 useSolidColor = true; 13240 } 13241 } else { 13242 backgroundMaterial.color.copy(_clearColor$2); 13243 useSolidColor = true; 13244 } 13245 renderer.setRenderTarget(cubeUVRenderTarget); 13246 renderer.clear(); 13247 if (useSolidColor) { 13248 renderer.render(backgroundBox, cubeCamera); 13249 } 13250 for (let i = 0; i < 6; i++) { 13251 const col = i % 3; 13252 if (col === 0) { 13253 cubeCamera.up.set(0, upSign[i], 0); 13254 cubeCamera.position.set(position.x, position.y, position.z); 13255 cubeCamera.lookAt(position.x + forwardSign[i], position.y, position.z); 13256 } else if (col === 1) { 13257 cubeCamera.up.set(0, 0, upSign[i]); 13258 cubeCamera.position.set(position.x, position.y, position.z); 13259 cubeCamera.lookAt(position.x, position.y + forwardSign[i], position.z); 13260 } else { 13261 cubeCamera.up.set(0, upSign[i], 0); 13262 cubeCamera.position.set(position.x, position.y, position.z); 13263 cubeCamera.lookAt(position.x, position.y, position.z + forwardSign[i]); 13264 } 13265 const size3 = this._cubeSize; 13266 this._setViewport(cubeUVRenderTarget, col * size3, i > 2 ? size3 : 0, size3, size3); 13267 renderer.render(scene, cubeCamera); 13268 } 13269 renderer.autoClear = originalAutoClear; 13270 scene.background = background; 13271 } 13272 _textureToCubeUV(texture3, cubeUVRenderTarget) { 13273 const renderer = this._renderer; 13274 const isCubeTexture = texture3.mapping === CubeReflectionMapping || texture3.mapping === CubeRefractionMapping; 13275 if (isCubeTexture) { 13276 if (this._cubemapMaterial === null) { 13277 this._cubemapMaterial = _getCubemapMaterial(texture3); 13278 } 13279 } else { 13280 if (this._equirectMaterial === null) { 13281 this._equirectMaterial = _getEquirectMaterial(texture3); 13282 } 13283 } 13284 const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; 13285 material.fragmentNode.value = texture3; 13286 const mesh = this._lodMeshes[0]; 13287 mesh.material = material; 13288 const size3 = this._cubeSize; 13289 this._setViewport(cubeUVRenderTarget, 0, 0, 3 * size3, 2 * size3); 13290 renderer.setRenderTarget(cubeUVRenderTarget); 13291 renderer.render(mesh, _flatCamera); 13292 } 13293 _applyPMREM(cubeUVRenderTarget) { 13294 const renderer = this._renderer; 13295 const autoClear = renderer.autoClear; 13296 renderer.autoClear = false; 13297 const n = this._lodMeshes.length; 13298 for (let i = 1; i < n; i++) { 13299 this._applyGGXFilter(cubeUVRenderTarget, i - 1, i); 13300 } 13301 renderer.autoClear = autoClear; 13302 } 13303 /** 13304 * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map. 13305 * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the 13306 * GGX BRDF for physically-based rendering. Reads from the previous LOD level and 13307 * applies incremental roughness filtering to avoid over-blurring. 13308 * 13309 * @private 13310 * @param {RenderTarget} cubeUVRenderTarget 13311 * @param {number} lodIn - Source LOD level to read from 13312 * @param {number} lodOut - Target LOD level to write to 13313 */ 13314 _applyGGXFilter(cubeUVRenderTarget, lodIn, lodOut) { 13315 const renderer = this._renderer; 13316 const pingPongRenderTarget = this._pingPongRenderTarget; 13317 const ggxMaterial = this._ggxMaterial; 13318 const ggxMesh = this._lodMeshes[lodOut]; 13319 ggxMesh.material = ggxMaterial; 13320 const ggxUniforms = _uniformsMap.get(ggxMaterial); 13321 const targetRoughness = lodOut / (this._lodMeshes.length - 1); 13322 const sourceRoughness = lodIn / (this._lodMeshes.length - 1); 13323 const incrementalRoughness = Math.sqrt(targetRoughness * targetRoughness - sourceRoughness * sourceRoughness); 13324 const blurStrength = 0 + targetRoughness * 1.25; 13325 const adjustedRoughness = incrementalRoughness * blurStrength; 13326 const { _lodMax } = this; 13327 const outputSize = this._sizeLods[lodOut]; 13328 const x = 3 * outputSize * (lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0); 13329 const y = 4 * (this._cubeSize - outputSize); 13330 cubeUVRenderTarget.texture.frame = (cubeUVRenderTarget.texture.frame || 0) + 1; 13331 ggxUniforms.envMap.value = cubeUVRenderTarget.texture; 13332 ggxUniforms.roughness.value = adjustedRoughness; 13333 ggxUniforms.mipInt.value = _lodMax - lodIn; 13334 this._setViewport(pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize); 13335 renderer.setRenderTarget(pingPongRenderTarget); 13336 renderer.render(ggxMesh, _flatCamera); 13337 pingPongRenderTarget.texture.frame = (pingPongRenderTarget.texture.frame || 0) + 1; 13338 ggxUniforms.envMap.value = pingPongRenderTarget.texture; 13339 ggxUniforms.roughness.value = 0; 13340 ggxUniforms.mipInt.value = _lodMax - lodOut; 13341 this._setViewport(cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize); 13342 renderer.setRenderTarget(cubeUVRenderTarget); 13343 renderer.render(ggxMesh, _flatCamera); 13344 } 13345 /** 13346 * This is a two-pass Gaussian blur for a cubemap. Normally this is done 13347 * vertically and horizontally, but this breaks down on a cube. Here we apply 13348 * the blur latitudinally (around the poles), and then longitudinally (towards 13349 * the poles) to approximate the orthogonally-separable blur. It is least 13350 * accurate at the poles, but still does a decent job. 13351 * 13352 * Used for initial scene blur in fromScene() method when sigma > 0. 13353 * 13354 * @private 13355 * @param {RenderTarget} cubeUVRenderTarget - The cubemap render target. 13356 * @param {number} lodIn - The input level-of-detail. 13357 * @param {number} lodOut - The output level-of-detail. 13358 * @param {number} sigma - The blur radius in radians. 13359 * @param {Vector3} [poleAxis] - The pole axis. 13360 */ 13361 _blur(cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis) { 13362 const pingPongRenderTarget = this._pingPongRenderTarget; 13363 this._halfBlur( 13364 cubeUVRenderTarget, 13365 pingPongRenderTarget, 13366 lodIn, 13367 lodOut, 13368 sigma, 13369 "latitudinal", 13370 poleAxis 13371 ); 13372 this._halfBlur( 13373 pingPongRenderTarget, 13374 cubeUVRenderTarget, 13375 lodOut, 13376 lodOut, 13377 sigma, 13378 "longitudinal", 13379 poleAxis 13380 ); 13381 } 13382 _halfBlur(targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis) { 13383 const renderer = this._renderer; 13384 const blurMaterial = this._blurMaterial; 13385 if (direction !== "latitudinal" && direction !== "longitudinal") { 13386 error("blur direction must be either latitudinal or longitudinal!"); 13387 } 13388 const STANDARD_DEVIATIONS = 3; 13389 const blurMesh = this._lodMeshes[lodOut]; 13390 blurMesh.material = blurMaterial; 13391 const blurUniforms = _uniformsMap.get(blurMaterial); 13392 const pixels = this._sizeLods[lodIn] - 1; 13393 const radiansPerPixel = isFinite(sigmaRadians) ? Math.PI / (2 * pixels) : 2 * Math.PI / (2 * MAX_SAMPLES - 1); 13394 const sigmaPixels = sigmaRadians / radiansPerPixel; 13395 const samples = isFinite(sigmaRadians) ? 1 + Math.floor(STANDARD_DEVIATIONS * sigmaPixels) : MAX_SAMPLES; 13396 if (samples > MAX_SAMPLES) { 13397 warn(`sigmaRadians, ${sigmaRadians}, is too large and will clip, as it requested ${samples} samples when the maximum is set to ${MAX_SAMPLES}`); 13398 } 13399 const weights = []; 13400 let sum = 0; 13401 for (let i = 0; i < MAX_SAMPLES; ++i) { 13402 const x2 = i / sigmaPixels; 13403 const weight = Math.exp(-x2 * x2 / 2); 13404 weights.push(weight); 13405 if (i === 0) { 13406 sum += weight; 13407 } else if (i < samples) { 13408 sum += 2 * weight; 13409 } 13410 } 13411 for (let i = 0; i < weights.length; i++) { 13412 weights[i] = weights[i] / sum; 13413 } 13414 targetIn.texture.frame = (targetIn.texture.frame || 0) + 1; 13415 blurUniforms.envMap.value = targetIn.texture; 13416 blurUniforms.samples.value = samples; 13417 blurUniforms.weights.array = weights; 13418 blurUniforms.latitudinal.value = direction === "latitudinal" ? 1 : 0; 13419 if (poleAxis) { 13420 blurUniforms.poleAxis.value = poleAxis; 13421 } 13422 const { _lodMax } = this; 13423 blurUniforms.dTheta.value = radiansPerPixel; 13424 blurUniforms.mipInt.value = _lodMax - lodIn; 13425 const outputSize = this._sizeLods[lodOut]; 13426 const x = 3 * outputSize * (lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0); 13427 const y = 4 * (this._cubeSize - outputSize); 13428 this._setViewport(targetOut, x, y, 3 * outputSize, 2 * outputSize); 13429 renderer.setRenderTarget(targetOut); 13430 renderer.render(blurMesh, _flatCamera); 13431 } 13432 _setViewport(target, x, y, width, height) { 13433 if (this._renderer.isWebGLRenderer) { 13434 target.viewport.set(x, target.height - height - y, width, height); 13435 target.scissor.set(x, target.height - height - y, width, height); 13436 } else { 13437 target.viewport.set(x, y, width, height); 13438 target.scissor.set(x, y, width, height); 13439 } 13440 } 13441}; 13442function _createPlanes(lodMax) { 13443 const sizeLods = []; 13444 const sigmas = []; 13445 const lodMeshes = []; 13446 let lod = lodMax; 13447 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; 13448 for (let i = 0; i < totalLods; i++) { 13449 const sizeLod = Math.pow(2, lod); 13450 sizeLods.push(sizeLod); 13451 let sigma = 1 / sizeLod; 13452 if (i > lodMax - LOD_MIN) { 13453 sigma = EXTRA_LOD_SIGMA[i - lodMax + LOD_MIN - 1]; 13454 } else if (i === 0) { 13455 sigma = 0; 13456 } 13457 sigmas.push(sigma); 13458 const texelSize = 1 / (sizeLod - 2); 13459 const min5 = -texelSize; 13460 const max5 = 1 + texelSize; 13461 const uv1 = [min5, min5, max5, min5, max5, max5, min5, min5, max5, max5, min5, max5]; 13462 const cubeFaces = 6; 13463 const vertices = 6; 13464 const positionSize = 3; 13465 const uvSize = 2; 13466 const faceIndexSize = 1; 13467 const position = new Float32Array(positionSize * vertices * cubeFaces); 13468 const uv3 = new Float32Array(uvSize * vertices * cubeFaces); 13469 const faceIndex = new Float32Array(faceIndexSize * vertices * cubeFaces); 13470 for (let face = 0; face < cubeFaces; face++) { 13471 const x = face % 3 * 2 / 3 - 1; 13472 const y = face > 2 ? 0 : -1; 13473 const coordinates = [ 13474 x, 13475 y, 13476 0, 13477 x + 2 / 3, 13478 y, 13479 0, 13480 x + 2 / 3, 13481 y + 1, 13482 0, 13483 x, 13484 y, 13485 0, 13486 x + 2 / 3, 13487 y + 1, 13488 0, 13489 x, 13490 y + 1, 13491 0 13492 ]; 13493 const faceIdx = _faceLib[face]; 13494 position.set(coordinates, positionSize * vertices * faceIdx); 13495 uv3.set(uv1, uvSize * vertices * faceIdx); 13496 const fill = [faceIdx, faceIdx, faceIdx, faceIdx, faceIdx, faceIdx]; 13497 faceIndex.set(fill, faceIndexSize * vertices * faceIdx); 13498 } 13499 const planes = new BufferGeometry(); 13500 planes.setAttribute("position", new BufferAttribute(position, positionSize)); 13501 planes.setAttribute("uv", new BufferAttribute(uv3, uvSize)); 13502 planes.setAttribute("faceIndex", new BufferAttribute(faceIndex, faceIndexSize)); 13503 lodMeshes.push(new Mesh(planes, null)); 13504 if (lod > LOD_MIN) { 13505 lod--; 13506 } 13507 } 13508 return { lodMeshes, sizeLods, sigmas }; 13509} 13510function _createRenderTarget(width, height) { 13511 const params = { 13512 magFilter: LinearFilter, 13513 minFilter: LinearFilter, 13514 generateMipmaps: false, 13515 type: HalfFloatType, 13516 format: RGBAFormat, 13517 colorSpace: LinearSRGBColorSpace 13518 //depthBuffer: false 13519 }; 13520 const cubeUVRenderTarget = new RenderTarget(width, height, params); 13521 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; 13522 cubeUVRenderTarget.texture.name = "PMREM.cubeUv"; 13523 cubeUVRenderTarget.texture.isPMREMTexture = true; 13524 cubeUVRenderTarget.scissorTest = true; 13525 return cubeUVRenderTarget; 13526} 13527function _getMaterial(type) { 13528 const material = new NodeMaterial(); 13529 material.depthTest = false; 13530 material.depthWrite = false; 13531 material.blending = NoBlending; 13532 material.name = `PMREM_${type}`; 13533 return material; 13534} 13535function _getBlurShader(lodMax, width, height) { 13536 const weights = uniformArray(new Array(MAX_SAMPLES).fill(0)); 13537 const poleAxis = uniform(new Vector3(0, 1, 0)); 13538 const dTheta = uniform(0); 13539 const n = float(MAX_SAMPLES); 13540 const latitudinal = uniform(0); 13541 const samples = uniform(1); 13542 const envMap = texture(); 13543 const mipInt = uniform(0); 13544 const CUBEUV_TEXEL_WIDTH = float(1 / width); 13545 const CUBEUV_TEXEL_HEIGHT = float(1 / height); 13546 const CUBEUV_MAX_MIP = float(lodMax); 13547 const materialUniforms = { 13548 n, 13549 latitudinal, 13550 weights, 13551 poleAxis, 13552 outputDirection: _outputDirection, 13553 dTheta, 13554 samples, 13555 envMap, 13556 mipInt, 13557 CUBEUV_TEXEL_WIDTH, 13558 CUBEUV_TEXEL_HEIGHT, 13559 CUBEUV_MAX_MIP 13560 }; 13561 const material = _getMaterial("blur"); 13562 material.fragmentNode = blur({ ...materialUniforms, latitudinal: latitudinal.equal(1) }); 13563 _uniformsMap.set(material, materialUniforms); 13564 return material; 13565} 13566function _getGGXShader(lodMax, width, height) { 13567 const envMap = texture(); 13568 const roughness3 = uniform(0); 13569 const mipInt = uniform(0); 13570 const CUBEUV_TEXEL_WIDTH = float(1 / width); 13571 const CUBEUV_TEXEL_HEIGHT = float(1 / height); 13572 const CUBEUV_MAX_MIP = float(lodMax); 13573 const materialUniforms = { 13574 envMap, 13575 roughness: roughness3, 13576 mipInt, 13577 CUBEUV_TEXEL_WIDTH, 13578 CUBEUV_TEXEL_HEIGHT, 13579 CUBEUV_MAX_MIP 13580 }; 13581 const material = _getMaterial("ggx"); 13582 material.fragmentNode = ggxConvolution({ 13583 ...materialUniforms, 13584 N_immutable: _outputDirection, 13585 GGX_SAMPLES: uint(GGX_SAMPLES) 13586 }); 13587 _uniformsMap.set(material, materialUniforms); 13588 return material; 13589} 13590function _getCubemapMaterial(envTexture) { 13591 const material = _getMaterial("cubemap"); 13592 material.fragmentNode = cubeTexture(envTexture, _outputDirection); 13593 return material; 13594} 13595function _getEquirectMaterial(envTexture) { 13596 const material = _getMaterial("equirect"); 13597 material.fragmentNode = texture(envTexture, equirectUV(_outputDirection), 0); 13598 return material; 13599} 13600var _cache = /* @__PURE__ */ new WeakMap(); 13601function _generateCubeUVSize(imageHeight) { 13602 const maxMip = Math.log2(imageHeight) - 2; 13603 const texelHeight = 1 / imageHeight; 13604 const texelWidth = 1 / (3 * Math.max(Math.pow(2, maxMip), 7 * 16)); 13605 return { texelWidth, texelHeight, maxMip }; 13606} 13607function _getPMREMFromTexture(texture3, renderer, generator) { 13608 const cache4 = _getCache(renderer); 13609 let cacheTexture = cache4.get(texture3); 13610 const pmremVersion = cacheTexture !== void 0 ? cacheTexture.pmremVersion : -1; 13611 if (pmremVersion !== texture3.pmremVersion) { 13612 const image = texture3.image; 13613 if (texture3.isCubeTexture) { 13614 if (isCubeMapReady(image)) { 13615 cacheTexture = generator.fromCubemap(texture3, cacheTexture); 13616 } else { 13617 return null; 13618 } 13619 } else { 13620 if (isEquirectangularMapReady(image)) { 13621 cacheTexture = generator.fromEquirectangular(texture3, cacheTexture); 13622 } else { 13623 return null; 13624 } 13625 } 13626 cacheTexture.pmremVersion = texture3.pmremVersion; 13627 cache4.set(texture3, cacheTexture); 13628 } 13629 return cacheTexture.texture; 13630} 13631function _getCache(renderer) { 13632 let rendererCache = _cache.get(renderer); 13633 if (rendererCache === void 0) { 13634 rendererCache = /* @__PURE__ */ new WeakMap(); 13635 _cache.set(renderer, rendererCache); 13636 } 13637 return rendererCache; 13638} 13639var PMREMNode = class extends TempNode { 13640 static get type() { 13641 return "PMREMNode"; 13642 } 13643 /** 13644 * Constructs a new function overloading node. 13645 * 13646 * @param {Texture} value - The input texture. 13647 * @param {Node<vec2>} [uvNode=null] - The uv node. 13648 * @param {Node<float>} [levelNode=null] - The level node. 13649 */ 13650 constructor(value, uvNode = null, levelNode = null) { 13651 super("vec3"); 13652 this._value = value; 13653 this._pmrem = null; 13654 this.uvNode = uvNode; 13655 this.levelNode = levelNode; 13656 this._generator = null; 13657 const defaultTexture = new Texture(); 13658 defaultTexture.isRenderTargetTexture = true; 13659 this._texture = texture(defaultTexture); 13660 this._width = uniform(0); 13661 this._height = uniform(0); 13662 this._maxMip = uniform(0); 13663 this.updateBeforeType = NodeUpdateType.RENDER; 13664 } 13665 set value(value) { 13666 this._value = value; 13667 this._pmrem = null; 13668 } 13669 /** 13670 * The node's texture value. 13671 * 13672 * @type {Texture} 13673 */ 13674 get value() { 13675 return this._value; 13676 } 13677 /** 13678 * Uses the given PMREM texture to update internal values. 13679 * 13680 * @param {Texture} texture - The PMREM texture. 13681 */ 13682 updateFromTexture(texture3) { 13683 const cubeUVSize = _generateCubeUVSize(texture3.image.height); 13684 this._texture.value = texture3; 13685 this._width.value = cubeUVSize.texelWidth; 13686 this._height.value = cubeUVSize.texelHeight; 13687 this._maxMip.value = cubeUVSize.maxMip; 13688 } 13689 updateBefore(frame) { 13690 let pmrem = this._pmrem; 13691 const pmremVersion = pmrem ? pmrem.pmremVersion : -1; 13692 const texture3 = this._value; 13693 if (pmremVersion !== texture3.pmremVersion) { 13694 if (texture3.isPMREMTexture === true) { 13695 pmrem = texture3; 13696 } else { 13697 pmrem = _getPMREMFromTexture(texture3, frame.renderer, this._generator); 13698 } 13699 if (pmrem !== null) { 13700 this._pmrem = pmrem; 13701 this.updateFromTexture(pmrem); 13702 } 13703 } 13704 } 13705 setup(builder) { 13706 if (this._generator === null) { 13707 this._generator = new PMREMGenerator(builder.renderer); 13708 } 13709 this.updateBefore(builder); 13710 let uvNode = this.uvNode; 13711 if (uvNode === null && builder.context.getUV) { 13712 uvNode = builder.context.getUV(this, builder); 13713 } 13714 uvNode = materialEnvRotation.mul(vec3(uvNode.x, uvNode.y.negate(), uvNode.z)); 13715 let levelNode = this.levelNode; 13716 if (levelNode === null && builder.context.getTextureLevel) { 13717 levelNode = builder.context.getTextureLevel(this); 13718 } 13719 return textureCubeUV(this._texture, uvNode, levelNode, this._width, this._height, this._maxMip); 13720 } 13721 dispose() { 13722 super.dispose(); 13723 if (this._generator !== null) this._generator.dispose(); 13724 } 13725}; 13726function isCubeMapReady(image) { 13727 if (image === null || image === void 0) return false; 13728 let count = 0; 13729 const length3 = 6; 13730 for (let i = 0; i < length3; i++) { 13731 if (image[i] !== void 0) count++; 13732 } 13733 return count === length3; 13734} 13735function isEquirectangularMapReady(image) { 13736 if (image === null || image === void 0) return false; 13737 return image.height > 0; 13738} 13739var pmremTexture = /* @__PURE__ */ nodeProxy(PMREMNode).setParameterLength(1, 3); 13740var _rendererCache = /* @__PURE__ */ new WeakMap(); 13741var EnvironmentNode = class extends LightingNode { 13742 static get type() { 13743 return "EnvironmentNode"; 13744 } 13745 /** 13746 * Constructs a new environment node. 13747 * 13748 * @param {Node} [envNode=null] - A node representing the environment. 13749 */ 13750 constructor(envNode = null) { 13751 super(); 13752 this.envNode = envNode; 13753 } 13754 setup(builder) { 13755 const { material } = builder; 13756 let envNode = this.envNode; 13757 if (envNode.isTextureNode || envNode.isMaterialReferenceNode) { 13758 const value = envNode.isTextureNode ? envNode.value : material[envNode.property]; 13759 const cache4 = this._getPMREMNodeCache(builder.renderer); 13760 let cacheEnvNode = cache4.get(value); 13761 if (cacheEnvNode === void 0) { 13762 cacheEnvNode = pmremTexture(value); 13763 cache4.set(value, cacheEnvNode); 13764 } 13765 envNode = cacheEnvNode; 13766 } 13767 const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0; 13768 const radianceNormalView = useAnisotropy ? bentNormalView : normalView; 13769 const radiance = envNode.context(createRadianceContext(roughness, radianceNormalView)).mul(materialEnvIntensity); 13770 const irradiance = envNode.context(createIrradianceContext(normalWorld)).mul(Math.PI).mul(materialEnvIntensity); 13771 const isolateRadiance = isolate(radiance); 13772 const isolateIrradiance = isolate(irradiance); 13773 builder.context.radiance.addAssign(isolateRadiance); 13774 builder.context.iblIrradiance.addAssign(isolateIrradiance); 13775 const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance; 13776 if (clearcoatRadiance) { 13777 const clearcoatRadianceContext = envNode.context(createRadianceContext(clearcoatRoughness, clearcoatNormalView)).mul(materialEnvIntensity); 13778 const isolateClearcoatRadiance = isolate(clearcoatRadianceContext); 13779 clearcoatRadiance.addAssign(isolateClearcoatRadiance); 13780 } 13781 } 13782 /** 13783 * Returns the PMREM node cache of the current renderer. 13784 * 13785 * @private 13786 * @param {Renderer} renderer - The current renderer. 13787 * @return {WeakMap} The node cache. 13788 */ 13789 _getPMREMNodeCache(renderer) { 13790 let pmremCache = _rendererCache.get(renderer); 13791 if (pmremCache === void 0) { 13792 pmremCache = /* @__PURE__ */ new WeakMap(); 13793 _rendererCache.set(renderer, pmremCache); 13794 } 13795 return pmremCache; 13796 } 13797}; 13798var createRadianceContext = (roughnessNode, normalViewNode) => { 13799 let reflectVec = null; 13800 return { 13801 getUV: () => { 13802 if (reflectVec === null) { 13803 reflectVec = positionViewDirection.negate().reflect(normalViewNode); 13804 reflectVec = pow4(roughnessNode).mix(reflectVec, normalViewNode).normalize(); 13805 reflectVec = reflectVec.transformDirection(cameraViewMatrix); 13806 } 13807 return reflectVec; 13808 }, 13809 getTextureLevel: () => { 13810 return roughnessNode; 13811 } 13812 }; 13813}; 13814var createIrradianceContext = (normalWorldNode) => { 13815 return { 13816 getUV: () => { 13817 return normalWorldNode; 13818 }, 13819 getTextureLevel: () => { 13820 return float(1); 13821 } 13822 }; 13823}; 13824var _defaultValues$6 = /* @__PURE__ */ new MeshStandardMaterial(); 13825var MeshStandardNodeMaterial = class extends NodeMaterial { 13826 static get type() { 13827 return "MeshStandardNodeMaterial"; 13828 } 13829 /** 13830 * Constructs a new mesh standard node material. 13831 * 13832 * @param {Object} [parameters] - The configuration parameter. 13833 */ 13834 constructor(parameters) { 13835 super(); 13836 this.isMeshStandardNodeMaterial = true; 13837 this.lights = true; 13838 this.emissiveNode = null; 13839 this.metalnessNode = null; 13840 this.roughnessNode = null; 13841 this.setDefaultValues(_defaultValues$6); 13842 this.setValues(parameters); 13843 } 13844 /** 13845 * Overwritten since this type of material uses {@link EnvironmentNode} 13846 * to implement the PBR (PMREM based) environment mapping. Besides, the 13847 * method honors `Scene.environment`. 13848 * 13849 * @param {NodeBuilder} builder - The current node builder. 13850 * @return {?EnvironmentNode<vec3>} The environment node. 13851 */ 13852 setupEnvironment(builder) { 13853 let envNode = super.setupEnvironment(builder); 13854 if (envNode === null && builder.environmentNode) { 13855 envNode = builder.environmentNode; 13856 } 13857 return envNode ? new EnvironmentNode(envNode) : null; 13858 } 13859 /** 13860 * Setups the lighting model. 13861 * 13862 * @return {PhysicalLightingModel} The lighting model. 13863 */ 13864 setupLightingModel() { 13865 return new PhysicalLightingModel(); 13866 } 13867 /** 13868 * Setups the specular related node variables. 13869 */ 13870 setupSpecular() { 13871 const specularColorNode = mix(vec3(0.04), diffuseColor.rgb, metalness); 13872 specularColor.assign(vec3(0.04)); 13873 specularColorBlended.assign(specularColorNode); 13874 specularF90.assign(1); 13875 } 13876 /** 13877 * Setups the standard specific node variables. 13878 * 13879 * @param {NodeBuilder} builder - The current node builder. 13880 */ 13881 setupVariants() { 13882 const metalnessNode = this.metalnessNode ? float(this.metalnessNode) : materialMetalness; 13883 metalness.assign(metalnessNode); 13884 let roughnessNode = this.roughnessNode ? float(this.roughnessNode) : materialRoughness; 13885 roughnessNode = getRoughness({ roughness: roughnessNode }); 13886 roughness.assign(roughnessNode); 13887 this.setupSpecular(); 13888 diffuseContribution.assign(diffuseColor.rgb.mul(metalnessNode.oneMinus())); 13889 } 13890 copy(source) { 13891 this.emissiveNode = source.emissiveNode; 13892 this.metalnessNode = source.metalnessNode; 13893 this.roughnessNode = source.roughnessNode; 13894 return super.copy(source); 13895 } 13896}; 13897var _defaultValues$5 = /* @__PURE__ */ new MeshPhysicalMaterial(); 13898var MeshPhysicalNodeMaterial = class extends MeshStandardNodeMaterial { 13899 static get type() { 13900 return "MeshPhysicalNodeMaterial"; 13901 } 13902 /** 13903 * Constructs a new mesh physical node material. 13904 * 13905 * @param {Object} [parameters] - The configuration parameter. 13906 */ 13907 constructor(parameters) { 13908 super(); 13909 this.isMeshPhysicalNodeMaterial = true; 13910 this.clearcoatNode = null; 13911 this.clearcoatRoughnessNode = null; 13912 this.clearcoatNormalNode = null; 13913 this.sheenNode = null; 13914 this.sheenRoughnessNode = null; 13915 this.iridescenceNode = null; 13916 this.iridescenceIORNode = null; 13917 this.iridescenceThicknessNode = null; 13918 this.specularIntensityNode = null; 13919 this.specularColorNode = null; 13920 this.iorNode = null; 13921 this.transmissionNode = null; 13922 this.thicknessNode = null; 13923 this.attenuationDistanceNode = null; 13924 this.attenuationColorNode = null; 13925 this.dispersionNode = null; 13926 this.anisotropyNode = null; 13927 this.setDefaultValues(_defaultValues$5); 13928 this.setValues(parameters); 13929 } 13930 /** 13931 * Whether the lighting model should use clearcoat or not. 13932 * 13933 * @type {boolean} 13934 * @default true 13935 */ 13936 get useClearcoat() { 13937 return this.clearcoat > 0 || this.clearcoatNode !== null; 13938 } 13939 /** 13940 * Whether the lighting model should use iridescence or not. 13941 * 13942 * @type {boolean} 13943 * @default true 13944 */ 13945 get useIridescence() { 13946 return this.iridescence > 0 || this.iridescenceNode !== null; 13947 } 13948 /** 13949 * Whether the lighting model should use sheen or not. 13950 * 13951 * @type {boolean} 13952 * @default true 13953 */ 13954 get useSheen() { 13955 return this.sheen > 0 || this.sheenNode !== null; 13956 } 13957 /** 13958 * Whether the lighting model should use anisotropy or not. 13959 * 13960 * @type {boolean} 13961 * @default true 13962 */ 13963 get useAnisotropy() { 13964 return this.anisotropy > 0 || this.anisotropyNode !== null; 13965 } 13966 /** 13967 * Whether the lighting model should use transmission or not. 13968 * 13969 * @type {boolean} 13970 * @default true 13971 */ 13972 get useTransmission() { 13973 return this.transmission > 0 || this.transmissionNode !== null; 13974 } 13975 /** 13976 * Whether the lighting model should use dispersion or not. 13977 * 13978 * @type {boolean} 13979 * @default true 13980 */ 13981 get useDispersion() { 13982 return this.dispersion > 0 || this.dispersionNode !== null; 13983 } 13984 /** 13985 * Setups the specular related node variables. 13986 */ 13987 setupSpecular() { 13988 const iorNode = this.iorNode ? float(this.iorNode) : materialIOR; 13989 ior.assign(iorNode); 13990 specularColor.assign(min$1(pow2(ior.sub(1).div(ior.add(1))).mul(materialSpecularColor), vec3(1)).mul(materialSpecularIntensity)); 13991 specularColorBlended.assign(mix(specularColor, diffuseColor.rgb, metalness)); 13992 specularF90.assign(mix(materialSpecularIntensity, 1, metalness)); 13993 } 13994 /** 13995 * Setups the lighting model. 13996 * 13997 * @return {PhysicalLightingModel} The lighting model. 13998 */ 13999 setupLightingModel() { 14000 return new PhysicalLightingModel(this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion); 14001 } 14002 /** 14003 * Setups the physical specific node variables. 14004 * 14005 * @param {NodeBuilder} builder - The current node builder. 14006 */ 14007 setupVariants(builder) { 14008 super.setupVariants(builder); 14009 if (this.useClearcoat) { 14010 const clearcoatNode = this.clearcoatNode ? float(this.clearcoatNode) : materialClearcoat; 14011 const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float(this.clearcoatRoughnessNode) : materialClearcoatRoughness; 14012 clearcoat.assign(clearcoatNode); 14013 clearcoatRoughness.assign(getRoughness({ roughness: clearcoatRoughnessNode })); 14014 } 14015 if (this.useSheen) { 14016 const sheenNode = this.sheenNode ? vec3(this.sheenNode) : materialSheen; 14017 const sheenRoughnessNode = this.sheenRoughnessNode ? float(this.sheenRoughnessNode) : materialSheenRoughness; 14018 sheen.assign(sheenNode); 14019 sheenRoughness.assign(sheenRoughnessNode); 14020 } 14021 if (this.useIridescence) { 14022 const iridescenceNode = this.iridescenceNode ? float(this.iridescenceNode) : materialIridescence; 14023 const iridescenceIORNode = this.iridescenceIORNode ? float(this.iridescenceIORNode) : materialIridescenceIOR; 14024 const iridescenceThicknessNode = this.iridescenceThicknessNode ? float(this.iridescenceThicknessNode) : materialIridescenceThickness; 14025 iridescence.assign(iridescenceNode); 14026 iridescenceIOR.assign(iridescenceIORNode); 14027 iridescenceThickness.assign(iridescenceThicknessNode); 14028 } 14029 if (this.useAnisotropy) { 14030 const anisotropyV = (this.anisotropyNode ? vec2(this.anisotropyNode) : materialAnisotropy).toVar(); 14031 anisotropy.assign(anisotropyV.length()); 14032 If(anisotropy.equal(0), () => { 14033 anisotropyV.assign(vec2(1, 0)); 14034 }).Else(() => { 14035 anisotropyV.divAssign(vec2(anisotropy)); 14036 anisotropy.assign(anisotropy.saturate()); 14037 }); 14038 alphaT.assign(anisotropy.pow2().mix(roughness.pow2(), 1)); 14039 anisotropyT.assign(TBNViewMatrix[0].mul(anisotropyV.x).add(TBNViewMatrix[1].mul(anisotropyV.y))); 14040 anisotropyB.assign(TBNViewMatrix[1].mul(anisotropyV.x).sub(TBNViewMatrix[0].mul(anisotropyV.y))); 14041 } 14042 if (this.useTransmission) { 14043 const transmissionNode = this.transmissionNode ? float(this.transmissionNode) : materialTransmission; 14044 const thicknessNode = this.thicknessNode ? float(this.thicknessNode) : materialThickness; 14045 const attenuationDistanceNode = this.attenuationDistanceNode ? float(this.attenuationDistanceNode) : materialAttenuationDistance; 14046 const attenuationColorNode = this.attenuationColorNode ? vec3(this.attenuationColorNode) : materialAttenuationColor; 14047 transmission.assign(transmissionNode); 14048 thickness.assign(thicknessNode); 14049 attenuationDistance.assign(attenuationDistanceNode); 14050 attenuationColor.assign(attenuationColorNode); 14051 if (this.useDispersion) { 14052 const dispersionNode = this.dispersionNode ? float(this.dispersionNode) : materialDispersion; 14053 dispersion.assign(dispersionNode); 14054 } 14055 } 14056 } 14057 /** 14058 * Setups the clearcoat normal node. 14059 * 14060 * @return {Node<vec3>} The clearcoat normal. 14061 */ 14062 setupClearcoatNormal() { 14063 return this.clearcoatNormalNode ? vec3(this.clearcoatNormalNode) : materialClearcoatNormal; 14064 } 14065 setup(builder) { 14066 builder.context.setupClearcoatNormal = () => subBuild(this.setupClearcoatNormal(builder), "NORMAL", "vec3"); 14067 super.setup(builder); 14068 } 14069 copy(source) { 14070 this.clearcoatNode = source.clearcoatNode; 14071 this.clearcoatRoughnessNode = source.clearcoatRoughnessNode; 14072 this.clearcoatNormalNode = source.clearcoatNormalNode; 14073 this.sheenNode = source.sheenNode; 14074 this.sheenRoughnessNode = source.sheenRoughnessNode; 14075 this.iridescenceNode = source.iridescenceNode; 14076 this.iridescenceIORNode = source.iridescenceIORNode; 14077 this.iridescenceThicknessNode = source.iridescenceThicknessNode; 14078 this.specularIntensityNode = source.specularIntensityNode; 14079 this.specularColorNode = source.specularColorNode; 14080 this.iorNode = source.iorNode; 14081 this.transmissionNode = source.transmissionNode; 14082 this.thicknessNode = source.thicknessNode; 14083 this.attenuationDistanceNode = source.attenuationDistanceNode; 14084 this.attenuationColorNode = source.attenuationColorNode; 14085 this.dispersionNode = source.dispersionNode; 14086 this.anisotropyNode = source.anisotropyNode; 14087 return super.copy(source); 14088 } 14089}; 14090var getGradientIrradiance = /* @__PURE__ */ Fn(({ normal: normal2, lightDirection, builder }) => { 14091 const dotNL = normal2.dot(lightDirection); 14092 const coord = vec2(dotNL.mul(0.5).add(0.5), 0); 14093 if (builder.material.gradientMap) { 14094 const gradientMap = materialReference("gradientMap", "texture").context({ getUV: () => coord }); 14095 return vec3(gradientMap.r); 14096 } else { 14097 const fw = coord.fwidth().mul(0.5); 14098 return mix(vec3(0.7), vec3(1), smoothstep(float(0.7).sub(fw.x), float(0.7).add(fw.x), coord.x)); 14099 } 14100}); 14101var ToonLightingModel = class extends LightingModel { 14102 /** 14103 * Implements the direct lighting. Instead of using a conventional smooth irradiance, the irradiance is 14104 * reduced to a small number of discrete shades to create a comic-like, flat look. 14105 * 14106 * @param {Object} lightData - The light data. 14107 * @param {NodeBuilder} builder - The current node builder. 14108 */ 14109 direct({ lightDirection, lightColor, reflectedLight }, builder) { 14110 const irradiance = getGradientIrradiance({ normal: normalGeometry, lightDirection, builder }).mul(lightColor); 14111 reflectedLight.directDiffuse.addAssign(irradiance.mul(BRDF_Lambert({ diffuseColor: diffuseColor.rgb }))); 14112 } 14113 /** 14114 * Implements the indirect lighting. 14115 * 14116 * @param {NodeBuilder} builder - The current node builder. 14117 */ 14118 indirect(builder) { 14119 const { ambientOcclusion, irradiance, reflectedLight } = builder.context; 14120 reflectedLight.indirectDiffuse.addAssign(irradiance.mul(BRDF_Lambert({ diffuseColor }))); 14121 reflectedLight.indirectDiffuse.mulAssign(ambientOcclusion); 14122 } 14123}; 14124var _defaultValues$4 = /* @__PURE__ */ new MeshToonMaterial(); 14125var MeshToonNodeMaterial = class extends NodeMaterial { 14126 static get type() { 14127 return "MeshToonNodeMaterial"; 14128 } 14129 /** 14130 * Constructs a new mesh toon node material. 14131 * 14132 * @param {Object} [parameters] - The configuration parameter. 14133 */ 14134 constructor(parameters) { 14135 super(); 14136 this.isMeshToonNodeMaterial = true; 14137 this.lights = true; 14138 this.setDefaultValues(_defaultValues$4); 14139 this.setValues(parameters); 14140 } 14141 /** 14142 * Setups the lighting model. 14143 * 14144 * @return {ToonLightingModel} The lighting model. 14145 */ 14146 setupLightingModel() { 14147 return new ToonLightingModel(); 14148 } 14149}; 14150var matcapUV = /* @__PURE__ */ Fn(() => { 14151 const x = vec3(positionViewDirection.z, 0, positionViewDirection.x.negate()).normalize(); 14152 const y = positionViewDirection.cross(x); 14153 return vec2(x.dot(normalView), y.dot(normalView)).mul(0.495).add(0.5); 14154}).once(["NORMAL", "VERTEX"])().toVar("matcapUV"); 14155var _defaultValues$3 = /* @__PURE__ */ new MeshMatcapMaterial(); 14156var MeshMatcapNodeMaterial = class extends NodeMaterial { 14157 static get type() { 14158 return "MeshMatcapNodeMaterial"; 14159 } 14160 /** 14161 * Constructs a new mesh normal node material. 14162 * 14163 * @param {Object} [parameters] - The configuration parameter. 14164 */ 14165 constructor(parameters) { 14166 super(); 14167 this.isMeshMatcapNodeMaterial = true; 14168 this.setDefaultValues(_defaultValues$3); 14169 this.setValues(parameters); 14170 } 14171 /** 14172 * Setups the matcap specific node variables. 14173 * 14174 * @param {NodeBuilder} builder - The current node builder. 14175 */ 14176 setupVariants(builder) { 14177 const uv3 = matcapUV; 14178 let matcapColor; 14179 if (builder.material.matcap) { 14180 matcapColor = materialReference("matcap", "texture").context({ getUV: () => uv3 }); 14181 } else { 14182 matcapColor = vec3(mix(0.2, 0.8, uv3.y)); 14183 } 14184 diffuseColor.rgb.mulAssign(matcapColor.rgb); 14185 } 14186}; 14187var RotateNode = class extends TempNode { 14188 static get type() { 14189 return "RotateNode"; 14190 } 14191 /** 14192 * Constructs a new rotate node. 14193 * 14194 * @param {Node} positionNode - The position node. 14195 * @param {Node} rotationNode - Represents the rotation that is applied to the position node. Depending 14196 * on whether the position data are 2D or 3D, the rotation is expressed a single float value or an Euler value. 14197 */ 14198 constructor(positionNode, rotationNode) { 14199 super(); 14200 this.positionNode = positionNode; 14201 this.rotationNode = rotationNode; 14202 } 14203 /** 14204 * The type of the {@link RotateNode#positionNode} defines the node's type. 14205 * 14206 * @param {NodeBuilder} builder - The current node builder. 14207 * @return {string} The node's type. 14208 */ 14209 generateNodeType(builder) { 14210 return this.positionNode.getNodeType(builder); 14211 } 14212 setup(builder) { 14213 const { rotationNode, positionNode } = this; 14214 const nodeType = this.getNodeType(builder); 14215 if (nodeType === "vec2") { 14216 const cosAngle = rotationNode.cos(); 14217 const sinAngle = rotationNode.sin(); 14218 const rotationMatrix = mat2( 14219 cosAngle, 14220 sinAngle, 14221 sinAngle.negate(), 14222 cosAngle 14223 ); 14224 return rotationMatrix.mul(positionNode); 14225 } else { 14226 const rotation = rotationNode; 14227 const rotationXMatrix = mat4(vec4(1, 0, 0, 0), vec4(0, cos(rotation.x), sin(rotation.x).negate(), 0), vec4(0, sin(rotation.x), cos(rotation.x), 0), vec4(0, 0, 0, 1)); 14228 const rotationYMatrix = mat4(vec4(cos(rotation.y), 0, sin(rotation.y), 0), vec4(0, 1, 0, 0), vec4(sin(rotation.y).negate(), 0, cos(rotation.y), 0), vec4(0, 0, 0, 1)); 14229 const rotationZMatrix = mat4(vec4(cos(rotation.z), sin(rotation.z).negate(), 0, 0), vec4(sin(rotation.z), cos(rotation.z), 0, 0), vec4(0, 0, 1, 0), vec4(0, 0, 0, 1)); 14230 return rotationXMatrix.mul(rotationYMatrix).mul(rotationZMatrix).mul(vec4(positionNode, 1)).xyz; 14231 } 14232 } 14233}; 14234var rotate = /* @__PURE__ */ nodeProxy(RotateNode).setParameterLength(2); 14235var _defaultValues$2 = /* @__PURE__ */ new SpriteMaterial(); 14236var SpriteNodeMaterial = class extends NodeMaterial { 14237 static get type() { 14238 return "SpriteNodeMaterial"; 14239 } 14240 /** 14241 * Constructs a new sprite node material. 14242 * 14243 * @param {Object} [parameters] - The configuration parameter. 14244 */ 14245 constructor(parameters) { 14246 super(); 14247 this.isSpriteNodeMaterial = true; 14248 this._useSizeAttenuation = true; 14249 this.positionNode = null; 14250 this.rotationNode = null; 14251 this.scaleNode = null; 14252 this.transparent = true; 14253 this.setDefaultValues(_defaultValues$2); 14254 this.setValues(parameters); 14255 } 14256 /** 14257 * Setups the position node in view space. This method implements 14258 * the sprite specific vertex shader. 14259 * 14260 * @param {NodeBuilder} builder - The current node builder. 14261 * @return {Node<vec3>} The position in view space. 14262 */ 14263 setupPositionView(builder) { 14264 const { object, camera } = builder; 14265 const { positionNode, rotationNode, scaleNode, sizeAttenuation } = this; 14266 const mvPosition = modelViewMatrix.mul(vec3(positionNode || 0)); 14267 let scale2 = vec2(modelWorldMatrix[0].xyz.length(), modelWorldMatrix[1].xyz.length()); 14268 if (scaleNode !== null) { 14269 scale2 = scale2.mul(vec2(scaleNode)); 14270 } 14271 if (camera.isPerspectiveCamera && sizeAttenuation === false) { 14272 scale2 = scale2.mul(mvPosition.z.negate()); 14273 } 14274 let alignedPosition = positionGeometry.xy; 14275 if (object.center && object.center.isVector2 === true) { 14276 const center = reference$1("center", "vec2", object); 14277 alignedPosition = alignedPosition.sub(center.sub(0.5)); 14278 } 14279 alignedPosition = alignedPosition.mul(scale2); 14280 const rotation = float(rotationNode || materialRotation); 14281 const rotatedPosition = rotate(alignedPosition, rotation); 14282 return vec4(mvPosition.xy.add(rotatedPosition), mvPosition.zw); 14283 } 14284 copy(source) { 14285 this.positionNode = source.positionNode; 14286 this.rotationNode = source.rotationNode; 14287 this.scaleNode = source.scaleNode; 14288 return super.copy(source); 14289 } 14290 /** 14291 * Whether to use size attenuation or not. 14292 * 14293 * @type {boolean} 14294 * @default true 14295 */ 14296 get sizeAttenuation() { 14297 return this._useSizeAttenuation; 14298 } 14299 set sizeAttenuation(value) { 14300 if (this._useSizeAttenuation !== value) { 14301 this._useSizeAttenuation = value; 14302 this.needsUpdate = true; 14303 } 14304 } 14305}; 14306var _defaultValues$1 = /* @__PURE__ */ new PointsMaterial(); 14307var _size$4 = /* @__PURE__ */ new Vector2(); 14308var PointsNodeMaterial = class extends SpriteNodeMaterial { 14309 static get type() { 14310 return "PointsNodeMaterial"; 14311 } 14312 /** 14313 * Constructs a new points node material. 14314 * 14315 * @param {Object} [parameters] - The configuration parameter. 14316 */ 14317 constructor(parameters) { 14318 super(); 14319 this.sizeNode = null; 14320 this.isPointsNodeMaterial = true; 14321 this.setDefaultValues(_defaultValues$1); 14322 this.setValues(parameters); 14323 } 14324 setupPositionView() { 14325 const { positionNode } = this; 14326 return modelViewMatrix.mul(vec3(positionNode || positionLocal)).xyz; 14327 } 14328 setupVertexSprite(builder) { 14329 const { material, camera } = builder; 14330 const { rotationNode, scaleNode, sizeNode, sizeAttenuation } = this; 14331 let mvp = super.setupVertex(builder); 14332 if (material.isNodeMaterial !== true) { 14333 return mvp; 14334 } 14335 let pointSize = sizeNode !== null ? vec2(sizeNode) : materialPointSize; 14336 pointSize = pointSize.mul(screenDPR); 14337 if (camera.isPerspectiveCamera && sizeAttenuation === true) { 14338 pointSize = pointSize.mul(scale.div(positionView.z.negate())); 14339 } 14340 if (scaleNode && scaleNode.isNode) { 14341 pointSize = pointSize.mul(vec2(scaleNode)); 14342 } 14343 let offset3 = positionGeometry.xy; 14344 if (rotationNode && rotationNode.isNode) { 14345 const rotation = float(rotationNode); 14346 offset3 = rotate(offset3, rotation); 14347 } 14348 offset3 = offset3.mul(pointSize); 14349 offset3 = offset3.div(viewportSize.div(2)); 14350 offset3 = offset3.mul(mvp.w); 14351 mvp = mvp.add(vec4(offset3, 0, 0)); 14352 return mvp; 14353 } 14354 setupVertex(builder) { 14355 if (builder.object.isPoints) { 14356 return super.setupVertex(builder); 14357 } else { 14358 return this.setupVertexSprite(builder); 14359 } 14360 } 14361 /** 14362 * Whether alpha to coverage should be used or not. 14363 * 14364 * @type {boolean} 14365 * @default true 14366 */ 14367 get alphaToCoverage() { 14368 return this._useAlphaToCoverage; 14369 } 14370 set alphaToCoverage(value) { 14371 if (this._useAlphaToCoverage !== value) { 14372 this._useAlphaToCoverage = value; 14373 this.needsUpdate = true; 14374 } 14375 } 14376}; 14377var scale = /* @__PURE__ */ uniform(1).onFrameUpdate(function({ renderer }) { 14378 const size3 = renderer.getSize(_size$4); 14379 this.value = 0.5 * size3.y; 14380}); 14381var ShadowMaskModel = class extends LightingModel { 14382 /** 14383 * Constructs a new shadow mask model. 14384 */ 14385 constructor() { 14386 super(); 14387 this.shadowNode = float(1).toVar("shadowMask"); 14388 } 14389 /** 14390 * Only used to save the shadow mask. 14391 * 14392 * @param {Object} input - The input data. 14393 */ 14394 direct({ lightNode }) { 14395 if (lightNode.shadowNode !== null) { 14396 this.shadowNode.mulAssign(lightNode.shadowNode); 14397 } 14398 } 14399 /** 14400 * Uses the shadow mask to produce the final color. 14401 * 14402 * @param {NodeBuilder} builder - The current node builder. 14403 */ 14404 finish({ context: context3 }) { 14405 diffuseColor.a.mulAssign(this.shadowNode.oneMinus()); 14406 context3.outgoingLight.rgb.assign(diffuseColor.rgb); 14407 } 14408}; 14409var _defaultValues = /* @__PURE__ */ new ShadowMaterial(); 14410var ShadowNodeMaterial = class extends NodeMaterial { 14411 static get type() { 14412 return "ShadowNodeMaterial"; 14413 } 14414 /** 14415 * Constructs a new shadow node material. 14416 * 14417 * @param {Object} [parameters] - The configuration parameter. 14418 */ 14419 constructor(parameters) { 14420 super(); 14421 this.isShadowNodeMaterial = true; 14422 this.lights = true; 14423 this.transparent = true; 14424 this.setDefaultValues(_defaultValues); 14425 this.setValues(parameters); 14426 } 14427 /** 14428 * Setups the lighting model. 14429 * 14430 * @return {ShadowMaskModel} The lighting model. 14431 */ 14432 setupLightingModel() { 14433 return new ShadowMaskModel(); 14434 } 14435}; 14436var scatteringDensity = property("vec3"); 14437var linearDepthRay = property("vec3"); 14438var outgoingRayLight = property("vec3"); 14439var Animation = class { 14440 /** 14441 * Constructs a new animation loop management component. 14442 * 14443 * @param {Renderer} renderer - A reference to the main renderer. 14444 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 14445 * @param {Info} info - Renderer component for managing metrics and monitoring data. 14446 */ 14447 constructor(renderer, nodes, info) { 14448 this.renderer = renderer; 14449 this.nodes = nodes; 14450 this.info = info; 14451 this._context = typeof self !== "undefined" ? self : null; 14452 this._animationLoop = null; 14453 this._requestId = null; 14454 } 14455 /** 14456 * Starts the internal animation loop. 14457 */ 14458 start() { 14459 const update = (time3, xrFrame) => { 14460 this._requestId = this._context.requestAnimationFrame(update); 14461 if (this.info.autoReset === true) this.info.reset(); 14462 this.nodes.nodeFrame.update(); 14463 this.info.frame = this.nodes.nodeFrame.frameId; 14464 this.renderer._inspector.begin(); 14465 if (this._animationLoop !== null) this._animationLoop(time3, xrFrame); 14466 this.renderer._inspector.finish(); 14467 }; 14468 update(); 14469 } 14470 /** 14471 * Stops the internal animation loop. 14472 */ 14473 stop() { 14474 if (this._context !== null) this._context.cancelAnimationFrame(this._requestId); 14475 this._requestId = null; 14476 } 14477 /** 14478 * Returns the user-level animation loop. 14479 * 14480 * @return {?Function} The animation loop. 14481 */ 14482 getAnimationLoop() { 14483 return this._animationLoop; 14484 } 14485 /** 14486 * Defines the user-level animation loop. 14487 * 14488 * @param {?Function} callback - The animation loop. 14489 */ 14490 setAnimationLoop(callback) { 14491 this._animationLoop = callback; 14492 } 14493 /** 14494 * Returns the animation context. 14495 * 14496 * @return {Window|XRSession} The animation context. 14497 */ 14498 getContext() { 14499 return this._context; 14500 } 14501 /** 14502 * Defines the context in which `requestAnimationFrame()` is executed. 14503 * 14504 * @param {Window|XRSession} context - The context to set. 14505 */ 14506 setContext(context3) { 14507 this._context = context3; 14508 } 14509 /** 14510 * Frees all internal resources and stops the animation loop. 14511 */ 14512 dispose() { 14513 this.stop(); 14514 } 14515}; 14516var ChainMap = class { 14517 /** 14518 * Constructs a new Chain Map. 14519 */ 14520 constructor() { 14521 this.weakMaps = {}; 14522 } 14523 /** 14524 * Returns the Weak Map for the given keys. 14525 * 14526 * @param {Array<Object>} keys - List of keys. 14527 * @return {WeakMap} The weak map. 14528 */ 14529 _getWeakMap(keys5) { 14530 const length3 = keys5.length; 14531 let weakMap = this.weakMaps[length3]; 14532 if (weakMap === void 0) { 14533 weakMap = /* @__PURE__ */ new WeakMap(); 14534 this.weakMaps[length3] = weakMap; 14535 } 14536 return weakMap; 14537 } 14538 /** 14539 * Returns the value for the given array of keys. 14540 * 14541 * @param {Array<Object>} keys - List of keys. 14542 * @return {any} The value. Returns `undefined` if no value was found. 14543 */ 14544 get(keys5) { 14545 let map = this._getWeakMap(keys5); 14546 for (let i = 0; i < keys5.length - 1; i++) { 14547 map = map.get(keys5[i]); 14548 if (map === void 0) return void 0; 14549 } 14550 return map.get(keys5[keys5.length - 1]); 14551 } 14552 /** 14553 * Sets the value for the given keys. 14554 * 14555 * @param {Array<Object>} keys - List of keys. 14556 * @param {any} value - The value to set. 14557 * @return {ChainMap} A reference to this Chain Map. 14558 */ 14559 set(keys5, value) { 14560 let map = this._getWeakMap(keys5); 14561 for (let i = 0; i < keys5.length - 1; i++) { 14562 const key = keys5[i]; 14563 if (map.has(key) === false) map.set(key, /* @__PURE__ */ new WeakMap()); 14564 map = map.get(key); 14565 } 14566 map.set(keys5[keys5.length - 1], value); 14567 return this; 14568 } 14569 /** 14570 * Deletes a value for the given keys. 14571 * 14572 * @param {Array<Object>} keys - The keys. 14573 * @return {boolean} Returns `true` if the value has been removed successfully and `false` if the value has not be found. 14574 */ 14575 delete(keys5) { 14576 let map = this._getWeakMap(keys5); 14577 for (let i = 0; i < keys5.length - 1; i++) { 14578 map = map.get(keys5[i]); 14579 if (map === void 0) return false; 14580 } 14581 return map.delete(keys5[keys5.length - 1]); 14582 } 14583}; 14584var _id$a = 0; 14585function getKeys(obj) { 14586 const keys5 = Object.keys(obj); 14587 let proto2 = Object.getPrototypeOf(obj); 14588 while (proto2) { 14589 const descriptors = Object.getOwnPropertyDescriptors(proto2); 14590 for (const key in descriptors) { 14591 if (descriptors[key] !== void 0) { 14592 const descriptor = descriptors[key]; 14593 if (descriptor && typeof descriptor.get === "function") { 14594 keys5.push(key); 14595 } 14596 } 14597 } 14598 proto2 = Object.getPrototypeOf(proto2); 14599 } 14600 return keys5; 14601} 14602var RenderObject = class { 14603 /** 14604 * Constructs a new render object. 14605 * 14606 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 14607 * @param {Geometries} geometries - Renderer component for managing geometries. 14608 * @param {Renderer} renderer - The renderer. 14609 * @param {Object3D} object - The 3D object. 14610 * @param {Material} material - The 3D object's material. 14611 * @param {Scene} scene - The scene the 3D object belongs to. 14612 * @param {Camera} camera - The camera the object should be rendered with. 14613 * @param {LightsNode} lightsNode - The lights node. 14614 * @param {RenderContext} renderContext - The render context. 14615 * @param {ClippingContext} clippingContext - The clipping context. 14616 */ 14617 constructor(nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext) { 14618 this.id = _id$a++; 14619 this._nodes = nodes; 14620 this._geometries = geometries; 14621 this.renderer = renderer; 14622 this.object = object; 14623 this.material = material; 14624 this.scene = scene; 14625 this.camera = camera; 14626 this.lightsNode = lightsNode; 14627 this.context = renderContext; 14628 this.geometry = object.geometry; 14629 this.version = material.version; 14630 this.drawRange = null; 14631 this.attributes = null; 14632 this.attributesId = null; 14633 this.pipeline = null; 14634 this.group = null; 14635 this.vertexBuffers = null; 14636 this.drawParams = null; 14637 this.bundle = null; 14638 this.clippingContext = clippingContext; 14639 this.clippingContextCacheKey = clippingContext !== null ? clippingContext.cacheKey : ""; 14640 this.initialNodesCacheKey = this.getDynamicCacheKey(); 14641 this.initialCacheKey = this.getCacheKey(); 14642 this._nodeBuilderState = null; 14643 this._bindings = null; 14644 this._monitor = null; 14645 this.onDispose = null; 14646 this.isRenderObject = true; 14647 this.onMaterialDispose = () => { 14648 this.dispose(); 14649 }; 14650 this.onGeometryDispose = () => { 14651 this.attributes = null; 14652 this.attributesId = null; 14653 }; 14654 this.material.addEventListener("dispose", this.onMaterialDispose); 14655 this.geometry.addEventListener("dispose", this.onGeometryDispose); 14656 } 14657 /** 14658 * Updates the clipping context. 14659 * 14660 * @param {ClippingContext} context - The clipping context to set. 14661 */ 14662 updateClipping(context3) { 14663 this.clippingContext = context3; 14664 } 14665 /** 14666 * Whether the clipping requires an update or not. 14667 * 14668 * @type {boolean} 14669 * @readonly 14670 */ 14671 get clippingNeedsUpdate() { 14672 if (this.clippingContext === null || this.clippingContext.cacheKey === this.clippingContextCacheKey) return false; 14673 this.clippingContextCacheKey = this.clippingContext.cacheKey; 14674 return true; 14675 } 14676 /** 14677 * The number of clipping planes defined in context of hardware clipping. 14678 * 14679 * @type {number} 14680 * @readonly 14681 */ 14682 get hardwareClippingPlanes() { 14683 return this.material.hardwareClipping === true ? this.clippingContext.unionClippingCount : 0; 14684 } 14685 /** 14686 * Returns the node builder state of this render object. 14687 * 14688 * @return {NodeBuilderState} The node builder state. 14689 */ 14690 getNodeBuilderState() { 14691 return this._nodeBuilderState || (this._nodeBuilderState = this._nodes.getForRender(this)); 14692 } 14693 /** 14694 * Returns the node material observer of this render object. 14695 * 14696 * @return {NodeMaterialObserver} The node material observer. 14697 */ 14698 getMonitor() { 14699 return this._monitor || (this._monitor = this.getNodeBuilderState().observer); 14700 } 14701 /** 14702 * Returns an array of bind groups of this render object. 14703 * 14704 * @return {Array<BindGroup>} The bindings. 14705 */ 14706 getBindings() { 14707 return this._bindings || (this._bindings = this.getNodeBuilderState().createBindings()); 14708 } 14709 /** 14710 * Returns a binding group by group name of this render object. 14711 * 14712 * @param {string} name - The name of the binding group. 14713 * @return {?BindGroup} The bindings. 14714 */ 14715 getBindingGroup(name) { 14716 for (const bindingGroup of this.getBindings()) { 14717 if (bindingGroup.name === name) { 14718 return bindingGroup; 14719 } 14720 } 14721 } 14722 /** 14723 * Returns the index of the render object's geometry. 14724 * 14725 * @return {?BufferAttribute} The index. Returns `null` for non-indexed geometries. 14726 */ 14727 getIndex() { 14728 return this._geometries.getIndex(this); 14729 } 14730 /** 14731 * Returns the indirect buffer attribute. 14732 * 14733 * @return {?BufferAttribute} The indirect attribute. `null` if no indirect drawing is used. 14734 */ 14735 getIndirect() { 14736 return this._geometries.getIndirect(this); 14737 } 14738 /** 14739 * Returns the byte offset into the indirect attribute buffer. 14740 * 14741 * @return {number|Array<number>} The byte offset into the indirect attribute buffer. 14742 */ 14743 getIndirectOffset() { 14744 return this._geometries.getIndirectOffset(this); 14745 } 14746 /** 14747 * Returns an array that acts as a key for identifying the render object in a chain map. 14748 * 14749 * @return {Array<Object>} An array with object references. 14750 */ 14751 getChainArray() { 14752 return [this.object, this.material, this.context, this.lightsNode]; 14753 } 14754 /** 14755 * This method is used when the geometry of a 3D object has been exchanged and the 14756 * respective render object now requires an update. 14757 * 14758 * @param {BufferGeometry} geometry - The geometry to set. 14759 */ 14760 setGeometry(geometry) { 14761 this.geometry = geometry; 14762 this.attributes = null; 14763 this.attributesId = null; 14764 } 14765 /** 14766 * Returns the buffer attributes of the render object. The returned array holds 14767 * attribute definitions on geometry and node level. 14768 * 14769 * @return {Array<BufferAttribute>} An array with buffer attributes. 14770 */ 14771 getAttributes() { 14772 if (this.attributes !== null) return this.attributes; 14773 const nodeAttributes = this.getNodeBuilderState().nodeAttributes; 14774 const geometry = this.geometry; 14775 const attributes = []; 14776 const vertexBuffers = /* @__PURE__ */ new Set(); 14777 const attributesId = {}; 14778 for (const nodeAttribute of nodeAttributes) { 14779 let attribute3; 14780 if (nodeAttribute.node && nodeAttribute.node.attribute) { 14781 attribute3 = nodeAttribute.node.attribute; 14782 } else { 14783 attribute3 = geometry.getAttribute(nodeAttribute.name); 14784 attributesId[nodeAttribute.name] = attribute3.id; 14785 } 14786 if (attribute3 === void 0) continue; 14787 attributes.push(attribute3); 14788 const bufferAttribute3 = attribute3.isInterleavedBufferAttribute ? attribute3.data : attribute3; 14789 vertexBuffers.add(bufferAttribute3); 14790 } 14791 this.attributes = attributes; 14792 this.attributesId = attributesId; 14793 this.vertexBuffers = Array.from(vertexBuffers.values()); 14794 return attributes; 14795 } 14796 /** 14797 * Returns the vertex buffers of the render object. 14798 * 14799 * @return {Array<BufferAttribute|InterleavedBuffer>} An array with buffer attribute or interleaved buffers. 14800 */ 14801 getVertexBuffers() { 14802 if (this.vertexBuffers === null) this.getAttributes(); 14803 return this.vertexBuffers; 14804 } 14805 /** 14806 * Returns the draw parameters for the render object. 14807 * 14808 * @return {?{vertexCount: number, firstVertex: number, instanceCount: number, firstInstance: number}} The draw parameters. 14809 */ 14810 getDrawParameters() { 14811 const { object, material, geometry, group, drawRange } = this; 14812 const drawParams = this.drawParams || (this.drawParams = { 14813 vertexCount: 0, 14814 firstVertex: 0, 14815 instanceCount: 0, 14816 firstInstance: 0 14817 }); 14818 const index = this.getIndex(); 14819 const hasIndex = index !== null; 14820 let instanceCount = 1; 14821 if (geometry.isInstancedBufferGeometry === true) { 14822 instanceCount = geometry.instanceCount; 14823 } else if (object.count !== void 0) { 14824 instanceCount = Math.max(0, object.count); 14825 } 14826 if (instanceCount === 0) return null; 14827 drawParams.instanceCount = instanceCount; 14828 if (object.isBatchedMesh === true) return drawParams; 14829 let rangeFactor = 1; 14830 if (material.wireframe === true && !object.isPoints && !object.isLineSegments && !object.isLine && !object.isLineLoop) { 14831 rangeFactor = 2; 14832 } 14833 let firstVertex = drawRange.start * rangeFactor; 14834 let lastVertex = (drawRange.start + drawRange.count) * rangeFactor; 14835 if (group !== null) { 14836 firstVertex = Math.max(firstVertex, group.start * rangeFactor); 14837 lastVertex = Math.min(lastVertex, (group.start + group.count) * rangeFactor); 14838 } 14839 const position = geometry.attributes.position; 14840 let itemCount = Infinity; 14841 if (hasIndex) { 14842 itemCount = index.count; 14843 } else if (position !== void 0 && position !== null) { 14844 itemCount = position.count; 14845 } 14846 firstVertex = Math.max(firstVertex, 0); 14847 lastVertex = Math.min(lastVertex, itemCount); 14848 const count = lastVertex - firstVertex; 14849 if (count < 0 || count === Infinity) return null; 14850 drawParams.vertexCount = count; 14851 drawParams.firstVertex = firstVertex; 14852 return drawParams; 14853 } 14854 /** 14855 * Returns the render object's geometry cache key. 14856 * 14857 * The geometry cache key is part of the material cache key. 14858 * 14859 * @return {string} The geometry cache key. 14860 */ 14861 getGeometryCacheKey() { 14862 const { geometry } = this; 14863 let cacheKey = ""; 14864 for (const name of Object.keys(geometry.attributes).sort()) { 14865 const attribute3 = geometry.attributes[name]; 14866 cacheKey += name + ","; 14867 if (attribute3.data) cacheKey += attribute3.data.stride + ","; 14868 if (attribute3.offset) cacheKey += attribute3.offset + ","; 14869 if (attribute3.itemSize) cacheKey += attribute3.itemSize + ","; 14870 if (attribute3.normalized) cacheKey += "n,"; 14871 } 14872 for (const name of Object.keys(geometry.morphAttributes).sort()) { 14873 const targets = geometry.morphAttributes[name]; 14874 cacheKey += "morph-" + name + ","; 14875 for (let i = 0, l = targets.length; i < l; i++) { 14876 const attribute3 = targets[i]; 14877 cacheKey += attribute3.id + ","; 14878 } 14879 } 14880 if (geometry.index) { 14881 cacheKey += "index,"; 14882 } 14883 return cacheKey; 14884 } 14885 /** 14886 * Returns the render object's material cache key. 14887 * 14888 * The material cache key is part of the render object cache key. 14889 * 14890 * @return {number} The material cache key. 14891 */ 14892 getMaterialCacheKey() { 14893 const { object, material, renderer } = this; 14894 let cacheKey = material.customProgramCacheKey(); 14895 for (const property3 of getKeys(material)) { 14896 if (/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(property3)) continue; 14897 const value = material[property3]; 14898 let valueKey; 14899 if (value !== null) { 14900 const type = typeof value; 14901 if (type === "number") { 14902 valueKey = value !== 0 ? "1" : "0"; 14903 } else if (type === "object") { 14904 valueKey = "{"; 14905 if (value.isTexture) { 14906 valueKey += value.mapping; 14907 if (renderer.backend.isWebGPUBackend === true) { 14908 valueKey += value.magFilter; 14909 valueKey += value.minFilter; 14910 valueKey += value.wrapS; 14911 valueKey += value.wrapT; 14912 valueKey += value.wrapR; 14913 } 14914 } 14915 valueKey += "}"; 14916 } else { 14917 valueKey = String(value); 14918 } 14919 } else { 14920 valueKey = String(value); 14921 } 14922 cacheKey += /*property + ':' +*/ 14923 valueKey + ","; 14924 } 14925 cacheKey += this.clippingContextCacheKey + ","; 14926 if (object.geometry) { 14927 cacheKey += this.getGeometryCacheKey(); 14928 } 14929 if (object.skeleton) { 14930 cacheKey += object.skeleton.bones.length + ","; 14931 } 14932 if (object.isBatchedMesh) { 14933 cacheKey += object._matricesTexture.uuid + ","; 14934 if (object._colorsTexture !== null) { 14935 cacheKey += object._colorsTexture.uuid + ","; 14936 } 14937 } 14938 if (object.isInstancedMesh || object.count > 1 || Array.isArray(object.morphTargetInfluences)) { 14939 cacheKey += object.uuid + ","; 14940 } 14941 cacheKey += this.context.id + ","; 14942 cacheKey += object.receiveShadow + ","; 14943 return hashString(cacheKey); 14944 } 14945 /** 14946 * Whether the geometry requires an update or not. 14947 * 14948 * @type {boolean} 14949 * @readonly 14950 */ 14951 get needsGeometryUpdate() { 14952 if (this.geometry.id !== this.object.geometry.id) return true; 14953 if (this.attributes !== null) { 14954 const attributesId = this.attributesId; 14955 for (const name in attributesId) { 14956 const attribute3 = this.geometry.getAttribute(name); 14957 if (attribute3 === void 0 || attributesId[name] !== attribute3.id) { 14958 return true; 14959 } 14960 } 14961 } 14962 return false; 14963 } 14964 /** 14965 * Whether the render object requires an update or not. 14966 * 14967 * Note: There are two distinct places where render objects are checked for an update. 14968 * 14969 * 1. In `RenderObjects.get()` which is executed when the render object is request. This 14970 * method checks the `needsUpdate` flag and recreates the render object if necessary. 14971 * 2. In `Renderer._renderObjectDirect()` right after getting the render object via 14972 * `RenderObjects.get()`. The render object's NodeMaterialObserver is then used to detect 14973 * a need for a refresh due to material, geometry or object related value changes. 14974 * 14975 * TODO: Investigate if it's possible to merge both steps so there is only a single place 14976 * that performs the 'needsUpdate' check. 14977 * 14978 * @type {boolean} 14979 * @readonly 14980 */ 14981 get needsUpdate() { 14982 return ( 14983 /*this.object.static !== true &&*/ 14984 this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate 14985 ); 14986 } 14987 /** 14988 * Returns the dynamic cache key which represents a key that is computed per draw command. 14989 * 14990 * @return {number} The cache key. 14991 */ 14992 getDynamicCacheKey() { 14993 let cacheKey = 0; 14994 if (this.material.isShadowPassMaterial !== true) { 14995 cacheKey = this._nodes.getCacheKey(this.scene, this.lightsNode); 14996 } 14997 if (this.camera.isArrayCamera) { 14998 cacheKey = hash$1(cacheKey, this.camera.cameras.length); 14999 } 15000 if (this.object.receiveShadow) { 15001 cacheKey = hash$1(cacheKey, 1); 15002 } 15003 cacheKey = hash$1(cacheKey, this.renderer.contextNode.id, this.renderer.contextNode.version); 15004 return cacheKey; 15005 } 15006 /** 15007 * Returns the render object's cache key. 15008 * 15009 * @return {number} The cache key. 15010 */ 15011 getCacheKey() { 15012 return this.getMaterialCacheKey() + this.getDynamicCacheKey(); 15013 } 15014 /** 15015 * Frees internal resources. 15016 */ 15017 dispose() { 15018 this.material.removeEventListener("dispose", this.onMaterialDispose); 15019 this.geometry.removeEventListener("dispose", this.onGeometryDispose); 15020 this.onDispose(); 15021 } 15022}; 15023var _chainKeys$3 = []; 15024var RenderObjects = class { 15025 /** 15026 * Constructs a new render object management component. 15027 * 15028 * @param {Renderer} renderer - The renderer. 15029 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 15030 * @param {Geometries} geometries - Renderer component for managing geometries. 15031 * @param {Pipelines} pipelines - Renderer component for managing pipelines. 15032 * @param {Bindings} bindings - Renderer component for managing bindings. 15033 * @param {Info} info - Renderer component for managing metrics and monitoring data. 15034 */ 15035 constructor(renderer, nodes, geometries, pipelines, bindings, info) { 15036 this.renderer = renderer; 15037 this.nodes = nodes; 15038 this.geometries = geometries; 15039 this.pipelines = pipelines; 15040 this.bindings = bindings; 15041 this.info = info; 15042 this.chainMaps = {}; 15043 } 15044 /** 15045 * Returns a render object for the given object and state data. 15046 * 15047 * @param {Object3D} object - The 3D object. 15048 * @param {Material} material - The 3D object's material. 15049 * @param {Scene} scene - The scene the 3D object belongs to. 15050 * @param {Camera} camera - The camera the 3D object should be rendered with. 15051 * @param {LightsNode} lightsNode - The lights node. 15052 * @param {RenderContext} renderContext - The render context. 15053 * @param {ClippingContext} clippingContext - The clipping context. 15054 * @param {string} [passId] - An optional ID for identifying the pass. 15055 * @return {RenderObject} The render object. 15056 */ 15057 get(object, material, scene, camera, lightsNode, renderContext, clippingContext, passId) { 15058 const chainMap = this.getChainMap(passId); 15059 _chainKeys$3[0] = object; 15060 _chainKeys$3[1] = material; 15061 _chainKeys$3[2] = renderContext; 15062 _chainKeys$3[3] = lightsNode; 15063 let renderObject = chainMap.get(_chainKeys$3); 15064 if (renderObject === void 0) { 15065 renderObject = this.createRenderObject(this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId); 15066 chainMap.set(_chainKeys$3, renderObject); 15067 } else { 15068 renderObject.camera = camera; 15069 renderObject.updateClipping(clippingContext); 15070 if (renderObject.needsGeometryUpdate) { 15071 renderObject.setGeometry(object.geometry); 15072 } 15073 if (renderObject.version !== material.version || renderObject.needsUpdate) { 15074 if (renderObject.initialCacheKey !== renderObject.getCacheKey()) { 15075 renderObject.dispose(); 15076 renderObject = this.get(object, material, scene, camera, lightsNode, renderContext, clippingContext, passId); 15077 } else { 15078 renderObject.version = material.version; 15079 } 15080 } 15081 } 15082 _chainKeys$3[0] = null; 15083 _chainKeys$3[1] = null; 15084 _chainKeys$3[2] = null; 15085 _chainKeys$3[3] = null; 15086 return renderObject; 15087 } 15088 /** 15089 * Returns a chain map for the given pass ID. 15090 * 15091 * @param {string} [passId='default'] - The pass ID. 15092 * @return {ChainMap} The chain map. 15093 */ 15094 getChainMap(passId = "default") { 15095 return this.chainMaps[passId] || (this.chainMaps[passId] = new ChainMap()); 15096 } 15097 /** 15098 * Frees internal resources. 15099 */ 15100 dispose() { 15101 this.chainMaps = {}; 15102 } 15103 /** 15104 * Factory method for creating render objects with the given list of parameters. 15105 * 15106 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 15107 * @param {Geometries} geometries - Renderer component for managing geometries. 15108 * @param {Renderer} renderer - The renderer. 15109 * @param {Object3D} object - The 3D object. 15110 * @param {Material} material - The object's material. 15111 * @param {Scene} scene - The scene the 3D object belongs to. 15112 * @param {Camera} camera - The camera the object should be rendered with. 15113 * @param {LightsNode} lightsNode - The lights node. 15114 * @param {RenderContext} renderContext - The render context. 15115 * @param {ClippingContext} clippingContext - The clipping context. 15116 * @param {string} [passId] - An optional ID for identifying the pass. 15117 * @return {RenderObject} The render object. 15118 */ 15119 createRenderObject(nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId) { 15120 const chainMap = this.getChainMap(passId); 15121 const renderObject = new RenderObject(nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext); 15122 renderObject.onDispose = () => { 15123 this.pipelines.delete(renderObject); 15124 this.bindings.deleteForRender(renderObject); 15125 this.nodes.delete(renderObject); 15126 chainMap.delete(renderObject.getChainArray()); 15127 }; 15128 return renderObject; 15129 } 15130}; 15131var DataMap = class { 15132 /** 15133 * Constructs a new data map. 15134 */ 15135 constructor() { 15136 this.data = /* @__PURE__ */ new WeakMap(); 15137 } 15138 /** 15139 * Returns the dictionary for the given object. 15140 * 15141 * @param {Object} object - The object. 15142 * @return {Object} The dictionary. 15143 */ 15144 get(object) { 15145 let map = this.data.get(object); 15146 if (map === void 0) { 15147 map = {}; 15148 this.data.set(object, map); 15149 } 15150 return map; 15151 } 15152 /** 15153 * Deletes the dictionary for the given object. 15154 * 15155 * @param {Object} object - The object. 15156 * @return {?Object} The deleted dictionary. 15157 */ 15158 delete(object) { 15159 let map = null; 15160 if (this.data.has(object)) { 15161 map = this.data.get(object); 15162 this.data.delete(object); 15163 } 15164 return map; 15165 } 15166 /** 15167 * Returns `true` if the given object has a dictionary defined. 15168 * 15169 * @param {Object} object - The object to test. 15170 * @return {boolean} Whether a dictionary is defined or not. 15171 */ 15172 has(object) { 15173 return this.data.has(object); 15174 } 15175 /** 15176 * Frees internal resources. 15177 */ 15178 dispose() { 15179 this.data = /* @__PURE__ */ new WeakMap(); 15180 } 15181}; 15182var AttributeType = { 15183 VERTEX: 1, 15184 INDEX: 2, 15185 STORAGE: 3, 15186 INDIRECT: 4 15187}; 15188var GPU_CHUNK_BYTES = 16; 15189var BlendColorFactor = 211; 15190var OneMinusBlendColorFactor = 212; 15191var Attributes = class extends DataMap { 15192 /** 15193 * Constructs a new attribute management component. 15194 * 15195 * @param {Backend} backend - The renderer's backend. 15196 * @param {Info} info - Renderer component for managing metrics and monitoring data. 15197 */ 15198 constructor(backend, info) { 15199 super(); 15200 this.backend = backend; 15201 this.info = info; 15202 } 15203 /** 15204 * Deletes the data for the given attribute. 15205 * 15206 * @param {BufferAttribute} attribute - The attribute. 15207 * @return {?Object} The deleted attribute data. 15208 */ 15209 delete(attribute3) { 15210 const attributeData = super.delete(attribute3); 15211 if (attributeData !== null) { 15212 this.backend.destroyAttribute(attribute3); 15213 this.info.destroyAttribute(attribute3); 15214 } 15215 return attributeData; 15216 } 15217 /** 15218 * Updates the given attribute. This method creates attribute buffers 15219 * for new attributes and updates data for existing ones. 15220 * 15221 * @param {BufferAttribute} attribute - The attribute to update. 15222 * @param {number} type - The attribute type. 15223 */ 15224 update(attribute3, type) { 15225 const data = this.get(attribute3); 15226 if (data.version === void 0) { 15227 if (type === AttributeType.VERTEX) { 15228 this.backend.createAttribute(attribute3); 15229 this.info.createAttribute(attribute3); 15230 } else if (type === AttributeType.INDEX) { 15231 this.backend.createIndexAttribute(attribute3); 15232 this.info.createIndexAttribute(attribute3); 15233 } else if (type === AttributeType.STORAGE) { 15234 this.backend.createStorageAttribute(attribute3); 15235 this.info.createStorageAttribute(attribute3); 15236 } else if (type === AttributeType.INDIRECT) { 15237 this.backend.createIndirectStorageAttribute(attribute3); 15238 this.info.createIndirectStorageAttribute(attribute3); 15239 } 15240 data.version = this._getBufferAttribute(attribute3).version; 15241 } else { 15242 const bufferAttribute3 = this._getBufferAttribute(attribute3); 15243 if (data.version < bufferAttribute3.version || bufferAttribute3.usage === DynamicDrawUsage) { 15244 this.backend.updateAttribute(attribute3); 15245 data.version = bufferAttribute3.version; 15246 } 15247 } 15248 } 15249 /** 15250 * Utility method for handling interleaved buffer attributes correctly. 15251 * To process them, their `InterleavedBuffer` is returned. 15252 * 15253 * @param {BufferAttribute} attribute - The attribute. 15254 * @return {BufferAttribute|InterleavedBuffer} 15255 */ 15256 _getBufferAttribute(attribute3) { 15257 if (attribute3.isInterleavedBufferAttribute) attribute3 = attribute3.data; 15258 return attribute3; 15259 } 15260}; 15261function getWireframeVersion(geometry) { 15262 return geometry.index !== null ? geometry.index.version : geometry.attributes.position.version; 15263} 15264function getWireframeId(geometry) { 15265 return geometry.index !== null ? geometry.index.id : geometry.attributes.position.id; 15266} 15267function getWireframeIndex(geometry) { 15268 const indices = []; 15269 const geometryIndex = geometry.index; 15270 const geometryPosition = geometry.attributes.position; 15271 if (geometryIndex !== null) { 15272 const array3 = geometryIndex.array; 15273 for (let i = 0, l = array3.length; i < l; i += 3) { 15274 const a = array3[i + 0]; 15275 const b = array3[i + 1]; 15276 const c = array3[i + 2]; 15277 indices.push(a, b, b, c, c, a); 15278 } 15279 } else { 15280 const array3 = geometryPosition.array; 15281 for (let i = 0, l = array3.length / 3 - 1; i < l; i += 3) { 15282 const a = i + 0; 15283 const b = i + 1; 15284 const c = i + 2; 15285 indices.push(a, b, b, c, c, a); 15286 } 15287 } 15288 const attribute3 = new (geometryPosition.count >= 65535 ? Uint32BufferAttribute : Uint16BufferAttribute)(indices, 1); 15289 attribute3.version = getWireframeVersion(geometry); 15290 attribute3.__id = getWireframeId(geometry); 15291 return attribute3; 15292} 15293var Geometries = class extends DataMap { 15294 /** 15295 * Constructs a new geometry management component. 15296 * 15297 * @param {Attributes} attributes - Renderer component for managing attributes. 15298 * @param {Info} info - Renderer component for managing metrics and monitoring data. 15299 */ 15300 constructor(attributes, info) { 15301 super(); 15302 this.attributes = attributes; 15303 this.info = info; 15304 this.wireframes = /* @__PURE__ */ new WeakMap(); 15305 this.attributeCall = /* @__PURE__ */ new WeakMap(); 15306 this._geometryDisposeListeners = /* @__PURE__ */ new Map(); 15307 } 15308 /** 15309 * Returns `true` if the given render object has an initialized geometry. 15310 * 15311 * @param {RenderObject} renderObject - The render object. 15312 * @return {boolean} Whether if the given render object has an initialized geometry or not. 15313 */ 15314 has(renderObject) { 15315 const geometry = renderObject.geometry; 15316 return super.has(geometry) && this.get(geometry).initialized === true; 15317 } 15318 /** 15319 * Prepares the geometry of the given render object for rendering. 15320 * 15321 * @param {RenderObject} renderObject - The render object. 15322 */ 15323 updateForRender(renderObject) { 15324 if (this.has(renderObject) === false) this.initGeometry(renderObject); 15325 this.updateAttributes(renderObject); 15326 } 15327 /** 15328 * Initializes the geometry of the given render object. 15329 * 15330 * @param {RenderObject} renderObject - The render object. 15331 */ 15332 initGeometry(renderObject) { 15333 const geometry = renderObject.geometry; 15334 const geometryData = this.get(geometry); 15335 geometryData.initialized = true; 15336 this.info.memory.geometries++; 15337 const onDispose = () => { 15338 this.info.memory.geometries--; 15339 const index = geometry.index; 15340 const geometryAttributes = renderObject.getAttributes(); 15341 if (index !== null) { 15342 this.attributes.delete(index); 15343 } 15344 for (const geometryAttribute of geometryAttributes) { 15345 this.attributes.delete(geometryAttribute); 15346 } 15347 const wireframeAttribute = this.wireframes.get(geometry); 15348 if (wireframeAttribute !== void 0) { 15349 this.attributes.delete(wireframeAttribute); 15350 } 15351 geometry.removeEventListener("dispose", onDispose); 15352 this._geometryDisposeListeners.delete(geometry); 15353 }; 15354 geometry.addEventListener("dispose", onDispose); 15355 this._geometryDisposeListeners.set(geometry, onDispose); 15356 } 15357 /** 15358 * Updates the geometry attributes of the given render object. 15359 * 15360 * @param {RenderObject} renderObject - The render object. 15361 */ 15362 updateAttributes(renderObject) { 15363 const attributes = renderObject.getAttributes(); 15364 for (const attribute3 of attributes) { 15365 if (attribute3.isStorageBufferAttribute || attribute3.isStorageInstancedBufferAttribute) { 15366 this.updateAttribute(attribute3, AttributeType.STORAGE); 15367 } else { 15368 this.updateAttribute(attribute3, AttributeType.VERTEX); 15369 } 15370 } 15371 const index = this.getIndex(renderObject); 15372 if (index !== null) { 15373 this.updateAttribute(index, AttributeType.INDEX); 15374 } 15375 const indirect = renderObject.geometry.indirect; 15376 if (indirect !== null) { 15377 this.updateAttribute(indirect, AttributeType.INDIRECT); 15378 } 15379 } 15380 /** 15381 * Updates the given attribute. 15382 * 15383 * @param {BufferAttribute} attribute - The attribute to update. 15384 * @param {number} type - The attribute type. 15385 */ 15386 updateAttribute(attribute3, type) { 15387 const callId = this.info.render.calls; 15388 if (!attribute3.isInterleavedBufferAttribute) { 15389 if (this.attributeCall.get(attribute3) !== callId) { 15390 this.attributes.update(attribute3, type); 15391 this.attributeCall.set(attribute3, callId); 15392 } 15393 } else { 15394 if (this.attributeCall.get(attribute3) === void 0) { 15395 this.attributes.update(attribute3, type); 15396 this.attributeCall.set(attribute3, callId); 15397 } else if (this.attributeCall.get(attribute3.data) !== callId) { 15398 this.attributes.update(attribute3, type); 15399 this.attributeCall.set(attribute3.data, callId); 15400 this.attributeCall.set(attribute3, callId); 15401 } 15402 } 15403 } 15404 /** 15405 * Returns the indirect buffer attribute of the given render object. 15406 * 15407 * @param {RenderObject} renderObject - The render object. 15408 * @return {?BufferAttribute} The indirect attribute. `null` if no indirect drawing is used. 15409 */ 15410 getIndirect(renderObject) { 15411 return renderObject.geometry.indirect; 15412 } 15413 /** 15414 * Returns the byte offset into the indirect attribute buffer of the given render object. 15415 * 15416 * @param {RenderObject} renderObject - The render object. 15417 * @return {number} The byte offset into the indirect attribute buffer. 15418 */ 15419 getIndirectOffset(renderObject) { 15420 return renderObject.geometry.indirectOffset; 15421 } 15422 /** 15423 * Returns the index of the given render object's geometry. This is implemented 15424 * in a method to return a wireframe index if necessary. 15425 * 15426 * @param {RenderObject} renderObject - The render object. 15427 * @return {?BufferAttribute} The index. Returns `null` for non-indexed geometries. 15428 */ 15429 getIndex(renderObject) { 15430 const { geometry, material } = renderObject; 15431 let index = geometry.index; 15432 if (material.wireframe === true) { 15433 const wireframes = this.wireframes; 15434 let wireframeAttribute = wireframes.get(geometry); 15435 if (wireframeAttribute === void 0) { 15436 wireframeAttribute = getWireframeIndex(geometry); 15437 wireframes.set(geometry, wireframeAttribute); 15438 } else if (wireframeAttribute.version !== getWireframeVersion(geometry) || wireframeAttribute.__id !== getWireframeId(geometry)) { 15439 this.attributes.delete(wireframeAttribute); 15440 wireframeAttribute = getWireframeIndex(geometry); 15441 wireframes.set(geometry, wireframeAttribute); 15442 } 15443 index = wireframeAttribute; 15444 } 15445 return index; 15446 } 15447 dispose() { 15448 for (const [geometry, onDispose] of this._geometryDisposeListeners.entries()) { 15449 geometry.removeEventListener("dispose", onDispose); 15450 } 15451 this._geometryDisposeListeners.clear(); 15452 } 15453}; 15454var Info = class { 15455 /** 15456 * Constructs a new info component. 15457 */ 15458 constructor() { 15459 this.autoReset = true; 15460 this.frame = 0; 15461 this.calls = 0; 15462 this.render = { 15463 calls: 0, 15464 frameCalls: 0, 15465 drawCalls: 0, 15466 triangles: 0, 15467 points: 0, 15468 lines: 0, 15469 timestamp: 0 15470 }; 15471 this.compute = { 15472 calls: 0, 15473 frameCalls: 0, 15474 timestamp: 0 15475 }; 15476 this.memory = { 15477 geometries: 0, 15478 textures: 0, 15479 attributes: 0, 15480 indexAttributes: 0, 15481 storageAttributes: 0, 15482 indirectStorageAttributes: 0, 15483 readbackBuffers: 0, 15484 programs: 0, 15485 renderTargets: 0, 15486 total: 0, 15487 texturesSize: 0, 15488 attributesSize: 0, 15489 indexAttributesSize: 0, 15490 storageAttributesSize: 0, 15491 indirectStorageAttributesSize: 0, 15492 readbackBuffersSize: 0, 15493 programsSize: 0 15494 }; 15495 this.memoryMap = /* @__PURE__ */ new Map(); 15496 } 15497 /** 15498 * This method should be executed per draw call and updates the corresponding metrics. 15499 * 15500 * @param {Object3D} object - The 3D object that is going to be rendered. 15501 * @param {number} count - The vertex or index count. 15502 * @param {number} instanceCount - The instance count. 15503 */ 15504 update(object, count, instanceCount) { 15505 this.render.drawCalls++; 15506 if (object.isMesh || object.isSprite) { 15507 this.render.triangles += instanceCount * (count / 3); 15508 } else if (object.isPoints) { 15509 this.render.points += instanceCount * count; 15510 } else if (object.isLineSegments) { 15511 this.render.lines += instanceCount * (count / 2); 15512 } else if (object.isLine) { 15513 this.render.lines += instanceCount * (count - 1); 15514 } else { 15515 error("WebGPUInfo: Unknown object type."); 15516 } 15517 } 15518 /** 15519 * Resets frame related metrics. 15520 */ 15521 reset() { 15522 this.render.drawCalls = 0; 15523 this.render.frameCalls = 0; 15524 this.compute.frameCalls = 0; 15525 this.render.triangles = 0; 15526 this.render.points = 0; 15527 this.render.lines = 0; 15528 } 15529 /** 15530 * Performs a complete reset of the object. 15531 */ 15532 dispose() { 15533 this.reset(); 15534 this.calls = 0; 15535 this.render.calls = 0; 15536 this.compute.calls = 0; 15537 this.render.timestamp = 0; 15538 this.compute.timestamp = 0; 15539 for (const prop in this.memory) { 15540 this.memory[prop] = 0; 15541 } 15542 this.memoryMap.clear(); 15543 } 15544 /** 15545 * Tracks texture memory explicitly, updating counts and byte tracking. 15546 * 15547 * @param {Texture} texture 15548 */ 15549 createTexture(texture3) { 15550 const size3 = this._getTextureMemorySize(texture3); 15551 this.memoryMap.set(texture3, size3); 15552 this.memory.textures++; 15553 this.memory.total += size3; 15554 this.memory.texturesSize += size3; 15555 } 15556 /** 15557 * Tracks texture memory explicitly, updating counts and byte tracking. 15558 * 15559 * @param {Texture} texture 15560 */ 15561 destroyTexture(texture3) { 15562 const size3 = this.memoryMap.get(texture3) || 0; 15563 this.memoryMap.delete(texture3); 15564 this.memory.textures--; 15565 this.memory.total -= size3; 15566 this.memory.texturesSize -= size3; 15567 } 15568 /** 15569 * Tracks attribute memory explicitly, updating counts and byte tracking. 15570 * 15571 * @param {BufferAttribute} attribute 15572 * @param {string} type - type of attribute 15573 * @private 15574 */ 15575 _createAttribute(attribute3, type) { 15576 const size3 = this._getAttributeMemorySize(attribute3); 15577 this.memoryMap.set(attribute3, { size: size3, type }); 15578 this.memory[type]++; 15579 this.memory.total += size3; 15580 this.memory[type + "Size"] += size3; 15581 } 15582 /** 15583 * Tracks a regular attribute memory explicitly. 15584 * 15585 * @param {BufferAttribute} attribute - The attribute to track. 15586 */ 15587 createAttribute(attribute3) { 15588 this._createAttribute(attribute3, "attributes"); 15589 } 15590 /** 15591 * Tracks an index attribute memory explicitly. 15592 * 15593 * @param {BufferAttribute} attribute - The index attribute to track. 15594 */ 15595 createIndexAttribute(attribute3) { 15596 this._createAttribute(attribute3, "indexAttributes"); 15597 } 15598 /** 15599 * Tracks a storage attribute memory explicitly. 15600 * 15601 * @param {BufferAttribute} attribute - The storage attribute to track. 15602 */ 15603 createStorageAttribute(attribute3) { 15604 this._createAttribute(attribute3, "storageAttributes"); 15605 } 15606 /** 15607 * Tracks an indirect storage attribute memory explicitly. 15608 * 15609 * @param {BufferAttribute} attribute - The indirect storage attribute to track. 15610 */ 15611 createIndirectStorageAttribute(attribute3) { 15612 this._createAttribute(attribute3, "indirectStorageAttributes"); 15613 } 15614 /** 15615 * Tracks attribute memory explicitly, updating counts and byte tracking. 15616 * 15617 * @param {BufferAttribute} attribute 15618 */ 15619 destroyAttribute(attribute3) { 15620 const data = this.memoryMap.get(attribute3); 15621 if (data) { 15622 this.memoryMap.delete(attribute3); 15623 this.memory[data.type]--; 15624 this.memory.total -= data.size; 15625 this.memory[data.type + "Size"] -= data.size; 15626 } 15627 } 15628 /** 15629 * Tracks a readback buffer memory explicitly. 15630 * 15631 * @param {ReadbackBuffer} readbackBuffer - The readback buffer to track. 15632 */ 15633 createReadbackBuffer(readbackBuffer) { 15634 const maxByteLength = readbackBuffer.maxByteLength; 15635 this.memoryMap.set(readbackBuffer, { size: maxByteLength, type: "readbackBuffers" }); 15636 this.memory.readbackBuffers++; 15637 this.memory.total += maxByteLength; 15638 this.memory.readbackBuffersSize += maxByteLength; 15639 } 15640 /** 15641 * Tracks a readback buffer memory explicitly. 15642 * 15643 * @param {ReadbackBuffer} readbackBuffer - The readback buffer to track. 15644 */ 15645 destroyReadbackBuffer(readbackBuffer) { 15646 const { size: size3 } = this.memoryMap.get(readbackBuffer); 15647 this.memoryMap.delete(readbackBuffer); 15648 this.memory.readbackBuffers--; 15649 this.memory.total -= size3; 15650 this.memory.readbackBuffersSize -= size3; 15651 } 15652 /** 15653 * Tracks program memory explicitly, updating counts and byte tracking. 15654 * 15655 * @param {ProgrammableStage} program - The program to track. 15656 */ 15657 createProgram(program) { 15658 const size3 = program.code.length; 15659 this.memoryMap.set(program, size3); 15660 this.memory.programs++; 15661 this.memory.total += size3; 15662 this.memory.programsSize += size3; 15663 } 15664 /** 15665 * Tracks program memory explicitly, updating counts and byte tracking. 15666 * 15667 * @param {Object} program - The program to track. 15668 */ 15669 destroyProgram(program) { 15670 const size3 = this.memoryMap.get(program) || 0; 15671 this.memoryMap.delete(program); 15672 this.memory.programs--; 15673 this.memory.total -= size3; 15674 this.memory.programsSize -= size3; 15675 } 15676 /** 15677 * Calculates the memory size of a texture in bytes. 15678 * 15679 * @param {Texture} texture - The texture to calculate the size for. 15680 * @return {number} The calculated size in bytes. 15681 * @private 15682 */ 15683 _getTextureMemorySize(texture3) { 15684 if (texture3.isCompressedTexture) { 15685 return 1; 15686 } 15687 let bytesPerChannel = 1; 15688 if (texture3.type === ByteType || texture3.type === UnsignedByteType) bytesPerChannel = 1; 15689 else if (texture3.type === ShortType || texture3.type === UnsignedShortType || texture3.type === HalfFloatType) bytesPerChannel = 2; 15690 else if (texture3.type === IntType || texture3.type === UnsignedIntType || texture3.type === FloatType) bytesPerChannel = 4; 15691 let channels = 4; 15692 if (texture3.format === AlphaFormat || texture3.format === RedFormat || texture3.format === RedIntegerFormat || texture3.format === DepthFormat || texture3.format === DepthStencilFormat) channels = 1; 15693 else if (texture3.format === RGFormat || texture3.format === RGIntegerFormat) channels = 2; 15694 else if (texture3.format === RGBFormat || texture3.format === RGBIntegerFormat) channels = 3; 15695 let bytesPerPixel = bytesPerChannel * channels; 15696 if (texture3.type === UnsignedShort4444Type || texture3.type === UnsignedShort5551Type) bytesPerPixel = 2; 15697 else if (texture3.type === UnsignedInt248Type || texture3.type === UnsignedInt5999Type || texture3.type === UnsignedInt101111Type) bytesPerPixel = 4; 15698 const width = texture3.width || 1; 15699 const height = texture3.height || 1; 15700 const depth3 = texture3.isCubeTexture ? 6 : texture3.depth || 1; 15701 let size3 = width * height * depth3 * bytesPerPixel; 15702 const mipmaps = texture3.mipmaps; 15703 if (mipmaps && mipmaps.length > 0) { 15704 let mipmapSize = 0; 15705 for (let i = 0; i < mipmaps.length; i++) { 15706 const mipmap = mipmaps[i]; 15707 if (mipmap.data) { 15708 mipmapSize += mipmap.data.byteLength; 15709 } else { 15710 const mipWidth = mipmap.width || Math.max(1, width >> i); 15711 const mipHeight = mipmap.height || Math.max(1, height >> i); 15712 mipmapSize += mipWidth * mipHeight * depth3 * bytesPerPixel; 15713 } 15714 } 15715 size3 += mipmapSize; 15716 } else if (texture3.generateMipmaps) { 15717 size3 = size3 * 1.333; 15718 } 15719 return Math.round(size3); 15720 } 15721 /** 15722 * Calculates the memory size of an attribute in bytes. 15723 * 15724 * @param {BufferAttribute} attribute - The attribute to calculate the size for. 15725 * @return {number} The calculated size in bytes. 15726 * @private 15727 */ 15728 _getAttributeMemorySize(attribute3) { 15729 if (attribute3.isInterleavedBufferAttribute) attribute3 = attribute3.data; 15730 if (attribute3.array) { 15731 return attribute3.array.byteLength; 15732 } else if (attribute3.count && attribute3.itemSize) { 15733 return attribute3.count * attribute3.itemSize * 4; 15734 } 15735 return 0; 15736 } 15737}; 15738var Pipeline = class { 15739 /** 15740 * Constructs a new pipeline. 15741 * 15742 * @param {string} cacheKey - The pipeline's cache key. 15743 */ 15744 constructor(cacheKey) { 15745 this.cacheKey = cacheKey; 15746 this.usedTimes = 0; 15747 } 15748}; 15749var RenderObjectPipeline = class extends Pipeline { 15750 /** 15751 * Constructs a new render object pipeline. 15752 * 15753 * @param {string} cacheKey - The pipeline's cache key. 15754 * @param {ProgrammableStage} vertexProgram - The pipeline's vertex shader. 15755 * @param {ProgrammableStage} fragmentProgram - The pipeline's fragment shader. 15756 */ 15757 constructor(cacheKey, vertexProgram, fragmentProgram) { 15758 super(cacheKey); 15759 this.vertexProgram = vertexProgram; 15760 this.fragmentProgram = fragmentProgram; 15761 } 15762}; 15763var ComputePipeline = class extends Pipeline { 15764 /** 15765 * Constructs a new compute pipeline. 15766 * 15767 * @param {string} cacheKey - The pipeline's cache key. 15768 * @param {ProgrammableStage} computeProgram - The pipeline's compute shader. 15769 */ 15770 constructor(cacheKey, computeProgram) { 15771 super(cacheKey); 15772 this.computeProgram = computeProgram; 15773 this.isComputePipeline = true; 15774 } 15775}; 15776var _id$9 = 0; 15777var ProgrammableStage = class { 15778 /** 15779 * Constructs a new programmable stage. 15780 * 15781 * @param {string} code - The shader code. 15782 * @param {('vertex'|'fragment'|'compute')} stage - The type of stage. 15783 * @param {string} name - The name of the shader. 15784 * @param {?Array<Object>} [transforms=null] - The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). 15785 * @param {?Array<Object>} [attributes=null] - The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). 15786 */ 15787 constructor(code3, stage, name, transforms = null, attributes = null) { 15788 this.id = _id$9++; 15789 this.code = code3; 15790 this.stage = stage; 15791 this.name = name; 15792 this.transforms = transforms; 15793 this.attributes = attributes; 15794 this.usedTimes = 0; 15795 } 15796}; 15797var Pipelines = class extends DataMap { 15798 /** 15799 * Constructs a new pipeline management component. 15800 * 15801 * @param {Backend} backend - The renderer's backend. 15802 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 15803 * @param {Info} info - Renderer component for managing metrics and monitoring data. 15804 */ 15805 constructor(backend, nodes, info) { 15806 super(); 15807 this.backend = backend; 15808 this.nodes = nodes; 15809 this.info = info; 15810 this.bindings = null; 15811 this.caches = /* @__PURE__ */ new Map(); 15812 this.programs = { 15813 vertex: /* @__PURE__ */ new Map(), 15814 fragment: /* @__PURE__ */ new Map(), 15815 compute: /* @__PURE__ */ new Map() 15816 }; 15817 } 15818 /** 15819 * Returns a compute pipeline for the given compute node. 15820 * 15821 * @param {Node} computeNode - The compute node. 15822 * @param {Array<BindGroup>} bindings - The bindings. 15823 * @return {ComputePipeline} The compute pipeline. 15824 */ 15825 getForCompute(computeNode, bindings) { 15826 const { backend } = this; 15827 const data = this.get(computeNode); 15828 if (this._needsComputeUpdate(computeNode)) { 15829 const previousPipeline = data.pipeline; 15830 if (previousPipeline) { 15831 previousPipeline.usedTimes--; 15832 previousPipeline.computeProgram.usedTimes--; 15833 } 15834 const nodeBuilderState = this.nodes.getForCompute(computeNode); 15835 let stageCompute = this.programs.compute.get(nodeBuilderState.computeShader); 15836 if (stageCompute === void 0) { 15837 if (previousPipeline && previousPipeline.computeProgram.usedTimes === 0) this._releaseProgram(previousPipeline.computeProgram); 15838 stageCompute = new ProgrammableStage(nodeBuilderState.computeShader, "compute", computeNode.name, nodeBuilderState.transforms, nodeBuilderState.nodeAttributes); 15839 this.programs.compute.set(nodeBuilderState.computeShader, stageCompute); 15840 backend.createProgram(stageCompute); 15841 this.info.createProgram(stageCompute); 15842 } 15843 const cacheKey = this._getComputeCacheKey(computeNode, stageCompute); 15844 let pipeline = this.caches.get(cacheKey); 15845 if (pipeline === void 0) { 15846 if (previousPipeline && previousPipeline.usedTimes === 0) this._releasePipeline(previousPipeline); 15847 pipeline = this._getComputePipeline(computeNode, stageCompute, cacheKey, bindings); 15848 } 15849 pipeline.usedTimes++; 15850 stageCompute.usedTimes++; 15851 data.version = computeNode.version; 15852 data.pipeline = pipeline; 15853 } 15854 return data.pipeline; 15855 } 15856 /** 15857 * Returns a render pipeline for the given render object. 15858 * 15859 * @param {RenderObject} renderObject - The render object. 15860 * @param {?Array<Promise>} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. 15861 * @return {RenderObjectPipeline} The render pipeline. 15862 */ 15863 getForRender(renderObject, promises = null) { 15864 const { backend } = this; 15865 const data = this.get(renderObject); 15866 if (this._needsRenderUpdate(renderObject)) { 15867 const previousPipeline = data.pipeline; 15868 if (previousPipeline) { 15869 previousPipeline.usedTimes--; 15870 previousPipeline.vertexProgram.usedTimes--; 15871 previousPipeline.fragmentProgram.usedTimes--; 15872 } 15873 const nodeBuilderState = renderObject.getNodeBuilderState(); 15874 const name = renderObject.material ? renderObject.material.name : ""; 15875 let stageVertex = this.programs.vertex.get(nodeBuilderState.vertexShader); 15876 if (stageVertex === void 0) { 15877 if (previousPipeline && previousPipeline.vertexProgram.usedTimes === 0) this._releaseProgram(previousPipeline.vertexProgram); 15878 stageVertex = new ProgrammableStage(nodeBuilderState.vertexShader, "vertex", name); 15879 this.programs.vertex.set(nodeBuilderState.vertexShader, stageVertex); 15880 backend.createProgram(stageVertex); 15881 this.info.createProgram(stageVertex); 15882 } 15883 let stageFragment = this.programs.fragment.get(nodeBuilderState.fragmentShader); 15884 if (stageFragment === void 0) { 15885 if (previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0) this._releaseProgram(previousPipeline.fragmentProgram); 15886 stageFragment = new ProgrammableStage(nodeBuilderState.fragmentShader, "fragment", name); 15887 this.programs.fragment.set(nodeBuilderState.fragmentShader, stageFragment); 15888 backend.createProgram(stageFragment); 15889 this.info.createProgram(stageFragment); 15890 } 15891 const cacheKey = this._getRenderCacheKey(renderObject, stageVertex, stageFragment); 15892 let pipeline = this.caches.get(cacheKey); 15893 if (pipeline === void 0) { 15894 if (previousPipeline && previousPipeline.usedTimes === 0) this._releasePipeline(previousPipeline); 15895 pipeline = this._getRenderPipeline(renderObject, stageVertex, stageFragment, cacheKey, promises); 15896 } else { 15897 renderObject.pipeline = pipeline; 15898 } 15899 pipeline.usedTimes++; 15900 stageVertex.usedTimes++; 15901 stageFragment.usedTimes++; 15902 data.pipeline = pipeline; 15903 } 15904 return data.pipeline; 15905 } 15906 /** 15907 * Checks if the render pipeline for the given render object is ready for drawing. 15908 * Returns false if the GPU pipeline is still being compiled asynchronously. 15909 * 15910 * @param {RenderObject} renderObject - The render object. 15911 * @return {boolean} True if the pipeline is ready for drawing. 15912 */ 15913 isReady(renderObject) { 15914 const data = this.get(renderObject); 15915 const pipeline = data.pipeline; 15916 if (pipeline === void 0) return false; 15917 const pipelineData = this.backend.get(pipeline); 15918 return pipelineData.pipeline !== void 0 && pipelineData.pipeline !== null; 15919 } 15920 /** 15921 * Deletes the pipeline for the given render object. 15922 * 15923 * @param {RenderObject} object - The render object. 15924 * @return {?Object} The deleted dictionary. 15925 */ 15926 delete(object) { 15927 const pipeline = this.get(object).pipeline; 15928 if (pipeline) { 15929 pipeline.usedTimes--; 15930 if (pipeline.usedTimes === 0) this._releasePipeline(pipeline); 15931 if (pipeline.isComputePipeline) { 15932 pipeline.computeProgram.usedTimes--; 15933 if (pipeline.computeProgram.usedTimes === 0) this._releaseProgram(pipeline.computeProgram); 15934 } else { 15935 pipeline.fragmentProgram.usedTimes--; 15936 pipeline.vertexProgram.usedTimes--; 15937 if (pipeline.vertexProgram.usedTimes === 0) this._releaseProgram(pipeline.vertexProgram); 15938 if (pipeline.fragmentProgram.usedTimes === 0) this._releaseProgram(pipeline.fragmentProgram); 15939 } 15940 } 15941 return super.delete(object); 15942 } 15943 /** 15944 * Frees internal resources. 15945 */ 15946 dispose() { 15947 super.dispose(); 15948 this.caches = /* @__PURE__ */ new Map(); 15949 this.programs = { 15950 vertex: /* @__PURE__ */ new Map(), 15951 fragment: /* @__PURE__ */ new Map(), 15952 compute: /* @__PURE__ */ new Map() 15953 }; 15954 } 15955 /** 15956 * Updates the pipeline for the given render object. 15957 * 15958 * @param {RenderObject} renderObject - The render object. 15959 */ 15960 updateForRender(renderObject) { 15961 this.getForRender(renderObject); 15962 } 15963 /** 15964 * Returns a compute pipeline for the given parameters. 15965 * 15966 * @private 15967 * @param {Node} computeNode - The compute node. 15968 * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. 15969 * @param {string} cacheKey - The cache key. 15970 * @param {Array<BindGroup>} bindings - The bindings. 15971 * @return {ComputePipeline} The compute pipeline. 15972 */ 15973 _getComputePipeline(computeNode, stageCompute, cacheKey, bindings) { 15974 cacheKey = cacheKey || this._getComputeCacheKey(computeNode, stageCompute); 15975 let pipeline = this.caches.get(cacheKey); 15976 if (pipeline === void 0) { 15977 pipeline = new ComputePipeline(cacheKey, stageCompute); 15978 this.caches.set(cacheKey, pipeline); 15979 this.backend.createComputePipeline(pipeline, bindings); 15980 } 15981 return pipeline; 15982 } 15983 /** 15984 * Returns a render pipeline for the given parameters. 15985 * 15986 * @private 15987 * @param {RenderObject} renderObject - The render object. 15988 * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. 15989 * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. 15990 * @param {string} cacheKey - The cache key. 15991 * @param {?Array<Promise>} promises - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. 15992 * @return {RenderObjectPipeline} The render pipeline. 15993 */ 15994 _getRenderPipeline(renderObject, stageVertex, stageFragment, cacheKey, promises) { 15995 cacheKey = cacheKey || this._getRenderCacheKey(renderObject, stageVertex, stageFragment); 15996 let pipeline = this.caches.get(cacheKey); 15997 if (pipeline === void 0) { 15998 pipeline = new RenderObjectPipeline(cacheKey, stageVertex, stageFragment); 15999 this.caches.set(cacheKey, pipeline); 16000 renderObject.pipeline = pipeline; 16001 this.backend.createRenderPipeline(renderObject, promises); 16002 } 16003 return pipeline; 16004 } 16005 /** 16006 * Computes a cache key representing a compute pipeline. 16007 * 16008 * @private 16009 * @param {Node} computeNode - The compute node. 16010 * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. 16011 * @return {string} The cache key. 16012 */ 16013 _getComputeCacheKey(computeNode, stageCompute) { 16014 return computeNode.id + "," + stageCompute.id; 16015 } 16016 /** 16017 * Computes a cache key representing a render pipeline. 16018 * 16019 * @private 16020 * @param {RenderObject} renderObject - The render object. 16021 * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. 16022 * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. 16023 * @return {string} The cache key. 16024 */ 16025 _getRenderCacheKey(renderObject, stageVertex, stageFragment) { 16026 return stageVertex.id + "," + stageFragment.id + "," + this.backend.getRenderCacheKey(renderObject); 16027 } 16028 /** 16029 * Releases the given pipeline. 16030 * 16031 * @private 16032 * @param {Pipeline} pipeline - The pipeline to release. 16033 */ 16034 _releasePipeline(pipeline) { 16035 this.caches.delete(pipeline.cacheKey); 16036 } 16037 /** 16038 * Releases the shader program. 16039 * 16040 * @private 16041 * @param {Object} program - The shader program to release. 16042 */ 16043 _releaseProgram(program) { 16044 const code3 = program.code; 16045 const stage = program.stage; 16046 this.programs[stage].delete(code3); 16047 this.info.destroyProgram(program); 16048 } 16049 /** 16050 * Returns `true` if the compute pipeline for the given compute node requires an update. 16051 * 16052 * @private 16053 * @param {Node} computeNode - The compute node. 16054 * @return {boolean} Whether the compute pipeline for the given compute node requires an update or not. 16055 */ 16056 _needsComputeUpdate(computeNode) { 16057 const data = this.get(computeNode); 16058 return data.pipeline === void 0 || data.version !== computeNode.version; 16059 } 16060 /** 16061 * Returns `true` if the render pipeline for the given render object requires an update. 16062 * 16063 * @private 16064 * @param {RenderObject} renderObject - The render object. 16065 * @return {boolean} Whether the render object for the given render object requires an update or not. 16066 */ 16067 _needsRenderUpdate(renderObject) { 16068 const data = this.get(renderObject); 16069 return data.pipeline === void 0 || this.backend.needsRenderUpdate(renderObject); 16070 } 16071}; 16072var Bindings = class extends DataMap { 16073 /** 16074 * Constructs a new bindings management component. 16075 * 16076 * @param {Backend} backend - The renderer's backend. 16077 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 16078 * @param {Textures} textures - Renderer component for managing textures. 16079 * @param {Attributes} attributes - Renderer component for managing attributes. 16080 * @param {Pipelines} pipelines - Renderer component for managing pipelines. 16081 * @param {Info} info - Renderer component for managing metrics and monitoring data. 16082 */ 16083 constructor(backend, nodes, textures, attributes, pipelines, info) { 16084 super(); 16085 this.backend = backend; 16086 this.textures = textures; 16087 this.pipelines = pipelines; 16088 this.attributes = attributes; 16089 this.nodes = nodes; 16090 this.info = info; 16091 this.pipelines.bindings = this; 16092 } 16093 /** 16094 * Returns the bind groups for the given render object. 16095 * 16096 * @param {RenderObject} renderObject - The render object. 16097 * @return {Array<BindGroup>} The bind groups. 16098 */ 16099 getForRender(renderObject) { 16100 const bindings = renderObject.getBindings(); 16101 for (const bindGroup of bindings) { 16102 const groupData = this.get(bindGroup); 16103 if (groupData.bindGroup === void 0) { 16104 this._init(bindGroup); 16105 this.backend.createBindings(bindGroup, bindings, 0); 16106 groupData.bindGroup = bindGroup; 16107 } 16108 } 16109 return bindings; 16110 } 16111 /** 16112 * Returns the bind groups for the given compute node. 16113 * 16114 * @param {Node} computeNode - The compute node. 16115 * @return {Array<BindGroup>} The bind groups. 16116 */ 16117 getForCompute(computeNode) { 16118 const bindings = this.nodes.getForCompute(computeNode).bindings; 16119 for (const bindGroup of bindings) { 16120 const groupData = this.get(bindGroup); 16121 if (groupData.bindGroup === void 0) { 16122 this._init(bindGroup); 16123 this.backend.createBindings(bindGroup, bindings, 0); 16124 groupData.bindGroup = bindGroup; 16125 } 16126 } 16127 return bindings; 16128 } 16129 /** 16130 * Updates the bindings for the given compute node. 16131 * 16132 * @param {Node} computeNode - The compute node. 16133 */ 16134 updateForCompute(computeNode) { 16135 this._updateBindings(this.getForCompute(computeNode)); 16136 } 16137 /** 16138 * Updates the bindings for the given render object. 16139 * 16140 * @param {RenderObject} renderObject - The render object. 16141 */ 16142 updateForRender(renderObject) { 16143 this._updateBindings(this.getForRender(renderObject)); 16144 } 16145 /** 16146 * Deletes the bindings for the given compute node. 16147 * 16148 * @param {Node} computeNode - The compute node. 16149 */ 16150 deleteForCompute(computeNode) { 16151 const bindings = this.nodes.getForCompute(computeNode).bindings; 16152 for (const bindGroup of bindings) { 16153 this.backend.deleteBindGroupData(bindGroup); 16154 this.delete(bindGroup); 16155 } 16156 } 16157 /** 16158 * Deletes the bindings for the given renderObject node. 16159 * 16160 * @param {RenderObject} renderObject - The renderObject. 16161 */ 16162 deleteForRender(renderObject) { 16163 const bindings = renderObject.getBindings(); 16164 for (const bindGroup of bindings) { 16165 this.backend.deleteBindGroupData(bindGroup); 16166 this.delete(bindGroup); 16167 } 16168 } 16169 /** 16170 * Updates the given array of bindings. 16171 * 16172 * @param {Array<BindGroup>} bindings - The bind groups. 16173 */ 16174 _updateBindings(bindings) { 16175 for (const bindGroup of bindings) { 16176 this._update(bindGroup, bindings); 16177 } 16178 } 16179 /** 16180 * Initializes the given bind group. 16181 * 16182 * @param {BindGroup} bindGroup - The bind group to initialize. 16183 */ 16184 _init(bindGroup) { 16185 for (const binding of bindGroup.bindings) { 16186 if (binding.isSampledTexture) { 16187 this.textures.updateTexture(binding.texture); 16188 } else if (binding.isSampler) { 16189 this.textures.updateSampler(binding.texture); 16190 } else if (binding.isStorageBuffer) { 16191 const attribute3 = binding.attribute; 16192 const attributeType = attribute3.isIndirectStorageBufferAttribute ? AttributeType.INDIRECT : AttributeType.STORAGE; 16193 this.attributes.update(attribute3, attributeType); 16194 } 16195 } 16196 } 16197 /** 16198 * Updates the given bind group. 16199 * 16200 * @param {BindGroup} bindGroup - The bind group to update. 16201 * @param {Array<BindGroup>} bindings - The bind groups. 16202 */ 16203 _update(bindGroup, bindings) { 16204 const { backend } = this; 16205 let needsBindingsUpdate = false; 16206 let cacheBindings = true; 16207 let cacheIndex = 0; 16208 let version = 0; 16209 for (const binding of bindGroup.bindings) { 16210 const updatedGroup = this.nodes.updateGroup(binding); 16211 if (updatedGroup === false) continue; 16212 if (binding.isStorageBuffer) { 16213 const attribute3 = binding.attribute; 16214 const attributeType = attribute3.isIndirectStorageBufferAttribute ? AttributeType.INDIRECT : AttributeType.STORAGE; 16215 const bindingData = backend.get(binding); 16216 this.attributes.update(attribute3, attributeType); 16217 if (bindingData.attribute !== attribute3) { 16218 bindingData.attribute = attribute3; 16219 needsBindingsUpdate = true; 16220 } 16221 } 16222 if (binding.isUniformBuffer) { 16223 const updated = binding.update(); 16224 if (updated) { 16225 backend.updateBinding(binding); 16226 } 16227 } else if (binding.isSampledTexture) { 16228 const updated = binding.update(); 16229 const texture3 = binding.texture; 16230 const texturesTextureData = this.textures.get(texture3); 16231 if (updated) { 16232 this.textures.updateTexture(texture3); 16233 if (binding.generation !== texturesTextureData.generation) { 16234 binding.generation = texturesTextureData.generation; 16235 needsBindingsUpdate = true; 16236 } 16237 texturesTextureData.bindGroups.add(bindGroup); 16238 } 16239 const textureData = backend.get(texture3); 16240 if (textureData.externalTexture !== void 0 || texturesTextureData.isDefaultTexture) { 16241 cacheBindings = false; 16242 } else { 16243 cacheIndex = cacheIndex * 10 + texture3.id; 16244 version += texture3.version; 16245 } 16246 if (texture3.isStorageTexture === true && texture3.mipmapsAutoUpdate === true) { 16247 const textureData2 = this.get(texture3); 16248 if (binding.store === true) { 16249 textureData2.needsMipmap = true; 16250 } else if (this.textures.needsMipmaps(texture3) && textureData2.needsMipmap === true) { 16251 this.backend.generateMipmaps(texture3); 16252 textureData2.needsMipmap = false; 16253 } 16254 } 16255 } else if (binding.isSampler) { 16256 const updated = binding.update(); 16257 if (updated) { 16258 const samplerKey = this.textures.updateSampler(binding.texture); 16259 if (binding.samplerKey !== samplerKey) { 16260 binding.samplerKey = samplerKey; 16261 needsBindingsUpdate = true; 16262 } 16263 } 16264 } 16265 if (binding.isBuffer && binding.updateRanges.length > 0) { 16266 binding.clearUpdateRanges(); 16267 } 16268 } 16269 if (needsBindingsUpdate === true) { 16270 this.backend.updateBindings(bindGroup, bindings, cacheBindings ? cacheIndex : 0, version); 16271 } 16272 } 16273}; 16274function painterSortStable(a, b) { 16275 if (a.groupOrder !== b.groupOrder) { 16276 return a.groupOrder - b.groupOrder; 16277 } else if (a.renderOrder !== b.renderOrder) { 16278 return a.renderOrder - b.renderOrder; 16279 } else if (a.z !== b.z) { 16280 return a.z - b.z; 16281 } else { 16282 return a.id - b.id; 16283 } 16284} 16285function reversePainterSortStable(a, b) { 16286 if (a.groupOrder !== b.groupOrder) { 16287 return a.groupOrder - b.groupOrder; 16288 } else if (a.renderOrder !== b.renderOrder) { 16289 return a.renderOrder - b.renderOrder; 16290 } else if (a.z !== b.z) { 16291 return b.z - a.z; 16292 } else { 16293 return a.id - b.id; 16294 } 16295} 16296function needsDoublePass(material) { 16297 const hasTransmission = material.transmission > 0 || material.transmissionNode && material.transmissionNode.isNode; 16298 return hasTransmission && material.side === DoubleSide && material.forceSinglePass === false; 16299} 16300var RenderList = class { 16301 /** 16302 * Constructs a render list. 16303 * 16304 * @param {Lighting} lighting - The lighting management component. 16305 * @param {Scene} scene - The scene. 16306 * @param {Camera} camera - The camera the scene is rendered with. 16307 */ 16308 constructor(lighting, scene, camera) { 16309 this.renderItems = []; 16310 this.renderItemsIndex = 0; 16311 this.opaque = []; 16312 this.transparentDoublePass = []; 16313 this.transparent = []; 16314 this.bundles = []; 16315 this.lightsNode = lighting.getNode(scene, camera); 16316 this.lightsArray = []; 16317 this.scene = scene; 16318 this.camera = camera; 16319 this.occlusionQueryCount = 0; 16320 } 16321 /** 16322 * This method is called right at the beginning of a render call 16323 * before the scene is analyzed. It prepares the internal data 16324 * structures for the upcoming render lists generation. 16325 * 16326 * @return {RenderList} A reference to this render list. 16327 */ 16328 begin() { 16329 this.renderItemsIndex = 0; 16330 this.opaque.length = 0; 16331 this.transparentDoublePass.length = 0; 16332 this.transparent.length = 0; 16333 this.bundles.length = 0; 16334 this.lightsArray.length = 0; 16335 this.occlusionQueryCount = 0; 16336 return this; 16337 } 16338 /** 16339 * Returns a render item for the giving render item state. The state is defined 16340 * by a series of object-related parameters. 16341 * 16342 * The method avoids object creation by holding render items and reusing them in 16343 * subsequent render calls (just with different property values). 16344 * 16345 * @param {Object3D} object - The 3D object. 16346 * @param {BufferGeometry} geometry - The 3D object's geometry. 16347 * @param {Material} material - The 3D object's material. 16348 * @param {number} groupOrder - The current group order. 16349 * @param {number} z - Th 3D object's depth value (z value in clip space). 16350 * @param {?number} group - {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 16351 * @param {ClippingContext} clippingContext - The current clipping context. 16352 * @return {Object} The render item. 16353 */ 16354 getNextRenderItem(object, geometry, material, groupOrder, z, group, clippingContext) { 16355 let renderItem = this.renderItems[this.renderItemsIndex]; 16356 if (renderItem === void 0) { 16357 renderItem = { 16358 id: object.id, 16359 object, 16360 geometry, 16361 material, 16362 groupOrder, 16363 renderOrder: object.renderOrder, 16364 z, 16365 group, 16366 clippingContext 16367 }; 16368 this.renderItems[this.renderItemsIndex] = renderItem; 16369 } else { 16370 renderItem.id = object.id; 16371 renderItem.object = object; 16372 renderItem.geometry = geometry; 16373 renderItem.material = material; 16374 renderItem.groupOrder = groupOrder; 16375 renderItem.renderOrder = object.renderOrder; 16376 renderItem.z = z; 16377 renderItem.group = group; 16378 renderItem.clippingContext = clippingContext; 16379 } 16380 this.renderItemsIndex++; 16381 return renderItem; 16382 } 16383 /** 16384 * Pushes the given object as a render item to the internal render lists. 16385 * The selected lists depend on the object properties. 16386 * 16387 * @param {Object3D} object - The 3D object. 16388 * @param {BufferGeometry} geometry - The 3D object's geometry. 16389 * @param {Material} material - The 3D object's material. 16390 * @param {number} groupOrder - The current group order. 16391 * @param {number} z - Th 3D object's depth value (z value in clip space). 16392 * @param {?number} group - {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 16393 * @param {ClippingContext} clippingContext - The current clipping context. 16394 */ 16395 push(object, geometry, material, groupOrder, z, group, clippingContext) { 16396 const renderItem = this.getNextRenderItem(object, geometry, material, groupOrder, z, group, clippingContext); 16397 if (object.occlusionTest === true) this.occlusionQueryCount++; 16398 if (material.transparent === true || material.transmission > 0 || material.transmissionNode && material.transmissionNode.isNode || material.backdropNode && material.backdropNode.isNode) { 16399 if (needsDoublePass(material)) this.transparentDoublePass.push(renderItem); 16400 this.transparent.push(renderItem); 16401 } else { 16402 this.opaque.push(renderItem); 16403 } 16404 } 16405 /** 16406 * Inserts the given object as a render item at the start of the internal render lists. 16407 * The selected lists depend on the object properties. 16408 * 16409 * @param {Object3D} object - The 3D object. 16410 * @param {BufferGeometry} geometry - The 3D object's geometry. 16411 * @param {Material} material - The 3D object's material. 16412 * @param {number} groupOrder - The current group order. 16413 * @param {number} z - Th 3D object's depth value (z value in clip space). 16414 * @param {?number} group - {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 16415 * @param {ClippingContext} clippingContext - The current clipping context. 16416 */ 16417 unshift(object, geometry, material, groupOrder, z, group, clippingContext) { 16418 const renderItem = this.getNextRenderItem(object, geometry, material, groupOrder, z, group, clippingContext); 16419 if (material.transparent === true || material.transmission > 0 || material.transmissionNode && material.transmissionNode.isNode || material.backdropNode && material.backdropNode.isNode) { 16420 if (needsDoublePass(material)) this.transparentDoublePass.unshift(renderItem); 16421 this.transparent.unshift(renderItem); 16422 } else { 16423 this.opaque.unshift(renderItem); 16424 } 16425 } 16426 /** 16427 * Pushes render bundle group data into the render list. 16428 * 16429 * @param {Object} group - Bundle group data. 16430 */ 16431 pushBundle(group) { 16432 this.bundles.push(group); 16433 } 16434 /** 16435 * Pushes a light into the render list. 16436 * 16437 * @param {Light} light - The light. 16438 */ 16439 pushLight(light) { 16440 this.lightsArray.push(light); 16441 } 16442 /** 16443 * Sorts the internal render lists. 16444 * 16445 * @param {?function(any, any): number} customOpaqueSort - A custom sort function for opaque objects. 16446 * @param {?function(any, any): number} customTransparentSort - A custom sort function for transparent objects. 16447 */ 16448 sort(customOpaqueSort, customTransparentSort) { 16449 if (this.opaque.length > 1) this.opaque.sort(customOpaqueSort || painterSortStable); 16450 if (this.transparentDoublePass.length > 1) this.transparentDoublePass.sort(customTransparentSort || reversePainterSortStable); 16451 if (this.transparent.length > 1) this.transparent.sort(customTransparentSort || reversePainterSortStable); 16452 } 16453 /** 16454 * This method performs finalizing tasks right after the render lists 16455 * have been generated. 16456 */ 16457 finish() { 16458 this.lightsNode.setLights(this.lightsArray); 16459 for (let i = this.renderItemsIndex, il = this.renderItems.length; i < il; i++) { 16460 const renderItem = this.renderItems[i]; 16461 if (renderItem.id === null) break; 16462 renderItem.id = null; 16463 renderItem.object = null; 16464 renderItem.geometry = null; 16465 renderItem.material = null; 16466 renderItem.groupOrder = null; 16467 renderItem.renderOrder = null; 16468 renderItem.z = null; 16469 renderItem.group = null; 16470 renderItem.clippingContext = null; 16471 } 16472 } 16473}; 16474var _chainKeys$2 = []; 16475var RenderLists = class { 16476 /** 16477 * Constructs a render lists management component. 16478 * 16479 * @param {Lighting} lighting - The lighting management component. 16480 */ 16481 constructor(lighting) { 16482 this.lighting = lighting; 16483 this.lists = new ChainMap(); 16484 } 16485 /** 16486 * Returns a render list for the given scene and camera. 16487 * 16488 * @param {Scene} scene - The scene. 16489 * @param {Camera} camera - The camera. 16490 * @return {RenderList} The render list. 16491 */ 16492 get(scene, camera) { 16493 const lists = this.lists; 16494 _chainKeys$2[0] = scene; 16495 _chainKeys$2[1] = camera; 16496 let list = lists.get(_chainKeys$2); 16497 if (list === void 0) { 16498 list = new RenderList(this.lighting, scene, camera); 16499 lists.set(_chainKeys$2, list); 16500 } 16501 _chainKeys$2[0] = null; 16502 _chainKeys$2[1] = null; 16503 return list; 16504 } 16505 /** 16506 * Frees all internal resources. 16507 */ 16508 dispose() { 16509 this.lists = new ChainMap(); 16510 } 16511}; 16512var _id$8 = 0; 16513var RenderContext = class { 16514 /** 16515 * Constructs a new render context. 16516 */ 16517 constructor() { 16518 this.id = _id$8++; 16519 this.mrt = null; 16520 this.color = true; 16521 this.clearColor = true; 16522 this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; 16523 this.depth = true; 16524 this.clearDepth = true; 16525 this.clearDepthValue = 1; 16526 this.stencil = false; 16527 this.clearStencil = true; 16528 this.clearStencilValue = 1; 16529 this.viewport = false; 16530 this.viewportValue = new Vector4(); 16531 this.scissor = false; 16532 this.scissorValue = new Vector4(); 16533 this.renderTarget = null; 16534 this.textures = null; 16535 this.depthTexture = null; 16536 this.activeCubeFace = 0; 16537 this.activeMipmapLevel = 0; 16538 this.sampleCount = 1; 16539 this.width = 0; 16540 this.height = 0; 16541 this.occlusionQueryCount = 0; 16542 this.clippingContext = null; 16543 this.camera = null; 16544 this.isRenderContext = true; 16545 } 16546 /** 16547 * Returns the cache key of this render context. 16548 * 16549 * @return {number} The cache key. 16550 */ 16551 getCacheKey() { 16552 return getCacheKey(this); 16553 } 16554}; 16555function getCacheKey(renderContext) { 16556 const { textures, activeCubeFace, activeMipmapLevel } = renderContext; 16557 const values = [activeCubeFace, activeMipmapLevel]; 16558 for (const texture3 of textures) { 16559 values.push(texture3.id); 16560 } 16561 return hashArray(values); 16562} 16563var RenderContexts = class { 16564 /** 16565 * Constructs a new render context management component. 16566 * 16567 * @param {Renderer} renderer - The renderer. 16568 */ 16569 constructor(renderer) { 16570 this.renderer = renderer; 16571 this._renderContexts = {}; 16572 } 16573 /** 16574 * Returns a render context for the given scene, camera and render target. 16575 * 16576 * @param {?RenderTarget} [renderTarget=null] - The active render target. 16577 * @param {?MRTNode} [mrt=null] - The MRT configuration 16578 * @param {?number} [callDepth=0] - The call depth of the renderer. 16579 * @return {RenderContext} The render context. 16580 */ 16581 get(renderTarget = null, mrt3 = null, callDepth = 0) { 16582 let attachmentState; 16583 if (renderTarget === null) { 16584 attachmentState = "default"; 16585 } else { 16586 const format = renderTarget.texture.format; 16587 const type = renderTarget.texture.type; 16588 const count = renderTarget.textures.length; 16589 attachmentState = `${count}:${format}:${type}:${renderTarget.samples}:${renderTarget.depthBuffer}:${renderTarget.stencilBuffer}`; 16590 } 16591 const mrtState = mrt3 !== null ? mrt3.id : "default"; 16592 const renderStateKey = attachmentState + "-" + mrtState + "-" + callDepth; 16593 let renderState = this._renderContexts[renderStateKey]; 16594 if (renderState === void 0) { 16595 renderState = new RenderContext(); 16596 renderState.mrt = mrt3; 16597 this._renderContexts[renderStateKey] = renderState; 16598 } 16599 if (renderTarget !== null) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; 16600 renderState.clearDepthValue = this.renderer.getClearDepth(); 16601 renderState.clearStencilValue = this.renderer.getClearStencil(); 16602 return renderState; 16603 } 16604 /** 16605 * Frees internal resources. 16606 */ 16607 dispose() { 16608 this._renderContexts = {}; 16609 } 16610}; 16611var _size$3 = /* @__PURE__ */ new Vector3(); 16612var Textures = class extends DataMap { 16613 /** 16614 * Constructs a new texture management component. 16615 * 16616 * @param {Renderer} renderer - The renderer. 16617 * @param {Backend} backend - The renderer's backend. 16618 * @param {Info} info - Renderer component for managing metrics and monitoring data. 16619 */ 16620 constructor(renderer, backend, info) { 16621 super(); 16622 this.renderer = renderer; 16623 this.backend = backend; 16624 this.info = info; 16625 this._htmlTextures = /* @__PURE__ */ new Set(); 16626 } 16627 /** 16628 * Updates the given render target. Based on the given render target configuration, 16629 * it updates the texture states representing the attachments of the framebuffer. 16630 * 16631 * @param {RenderTarget} renderTarget - The render target to update. 16632 * @param {number} [activeMipmapLevel=0] - The active mipmap level. 16633 */ 16634 updateRenderTarget(renderTarget, activeMipmapLevel = 0) { 16635 const renderTargetData = this.get(renderTarget); 16636 const sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; 16637 const depthTextureMips = renderTargetData.depthTextureMips || (renderTargetData.depthTextureMips = {}); 16638 const textures = renderTarget.textures; 16639 const size3 = this.getSize(textures[0]); 16640 const mipWidth = size3.width >> activeMipmapLevel; 16641 const mipHeight = size3.height >> activeMipmapLevel; 16642 let depthTexture = renderTarget.depthTexture || depthTextureMips[activeMipmapLevel]; 16643 const useDepthTexture = renderTarget.depthBuffer === true || renderTarget.stencilBuffer === true; 16644 let textureNeedsUpdate = false; 16645 if (depthTexture === void 0 && useDepthTexture) { 16646 depthTexture = new DepthTexture(); 16647 depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; 16648 depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; 16649 depthTexture.image.width = mipWidth; 16650 depthTexture.image.height = mipHeight; 16651 depthTexture.image.depth = size3.depth; 16652 depthTexture.renderTarget = renderTarget; 16653 depthTexture.isArrayTexture = renderTarget.multiview === true && size3.depth > 1; 16654 depthTextureMips[activeMipmapLevel] = depthTexture; 16655 } 16656 if (renderTargetData.width !== size3.width || size3.height !== renderTargetData.height) { 16657 textureNeedsUpdate = true; 16658 if (depthTexture) { 16659 depthTexture.needsUpdate = true; 16660 depthTexture.image.width = mipWidth; 16661 depthTexture.image.height = mipHeight; 16662 depthTexture.image.depth = depthTexture.isArrayTexture ? depthTexture.image.depth : 1; 16663 } 16664 } 16665 renderTargetData.width = size3.width; 16666 renderTargetData.height = size3.height; 16667 renderTargetData.textures = textures; 16668 renderTargetData.depthTexture = depthTexture || null; 16669 renderTargetData.depth = renderTarget.depthBuffer; 16670 renderTargetData.stencil = renderTarget.stencilBuffer; 16671 renderTargetData.renderTarget = renderTarget; 16672 if (renderTargetData.sampleCount !== sampleCount) { 16673 textureNeedsUpdate = true; 16674 if (depthTexture) { 16675 depthTexture.needsUpdate = true; 16676 } 16677 renderTargetData.sampleCount = sampleCount; 16678 } 16679 const options = { sampleCount }; 16680 if (renderTarget.isXRRenderTarget !== true) { 16681 for (let i = 0; i < textures.length; i++) { 16682 const texture3 = textures[i]; 16683 if (textureNeedsUpdate) texture3.needsUpdate = true; 16684 this.updateTexture(texture3, options); 16685 } 16686 if (depthTexture) { 16687 this.updateTexture(depthTexture, options); 16688 } 16689 } 16690 if (renderTargetData.initialized !== true) { 16691 renderTargetData.initialized = true; 16692 this.info.memory.renderTargets++; 16693 renderTargetData.onDispose = () => { 16694 this._destroyRenderTarget(renderTarget); 16695 }; 16696 renderTarget.addEventListener("dispose", renderTargetData.onDispose); 16697 } 16698 } 16699 /** 16700 * Updates the given texture. Depending on the texture state, this method 16701 * triggers the upload of texture data to the GPU memory. If the texture data are 16702 * not yet ready for the upload, it uses default texture data for as a placeholder. 16703 * 16704 * @param {Texture} texture - The texture to update. 16705 * @param {Object} [options={}] - The options. 16706 */ 16707 updateTexture(texture3, options = {}) { 16708 const textureData = this.get(texture3); 16709 if (textureData.initialized === true && textureData.version === texture3.version) return; 16710 const isRenderTarget = texture3.isRenderTargetTexture || texture3.isDepthTexture || texture3.isFramebufferTexture; 16711 const backend = this.backend; 16712 if (isRenderTarget && textureData.initialized === true) { 16713 backend.destroyTexture(texture3); 16714 } 16715 if (texture3.isFramebufferTexture) { 16716 const renderTarget = this.renderer.getRenderTarget(); 16717 if (renderTarget) { 16718 texture3.type = renderTarget.texture.type; 16719 } else { 16720 texture3.type = UnsignedByteType; 16721 } 16722 } 16723 if (texture3.isHTMLTexture && texture3.image) { 16724 const canvas = this.renderer.domElement; 16725 if ("requestPaint" in canvas) { 16726 if (!canvas.hasAttribute("layoutsubtree")) { 16727 canvas.setAttribute("layoutsubtree", "true"); 16728 } 16729 if (texture3.image.parentNode !== canvas) { 16730 canvas.appendChild(texture3.image); 16731 } 16732 if (this._htmlTextures.size === 0) { 16733 const htmlTextures = this._htmlTextures; 16734 canvas.onpaint = (event) => { 16735 const changed = event && event.changedElements; 16736 for (const t of htmlTextures) { 16737 if (!changed || changed.includes(t.image)) { 16738 t.needsUpdate = true; 16739 } 16740 } 16741 }; 16742 } 16743 this._htmlTextures.add(texture3); 16744 } 16745 } 16746 const { width, height, depth: depth3 } = this.getSize(texture3); 16747 options.width = width; 16748 options.height = height; 16749 options.depth = depth3; 16750 options.needsMipmaps = this.needsMipmaps(texture3); 16751 options.levels = options.needsMipmaps ? this.getMipLevels(texture3, width, height) : 1; 16752 if (texture3.isCubeTexture && texture3.mipmaps.length > 0) options.levels++; 16753 if (isRenderTarget || texture3.isStorageTexture === true || texture3.isExternalTexture === true) { 16754 backend.createTexture(texture3, options); 16755 textureData.generation = texture3.version; 16756 } else { 16757 if (texture3.version > 0) { 16758 const image = texture3.image; 16759 if (image === void 0) { 16760 warn("Renderer: Texture marked for update but image is undefined."); 16761 } else if (image.complete === false) { 16762 warn("Renderer: Texture marked for update but image is incomplete."); 16763 } else { 16764 if (texture3.images) { 16765 const images = []; 16766 for (const image2 of texture3.images) { 16767 images.push(image2); 16768 } 16769 options.images = images; 16770 } else { 16771 options.image = image; 16772 } 16773 if (textureData.isDefaultTexture === void 0 || textureData.isDefaultTexture === true) { 16774 backend.createTexture(texture3, options); 16775 textureData.isDefaultTexture = false; 16776 textureData.generation = texture3.version; 16777 } 16778 if (texture3.source.dataReady === true) backend.updateTexture(texture3, options); 16779 const skipAutoGeneration = texture3.isStorageTexture === true && texture3.mipmapsAutoUpdate === false; 16780 if (options.needsMipmaps && texture3.mipmaps.length === 0 && !skipAutoGeneration) { 16781 backend.generateMipmaps(texture3); 16782 } 16783 if (texture3.onUpdate) texture3.onUpdate(texture3); 16784 } 16785 } else { 16786 backend.createDefaultTexture(texture3); 16787 textureData.isDefaultTexture = true; 16788 textureData.generation = texture3.version; 16789 } 16790 } 16791 if (textureData.initialized !== true) { 16792 textureData.initialized = true; 16793 textureData.generation = texture3.version; 16794 textureData.bindGroups = /* @__PURE__ */ new Set(); 16795 this.info.createTexture(texture3); 16796 if (texture3.isVideoTexture && ColorManagement.enabled === true && ColorManagement.getTransfer(texture3.colorSpace) !== SRGBTransfer) { 16797 warn("WebGPURenderer: Video textures must use a color space with a sRGB transfer function, e.g. SRGBColorSpace."); 16798 } 16799 textureData.onDispose = () => { 16800 this._destroyTexture(texture3); 16801 }; 16802 texture3.addEventListener("dispose", textureData.onDispose); 16803 } 16804 textureData.version = texture3.version; 16805 } 16806 /** 16807 * Updates the sampler for the given texture. This method has no effect 16808 * for the WebGL backend since it has no concept of samplers. Texture 16809 * parameters are configured with the `texParameter()` command for each 16810 * texture. 16811 * 16812 * In WebGPU, samplers are objects like textures and it's possible to share 16813 * them when the texture parameters match. 16814 * 16815 * @param {Texture} texture - The texture to update the sampler for. 16816 * @return {string} The current sampler key. 16817 */ 16818 updateSampler(texture3) { 16819 return this.backend.updateSampler(texture3); 16820 } 16821 /** 16822 * Computes the size of the given texture and writes the result 16823 * into the target vector. This vector is also returned by the 16824 * method. 16825 * 16826 * If no texture data are available for the compute yet, the method 16827 * returns default size values. 16828 * 16829 * @param {Texture} texture - The texture to compute the size for. 16830 * @param {Vector3} target - The target vector. 16831 * @return {Vector3} The target vector. 16832 */ 16833 getSize(texture3, target = _size$3) { 16834 let image = texture3.images ? texture3.images[0] : texture3.image; 16835 if (image) { 16836 if (image.image !== void 0) image = image.image; 16837 if (texture3.isHTMLTexture) { 16838 target.width = image.offsetWidth || 1; 16839 target.height = image.offsetHeight || 1; 16840 target.depth = 1; 16841 } else if (typeof HTMLVideoElement !== "undefined" && image instanceof HTMLVideoElement) { 16842 target.width = image.videoWidth || 1; 16843 target.height = image.videoHeight || 1; 16844 target.depth = 1; 16845 } else if (typeof VideoFrame !== "undefined" && image instanceof VideoFrame) { 16846 target.width = image.displayWidth || 1; 16847 target.height = image.displayHeight || 1; 16848 target.depth = 1; 16849 } else { 16850 target.width = image.width || 1; 16851 target.height = image.height || 1; 16852 target.depth = texture3.isCubeTexture ? 6 : image.depth || 1; 16853 } 16854 } else { 16855 target.width = target.height = target.depth = 1; 16856 } 16857 return target; 16858 } 16859 /** 16860 * Computes the number of mipmap levels for the given texture. 16861 * 16862 * @param {Texture} texture - The texture. 16863 * @param {number} width - The texture's width. 16864 * @param {number} height - The texture's height. 16865 * @return {number} The number of mipmap levels. 16866 */ 16867 getMipLevels(texture3, width, height) { 16868 let mipLevelCount; 16869 if (texture3.mipmaps.length > 0) { 16870 mipLevelCount = texture3.mipmaps.length; 16871 } else { 16872 if (texture3.isCompressedTexture === true) { 16873 mipLevelCount = 1; 16874 } else { 16875 mipLevelCount = Math.floor(Math.log2(Math.max(width, height))) + 1; 16876 } 16877 } 16878 return mipLevelCount; 16879 } 16880 /** 16881 * Returns `true` if the given texture makes use of mipmapping. 16882 * 16883 * @param {Texture} texture - The texture. 16884 * @return {boolean} Whether mipmaps are required or not. 16885 */ 16886 needsMipmaps(texture3) { 16887 return texture3.generateMipmaps === true || texture3.mipmaps.length > 0; 16888 } 16889 /** 16890 * Frees internal resources when the given render target isn't 16891 * required anymore. 16892 * 16893 * @param {RenderTarget} renderTarget - The render target to destroy. 16894 */ 16895 _destroyRenderTarget(renderTarget) { 16896 if (this.has(renderTarget) === true) { 16897 const renderTargetData = this.get(renderTarget); 16898 const textures = renderTargetData.textures; 16899 const depthTexture = renderTargetData.depthTexture; 16900 renderTarget.removeEventListener("dispose", renderTargetData.onDispose); 16901 for (let i = 0; i < textures.length; i++) { 16902 this._destroyTexture(textures[i]); 16903 } 16904 if (depthTexture) { 16905 this._destroyTexture(depthTexture); 16906 } 16907 this.delete(renderTarget); 16908 this.backend.delete(renderTarget); 16909 this.info.memory.renderTargets--; 16910 } 16911 } 16912 /** 16913 * Frees internal resource when the given texture isn't 16914 * required anymore. 16915 * 16916 * @param {Texture} texture - The texture to destroy. 16917 */ 16918 _destroyTexture(texture3) { 16919 if (this.has(texture3) === true) { 16920 const textureData = this.get(texture3); 16921 texture3.removeEventListener("dispose", textureData.onDispose); 16922 const isDefaultTexture = textureData.isDefaultTexture; 16923 this.backend.destroyTexture(texture3, isDefaultTexture); 16924 if (textureData.bindGroups) { 16925 for (const bindGroup of textureData.bindGroups) { 16926 const bindingsData = this.backend.get(bindGroup); 16927 bindingsData.groups = void 0; 16928 bindingsData.versions = void 0; 16929 } 16930 } 16931 this._htmlTextures.delete(texture3); 16932 this.delete(texture3); 16933 this.info.destroyTexture(texture3); 16934 } 16935 } 16936}; 16937var Color4 = class extends Color { 16938 /** 16939 * Constructs a new four-component color. 16940 * You can also pass a single THREE.Color, hex or 16941 * string argument to this constructor. 16942 * 16943 * @param {number|string} [r=1] - The red value. 16944 * @param {number} [g=1] - The green value. 16945 * @param {number} [b=1] - The blue value. 16946 * @param {number} [a=1] - The alpha value. 16947 */ 16948 constructor(r, g, b, a = 1) { 16949 super(r, g, b); 16950 this.a = a; 16951 } 16952 /** 16953 * Overwrites the default to honor alpha. 16954 * You can also pass a single THREE.Color, hex or 16955 * string argument to this method. 16956 * 16957 * @param {number|string|Color} r - The red value. 16958 * @param {number} [g] - The green value. 16959 * @param {number} [b] - The blue value. 16960 * @param {number} [a=1] - The alpha value. 16961 * @return {Color4} A reference to this object. 16962 */ 16963 set(r, g, b, a = 1) { 16964 this.a = a; 16965 return super.set(r, g, b); 16966 } 16967 /** 16968 * Overwrites the default to honor alpha. 16969 * 16970 * @param {Color4} color - The color to copy. 16971 * @return {Color4} A reference to this object. 16972 */ 16973 copy(color3) { 16974 if (color3.a !== void 0) this.a = color3.a; 16975 return super.copy(color3); 16976 } 16977 /** 16978 * Overwrites the default to honor alpha. 16979 * 16980 * @return {Color4} The cloned color. 16981 */ 16982 clone() { 16983 return new this.constructor(this.r, this.g, this.b, this.a); 16984 } 16985}; 16986var ParameterNode = class extends PropertyNode { 16987 static get type() { 16988 return "ParameterNode"; 16989 } 16990 /** 16991 * Constructs a new parameter node. 16992 * 16993 * @param {string} nodeType - The type of the node. 16994 * @param {?string} [name=null] - The name of the parameter in the shader. 16995 */ 16996 constructor(nodeType, name = null) { 16997 super(nodeType, name); 16998 this.isParameterNode = true; 16999 } 17000 /** 17001 * Gets the type of a member variable in the parameter node. 17002 * 17003 * @param {NodeBuilder} builder - The node builder. 17004 * @param {string} name - The name of the member variable. 17005 * @returns {string} 17006 */ 17007 getMemberType(builder, name) { 17008 const type = this.getNodeType(builder); 17009 const struct3 = builder.getStructTypeNode(type); 17010 let memberType; 17011 if (struct3 !== null) { 17012 memberType = struct3.getMemberType(builder, name); 17013 } else { 17014 error(`TSL: Member "${name}" not found in struct "${type}".`, new StackTrace()); 17015 memberType = "float"; 17016 } 17017 return memberType; 17018 } 17019 getHash() { 17020 return String(this.id); 17021 } 17022 generate() { 17023 return this.name; 17024 } 17025}; 17026var parameter = (type, name) => new ParameterNode(type, name); 17027var StackNode = class extends Node2 { 17028 static get type() { 17029 return "StackNode"; 17030 } 17031 /** 17032 * Constructs a new stack node. 17033 * 17034 * @param {?StackNode} [parent=null] - The parent stack node. 17035 */ 17036 constructor(parent = null) { 17037 super(); 17038 this.nodes = []; 17039 this.outputNode = null; 17040 this.parent = parent; 17041 this._currentCond = null; 17042 this._expressionNode = null; 17043 this._currentNode = null; 17044 this.isStackNode = true; 17045 } 17046 getElementType(builder) { 17047 return this.hasOutput(builder) ? this.outputNode.getElementType(builder) : "void"; 17048 } 17049 generateNodeType(builder) { 17050 return this.hasOutput(builder) ? this.outputNode.getNodeType(builder) : "void"; 17051 } 17052 getMemberType(builder, name) { 17053 return this.hasOutput(builder) ? this.outputNode.getMemberType(builder, name) : "void"; 17054 } 17055 /** 17056 * Adds a node to this stack. 17057 * 17058 * @param {Node} node - The node to add. 17059 * @param {number} [index=this.nodes.length] - The index where the node should be added. 17060 * @return {StackNode} A reference to this stack node. 17061 */ 17062 addToStack(node, index = this.nodes.length) { 17063 if (node.isNode !== true) { 17064 error("TSL: Invalid node added to stack.", new StackTrace()); 17065 return this; 17066 } 17067 this.nodes.splice(index, 0, node); 17068 return this; 17069 } 17070 /** 17071 * Adds a node to the stack before the current node. 17072 * 17073 * @param {Node} node - The node to add. 17074 * @return {StackNode} A reference to this stack node. 17075 */ 17076 addToStackBefore(node) { 17077 const index = this._currentNode ? this.nodes.indexOf(this._currentNode) : 0; 17078 return this.addToStack(node, index); 17079 } 17080 /** 17081 * Represent an `if` statement in TSL. 17082 * 17083 * @param {Node} boolNode - Represents the condition. 17084 * @param {Function} method - TSL code which is executed if the condition evaluates to `true`. 17085 * @return {StackNode} A reference to this stack node. 17086 */ 17087 If(boolNode, method) { 17088 const methodNode = new ShaderNode(method); 17089 this._currentCond = select(boolNode, methodNode); 17090 return this.addToStack(this._currentCond); 17091 } 17092 /** 17093 * Represent an `elseif` statement in TSL. 17094 * 17095 * @param {Node} boolNode - Represents the condition. 17096 * @param {Function} method - TSL code which is executed if the condition evaluates to `true`. 17097 * @return {StackNode} A reference to this stack node. 17098 */ 17099 ElseIf(boolNode, method) { 17100 const methodNode = new ShaderNode(method); 17101 const ifNode = select(boolNode, methodNode); 17102 this._currentCond.elseNode = ifNode; 17103 this._currentCond = ifNode; 17104 return this; 17105 } 17106 /** 17107 * Represent an `else` statement in TSL. 17108 * 17109 * @param {Function} method - TSL code which is executed in the `else` case. 17110 * @return {StackNode} A reference to this stack node. 17111 */ 17112 Else(method) { 17113 this._currentCond.elseNode = new ShaderNode(method); 17114 return this; 17115 } 17116 /** 17117 * Represents a `switch` statement in TSL. 17118 * 17119 * @param {any} expression - Represents the expression. 17120 * @param {Function} method - TSL code which is executed if the condition evaluates to `true`. 17121 * @return {StackNode} A reference to this stack node. 17122 */ 17123 Switch(expression3) { 17124 this._expressionNode = nodeObject(expression3); 17125 return this; 17126 } 17127 /** 17128 * Represents a `case` statement in TSL. The TSL version accepts an arbitrary numbers of values. 17129 * The last parameter must be the callback method that should be executed in the `true` case. 17130 * 17131 * @param {...any} params - The values of the `Case()` statement as well as the callback method. 17132 * @return {StackNode} A reference to this stack node. 17133 */ 17134 Case(...params) { 17135 const caseNodes = []; 17136 if (params.length >= 2) { 17137 for (let i = 0; i < params.length - 1; i++) { 17138 caseNodes.push(this._expressionNode.equal(nodeObject(params[i]))); 17139 } 17140 } else { 17141 error("TSL: Invalid parameter length. Case() requires at least two parameters.", new StackTrace()); 17142 } 17143 const method = params[params.length - 1]; 17144 const methodNode = new ShaderNode(method); 17145 let caseNode = caseNodes[0]; 17146 for (let i = 1; i < caseNodes.length; i++) { 17147 caseNode = caseNode.or(caseNodes[i]); 17148 } 17149 const condNode = select(caseNode, methodNode); 17150 if (this._currentCond === null) { 17151 this._currentCond = condNode; 17152 return this.addToStack(this._currentCond); 17153 } else { 17154 this._currentCond.elseNode = condNode; 17155 this._currentCond = condNode; 17156 return this; 17157 } 17158 } 17159 /** 17160 * Represents the default code block of a Switch/Case statement. 17161 * 17162 * @param {Function} method - TSL code which is executed in the `else` case. 17163 * @return {StackNode} A reference to this stack node. 17164 */ 17165 Default(method) { 17166 this.Else(method); 17167 return this; 17168 } 17169 setup(builder) { 17170 const nodeProperties = builder.getNodeProperties(this); 17171 let index = 0; 17172 for (const childNode of this.getChildren()) { 17173 if (childNode.isVarNode && childNode.isIntent(builder)) { 17174 if (childNode.isAssign(builder) !== true) { 17175 continue; 17176 } 17177 } 17178 nodeProperties["node" + index++] = childNode; 17179 } 17180 return nodeProperties.outputNode || null; 17181 } 17182 hasOutput(builder) { 17183 return this.outputNode && this.outputNode.isNode && this.outputNode.getNodeType(builder) !== "void"; 17184 } 17185 build(builder, ...params) { 17186 const previousStack = getCurrentStack(); 17187 const buildStage = builder.buildStage; 17188 setCurrentStack(this); 17189 builder.setActiveStack(this); 17190 const buildNode = (node) => { 17191 this._currentNode = node; 17192 if (node.isVarNode && node.isIntent(builder)) { 17193 if (node.isAssign(builder) !== true) { 17194 return; 17195 } 17196 } 17197 if (buildStage === "setup") { 17198 node.build(builder); 17199 } else if (buildStage === "analyze") { 17200 node.build(builder, this); 17201 } else if (buildStage === "generate") { 17202 const stages = builder.getDataFromNode(node, "any").stages; 17203 const parents = stages && stages[builder.shaderStage]; 17204 if (node.isVarNode && parents && parents.length === 1 && parents[0] && parents[0].isStackNode) { 17205 return; 17206 } 17207 node.build(builder, "void"); 17208 } 17209 }; 17210 const nodes = [...this.nodes]; 17211 for (const node of nodes) { 17212 buildNode(node); 17213 } 17214 this._currentNode = null; 17215 const newNodes = this.nodes.filter((node) => nodes.indexOf(node) === -1); 17216 for (const node of newNodes) { 17217 buildNode(node); 17218 } 17219 let result; 17220 if (this.hasOutput(builder)) { 17221 result = this.outputNode.build(builder, ...params); 17222 } else { 17223 result = super.build(builder, ...params); 17224 } 17225 setCurrentStack(previousStack); 17226 builder.removeActiveStack(this); 17227 return result; 17228 } 17229}; 17230var stack = /* @__PURE__ */ nodeProxy(StackNode).setParameterLength(0, 1); 17231function getMembersLayout(members) { 17232 return Object.entries(members).map(([name, value]) => { 17233 if (typeof value === "string") { 17234 return { name, type: value, atomic: false }; 17235 } 17236 return { name, type: value.type, atomic: value.atomic || false }; 17237 }); 17238} 17239var StructTypeNode = class extends Node2 { 17240 static get type() { 17241 return "StructTypeNode"; 17242 } 17243 /** 17244 * Creates an instance of StructTypeNode. 17245 * 17246 * @param {Object} membersLayout - The layout of the members for the struct. 17247 * @param {?string} [name=null] - The optional name of the struct. 17248 */ 17249 constructor(membersLayout, name = null) { 17250 super("struct"); 17251 this.membersLayout = getMembersLayout(membersLayout); 17252 this.name = name; 17253 this.isStructLayoutNode = true; 17254 } 17255 /** 17256 * Returns the length of the struct. 17257 * The length is calculated by summing the lengths of the struct's members. 17258 * 17259 * @returns {number} The length of the struct. 17260 */ 17261 getLength() { 17262 const BYTES_PER_ELEMENT = Float32Array.BYTES_PER_ELEMENT; 17263 let maxAlignment = 1; 17264 let offset3 = 0; 17265 for (const member of this.membersLayout) { 17266 const type = member.type; 17267 const itemSize = getMemoryLengthFromType(type); 17268 const alignment = getAlignmentFromType(type) / BYTES_PER_ELEMENT; 17269 maxAlignment = Math.max(maxAlignment, alignment); 17270 const chunkOffset = offset3 % maxAlignment; 17271 const overhang = chunkOffset % alignment; 17272 if (overhang !== 0) { 17273 offset3 += alignment - overhang; 17274 } 17275 offset3 += itemSize; 17276 } 17277 return Math.ceil(offset3 / maxAlignment) * maxAlignment; 17278 } 17279 getMemberType(builder, name) { 17280 const member = this.membersLayout.find((m) => m.name === name); 17281 return member ? member.type : "void"; 17282 } 17283 generateNodeType(builder) { 17284 const structType = builder.getStructTypeFromNode(this, this.membersLayout, this.name); 17285 return structType.name; 17286 } 17287 setup(builder) { 17288 builder.getStructTypeFromNode(this, this.membersLayout, this.name); 17289 builder.addInclude(this); 17290 } 17291 generate(builder) { 17292 return this.getNodeType(builder); 17293 } 17294}; 17295var StructNode = class extends Node2 { 17296 static get type() { 17297 return "StructNode"; 17298 } 17299 constructor(structTypeNode, values) { 17300 super("vec3"); 17301 this.structTypeNode = structTypeNode; 17302 this.values = values; 17303 this.isStructNode = true; 17304 } 17305 generateNodeType(builder) { 17306 return this.structTypeNode.getNodeType(builder); 17307 } 17308 getMemberType(builder, name) { 17309 return this.structTypeNode.getMemberType(builder, name); 17310 } 17311 _getChildren() { 17312 const children2 = super._getChildren(); 17313 const structTypeProperty = children2.find((child) => child.childNode === this.structTypeNode); 17314 children2.splice(children2.indexOf(structTypeProperty), 1); 17315 children2.push(structTypeProperty); 17316 return children2; 17317 } 17318 generate(builder) { 17319 const nodeVar = builder.getVarFromNode(this); 17320 const structType = nodeVar.type; 17321 const propertyName = builder.getPropertyName(nodeVar); 17322 builder.addLineFlowCode(`${propertyName} = ${builder.generateStruct(structType, this.structTypeNode.membersLayout, this.values)}`, this); 17323 return nodeVar.name; 17324 } 17325}; 17326var struct = (membersLayout, name = null) => { 17327 const structLayout = new StructTypeNode(membersLayout, name); 17328 const struct3 = (...params) => { 17329 let values = null; 17330 if (params.length > 0) { 17331 if (params[0].isNode) { 17332 values = {}; 17333 const names = Object.keys(membersLayout); 17334 for (let i = 0; i < params.length; i++) { 17335 values[names[i]] = params[i]; 17336 } 17337 } else { 17338 values = params[0]; 17339 } 17340 } 17341 return new StructNode(structLayout, values); 17342 }; 17343 struct3.layout = structLayout; 17344 struct3.isStruct = true; 17345 return struct3; 17346}; 17347var OutputStructNode = class extends Node2 { 17348 static get type() { 17349 return "OutputStructNode"; 17350 } 17351 /** 17352 * Constructs a new output struct node. The constructor can be invoked with an 17353 * arbitrary number of nodes representing the members. 17354 * 17355 * @param {...Node} members - A parameter list of nodes. 17356 */ 17357 constructor(...members) { 17358 super(); 17359 this.members = members; 17360 this.isOutputStructNode = true; 17361 } 17362 generateNodeType() { 17363 return "OutputType"; 17364 } 17365 generate(builder) { 17366 const nodeData = builder.getDataFromNode(this); 17367 if (nodeData.membersLayout === void 0) { 17368 const members2 = this.members; 17369 const membersLayout = []; 17370 for (let i = 0; i < members2.length; i++) { 17371 const name = "m" + i; 17372 const type = members2[i].getNodeType(builder); 17373 membersLayout.push({ name, type, index: i }); 17374 } 17375 nodeData.membersLayout = membersLayout; 17376 nodeData.structType = builder.getOutputStructTypeFromNode(this, nodeData.membersLayout); 17377 } 17378 const propertyName = builder.getOutputStructName(); 17379 const members = this.members; 17380 const structPrefix = propertyName !== "" ? propertyName + "." : ""; 17381 for (let i = 0; i < members.length; i++) { 17382 const snippet = members[i].build(builder); 17383 builder.addLineFlowCode(`${structPrefix}m${i} = ${snippet}`, this); 17384 } 17385 return propertyName; 17386 } 17387}; 17388var outputStruct = /* @__PURE__ */ nodeProxy(OutputStructNode); 17389var BlendMode = class { 17390 /** 17391 * Constructs a new blending configuration. 17392 * 17393 * @param {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending|MaterialBlending)} [blending=NormalBlending] - The blending mode. 17394 */ 17395 constructor(blending = NormalBlending) { 17396 this.blending = blending; 17397 this.blendSrc = SrcAlphaFactor; 17398 this.blendDst = OneMinusSrcAlphaFactor; 17399 this.blendEquation = AddEquation; 17400 this.blendSrcAlpha = null; 17401 this.blendDstAlpha = null; 17402 this.blendEquationAlpha = null; 17403 this.premultiplyAlpha = false; 17404 } 17405 /** 17406 * Copies the blending properties from the given source to this instance. 17407 * 17408 * @param {BlendMode} source - The blending configuration to copy from. 17409 * @return {BlendMode} A reference to this instance. 17410 */ 17411 copy(source) { 17412 this.blending = source.blending; 17413 this.blendSrc = source.blendSrc; 17414 this.blendDst = source.blendDst; 17415 this.blendEquation = source.blendEquation; 17416 this.blendSrcAlpha = source.blendSrcAlpha; 17417 this.blendDstAlpha = source.blendDstAlpha; 17418 this.blendEquationAlpha = source.blendEquationAlpha; 17419 this.premultiplyAlpha = source.premultiplyAlpha; 17420 return this; 17421 } 17422 /** 17423 * Returns a clone of this blending configuration. 17424 * 17425 * @return {BlendMode} A new Blending instance with the same properties. 17426 */ 17427 clone() { 17428 return new this.constructor().copy(this); 17429 } 17430}; 17431var _noBlending = /* @__PURE__ */ new BlendMode(NoBlending); 17432var _materialBlending = /* @__PURE__ */ new BlendMode(MaterialBlending); 17433function getTextureIndex(textures, name) { 17434 for (let i = 0; i < textures.length; i++) { 17435 if (textures[i].name === name) { 17436 return i; 17437 } 17438 } 17439 return -1; 17440} 17441var MRTNode = class extends OutputStructNode { 17442 static get type() { 17443 return "MRTNode"; 17444 } 17445 /** 17446 * Constructs a new output struct node. 17447 * 17448 * @param {Object<string, Node>} outputNodes - The MRT outputs. 17449 */ 17450 constructor(outputNodes) { 17451 super(); 17452 this.outputNodes = outputNodes; 17453 this.blendModes = { 17454 output: _materialBlending 17455 }; 17456 this.isMRTNode = true; 17457 } 17458 /** 17459 * Sets the blend mode for the given output name. 17460 * 17461 * @param {string} name - The name of the output. 17462 * @param {BlendMode} blend - The blending mode. 17463 * @return {MRTNode} The current MRT node. 17464 */ 17465 setBlendMode(name, blend) { 17466 this.blendModes[name] = blend; 17467 return this; 17468 } 17469 /** 17470 * Returns the blend mode for the given output name. 17471 * 17472 * @param {string} name - The name of the output. 17473 * @return {BlendMode} The blend mode. 17474 */ 17475 getBlendMode(name) { 17476 return this.blendModes[name] || _noBlending; 17477 } 17478 /** 17479 * Returns `true` if the MRT node has an output with the given name. 17480 * 17481 * @param {string} name - The name of the output. 17482 * @return {NodeBuilder} Whether the MRT node has an output for the given name or not. 17483 */ 17484 has(name) { 17485 return this.outputNodes[name] !== void 0; 17486 } 17487 /** 17488 * Returns the output node for the given name. 17489 * 17490 * @param {string} name - The name of the output. 17491 * @return {Node} The output node. 17492 */ 17493 get(name) { 17494 return this.outputNodes[name]; 17495 } 17496 /** 17497 * Merges the outputs of the given MRT node with the outputs of this node. 17498 * 17499 * @param {MRTNode} mrtNode - The MRT to merge. 17500 * @return {MRTNode} A new MRT node with merged outputs.. 17501 */ 17502 merge(mrtNode) { 17503 const outputs = { ...this.outputNodes, ...mrtNode.outputNodes }; 17504 const blendings = { ...this.blendModes, ...mrtNode.blendModes }; 17505 const mrtTarget = mrt(outputs); 17506 mrtTarget.blendings = blendings; 17507 return mrtTarget; 17508 } 17509 setup(builder) { 17510 const outputNodes = this.outputNodes; 17511 const mrt3 = builder.renderer.getRenderTarget(); 17512 const members = []; 17513 const textures = mrt3.textures; 17514 for (const name in outputNodes) { 17515 const index = getTextureIndex(textures, name); 17516 members[index] = vec4(outputNodes[name]); 17517 } 17518 this.members = members; 17519 return super.setup(builder); 17520 } 17521}; 17522var mrt = /* @__PURE__ */ nodeProxy(MRTNode); 17523var BitcastNode = class extends TempNode { 17524 static get type() { 17525 return "BitcastNode"; 17526 } 17527 /** 17528 * Constructs a new bitcast node. 17529 * 17530 * @param {Node} valueNode - The value to convert. 17531 * @param {string} conversionType - The type to convert to. 17532 * @param {?string} [inputType = null] - The expected input data type of the bitcast operation. 17533 */ 17534 constructor(valueNode, conversionType, inputType = null) { 17535 super(); 17536 this.valueNode = valueNode; 17537 this.conversionType = conversionType; 17538 this.inputType = inputType; 17539 this.isBitcastNode = true; 17540 } 17541 generateNodeType(builder) { 17542 if (this.inputType !== null) { 17543 const valueType = this.valueNode.getNodeType(builder); 17544 const valueLength = builder.getTypeLength(valueType); 17545 return builder.getTypeFromLength(valueLength, this.conversionType); 17546 } 17547 return this.conversionType; 17548 } 17549 generate(builder) { 17550 const type = this.getNodeType(builder); 17551 let inputType = ""; 17552 if (this.inputType !== null) { 17553 const valueType = this.valueNode.getNodeType(builder); 17554 const valueTypeLength = builder.getTypeLength(valueType); 17555 inputType = valueTypeLength === 1 ? this.inputType : builder.changeComponentType(valueType, this.inputType); 17556 } else { 17557 inputType = this.valueNode.getNodeType(builder); 17558 } 17559 return `${builder.getBitcastMethod(type, inputType)}( ${this.valueNode.build(builder, inputType)} )`; 17560 } 17561}; 17562var bitcast = /* @__PURE__ */ nodeProxyIntent(BitcastNode).setParameterLength(2); 17563var floatBitsToInt = (value) => new BitcastNode(value, "int", "float"); 17564var floatBitsToUint = (value) => new BitcastNode(value, "uint", "float"); 17565var intBitsToFloat = (value) => new BitcastNode(value, "float", "int"); 17566var uintBitsToFloat = (value) => new BitcastNode(value, "float", "uint"); 17567var registeredBitcountFunctions = {}; 17568var BitcountNode = class _BitcountNode extends MathNode { 17569 static get type() { 17570 return "BitcountNode"; 17571 } 17572 /** 17573 * Constructs a new math node. 17574 * 17575 * @param {'countTrailingZeros'|'countLeadingZeros'|'countOneBits'} method - The method name. 17576 * @param {Node} aNode - The first input. 17577 */ 17578 constructor(method, aNode) { 17579 super(method, aNode); 17580 this.isBitcountNode = true; 17581 } 17582 /** 17583 * Casts the input value of the function to an integer if necessary. 17584 * 17585 * @private 17586 * @param {Node<uint>|Node<int>} inputNode - The input value. 17587 * @param {Node<uint>} outputNode - The output value. 17588 * @param {string} elementType - The type of the input value. 17589 */ 17590 _resolveElementType(inputNode, outputNode, elementType) { 17591 if (elementType === "int") { 17592 outputNode.assign(bitcast(inputNode, "uint")); 17593 } else { 17594 outputNode.assign(inputNode); 17595 } 17596 } 17597 _returnDataNode(inputType) { 17598 switch (inputType) { 17599 case "uint": { 17600 return uint; 17601 } 17602 case "int": { 17603 return int; 17604 } 17605 case "uvec2": { 17606 return uvec2; 17607 } 17608 case "uvec3": { 17609 return uvec3; 17610 } 17611 case "uvec4": { 17612 return uvec4; 17613 } 17614 case "ivec2": { 17615 return ivec2; 17616 } 17617 case "ivec3": { 17618 return ivec3; 17619 } 17620 case "ivec4": { 17621 return ivec4; 17622 } 17623 } 17624 } 17625 /** 17626 * Creates and registers a reusable GLSL function that emulates the behavior of countTrailingZeros. 17627 * 17628 * @private 17629 * @param {string} method - The name of the function to create. 17630 * @param {string} elementType - The type of the input value. 17631 * @returns {Function} - The generated function 17632 */ 17633 _createTrailingZerosBaseLayout(method, elementType) { 17634 const outputConvertNode = this._returnDataNode(elementType); 17635 const fnDef = Fn(([value]) => { 17636 const v = uint(0); 17637 this._resolveElementType(value, v, elementType); 17638 const f = float(v.bitAnd(negate(v))); 17639 const uintBits = floatBitsToUint(f); 17640 const numTrailingZeros = uintBits.shiftRight(23).sub(127); 17641 return outputConvertNode(numTrailingZeros); 17642 }).setLayout({ 17643 name: method, 17644 type: elementType, 17645 inputs: [ 17646 { name: "value", type: elementType } 17647 ] 17648 }); 17649 return fnDef; 17650 } 17651 /** 17652 * Creates and registers a reusable GLSL function that emulates the behavior of countLeadingZeros. 17653 * 17654 * @private 17655 * @param {string} method - The name of the function to create. 17656 * @param {string} elementType - The type of the input value. 17657 * @returns {Function} - The generated function 17658 */ 17659 _createLeadingZerosBaseLayout(method, elementType) { 17660 const outputConvertNode = this._returnDataNode(elementType); 17661 const fnDef = Fn(([value]) => { 17662 If(value.equal(uint(0)), () => { 17663 return uint(32); 17664 }); 17665 const v = uint(0); 17666 const n = uint(0); 17667 this._resolveElementType(value, v, elementType); 17668 If(v.shiftRight(16).equal(0), () => { 17669 n.addAssign(16); 17670 v.shiftLeftAssign(16); 17671 }); 17672 If(v.shiftRight(24).equal(0), () => { 17673 n.addAssign(8); 17674 v.shiftLeftAssign(8); 17675 }); 17676 If(v.shiftRight(28).equal(0), () => { 17677 n.addAssign(4); 17678 v.shiftLeftAssign(4); 17679 }); 17680 If(v.shiftRight(30).equal(0), () => { 17681 n.addAssign(2); 17682 v.shiftLeftAssign(2); 17683 }); 17684 If(v.shiftRight(31).equal(0), () => { 17685 n.addAssign(1); 17686 }); 17687 return outputConvertNode(n); 17688 }).setLayout({ 17689 name: method, 17690 type: elementType, 17691 inputs: [ 17692 { name: "value", type: elementType } 17693 ] 17694 }); 17695 return fnDef; 17696 } 17697 /** 17698 * Creates and registers a reusable GLSL function that emulates the behavior of countOneBits. 17699 * 17700 * @private 17701 * @param {string} method - The name of the function to create. 17702 * @param {string} elementType - The type of the input value. 17703 * @returns {Function} - The generated function 17704 */ 17705 _createOneBitsBaseLayout(method, elementType) { 17706 const outputConvertNode = this._returnDataNode(elementType); 17707 const fnDef = Fn(([value]) => { 17708 const v = uint(0); 17709 this._resolveElementType(value, v, elementType); 17710 v.assign(v.sub(v.shiftRight(uint(1)).bitAnd(uint(1431655765)))); 17711 v.assign(v.bitAnd(uint(858993459)).add(v.shiftRight(uint(2)).bitAnd(uint(858993459)))); 17712 const numBits = v.add(v.shiftRight(uint(4))).bitAnd(uint(252645135)).mul(uint(16843009)).shiftRight(uint(24)); 17713 return outputConvertNode(numBits); 17714 }).setLayout({ 17715 name: method, 17716 type: elementType, 17717 inputs: [ 17718 { name: "value", type: elementType } 17719 ] 17720 }); 17721 return fnDef; 17722 } 17723 /** 17724 * Creates and registers a reusable GLSL function that emulates the behavior of the specified bitcount function. 17725 * including considerations for component-wise bitcounts on vector type inputs. 17726 * 17727 * @private 17728 * @param {string} method - The name of the function to create. 17729 * @param {string} inputType - The type of the input value. 17730 * @param {number} typeLength - The vec length of the input value. 17731 * @param {Function} baseFn - The base function that operates on an individual component of the vector. 17732 * @returns {Function} - The alias function for the specified bitcount method. 17733 */ 17734 _createMainLayout(method, inputType, typeLength, baseFn) { 17735 const outputConvertNode = this._returnDataNode(inputType); 17736 const fnDef = Fn(([value]) => { 17737 if (typeLength === 1) { 17738 return outputConvertNode(baseFn(value)); 17739 } else { 17740 const vec = outputConvertNode(0); 17741 const components = ["x", "y", "z", "w"]; 17742 for (let i = 0; i < typeLength; i++) { 17743 const component = components[i]; 17744 vec[component].assign(baseFn(value[component])); 17745 } 17746 return vec; 17747 } 17748 }).setLayout({ 17749 name: method, 17750 type: inputType, 17751 inputs: [ 17752 { name: "value", type: inputType } 17753 ] 17754 }); 17755 return fnDef; 17756 } 17757 setup(builder) { 17758 const { method, aNode } = this; 17759 const { renderer } = builder; 17760 if (renderer.backend.isWebGPUBackend) { 17761 return super.setup(builder); 17762 } 17763 const inputType = this.getInputType(builder); 17764 const elementType = builder.getElementType(inputType); 17765 const typeLength = builder.getTypeLength(inputType); 17766 const baseMethod = `${method}_base_${elementType}`; 17767 const newMethod = `${method}_${inputType}`; 17768 let baseFn = registeredBitcountFunctions[baseMethod]; 17769 if (baseFn === void 0) { 17770 switch (method) { 17771 case _BitcountNode.COUNT_LEADING_ZEROS: { 17772 baseFn = this._createLeadingZerosBaseLayout(baseMethod, elementType); 17773 break; 17774 } 17775 case _BitcountNode.COUNT_TRAILING_ZEROS: { 17776 baseFn = this._createTrailingZerosBaseLayout(baseMethod, elementType); 17777 break; 17778 } 17779 case _BitcountNode.COUNT_ONE_BITS: { 17780 baseFn = this._createOneBitsBaseLayout(baseMethod, elementType); 17781 break; 17782 } 17783 } 17784 registeredBitcountFunctions[baseMethod] = baseFn; 17785 } 17786 let fn = registeredBitcountFunctions[newMethod]; 17787 if (fn === void 0) { 17788 fn = this._createMainLayout(newMethod, inputType, typeLength, baseFn); 17789 registeredBitcountFunctions[newMethod] = fn; 17790 } 17791 const output3 = Fn(() => { 17792 return fn( 17793 aNode 17794 ); 17795 }); 17796 return output3(); 17797 } 17798}; 17799BitcountNode.COUNT_TRAILING_ZEROS = "countTrailingZeros"; 17800BitcountNode.COUNT_LEADING_ZEROS = "countLeadingZeros"; 17801BitcountNode.COUNT_ONE_BITS = "countOneBits"; 17802var countTrailingZeros = /* @__PURE__ */ nodeProxyIntent(BitcountNode, BitcountNode.COUNT_TRAILING_ZEROS).setParameterLength(1); 17803var countLeadingZeros = /* @__PURE__ */ nodeProxyIntent(BitcountNode, BitcountNode.COUNT_LEADING_ZEROS).setParameterLength(1); 17804var countOneBits = /* @__PURE__ */ nodeProxyIntent(BitcountNode, BitcountNode.COUNT_ONE_BITS).setParameterLength(1); 17805var hash = /* @__PURE__ */ Fn(([seed]) => { 17806 const state = seed.toUint().mul(747796405).add(2891336453); 17807 const word = state.shiftRight(state.shiftRight(28).add(4)).bitXor(state).mul(277803737); 17808 const result = word.shiftRight(22).bitXor(word); 17809 return result.toFloat().mul(1 / 2 ** 32); 17810}); 17811var parabola = (x, k) => pow(mul(4, x.mul(sub(1, x))), k); 17812var gain = (x, k) => x.lessThan(0.5) ? parabola(x.mul(2), k).div(2) : sub(1, parabola(mul(sub(1, x), 2), k).div(2)); 17813var pcurve = (x, a, b) => pow(div(pow(x, a), add(pow(x, a), pow(sub(1, x), b))), 1 / a); 17814var sinc = (x, k) => sin(PI.mul(k.mul(x).sub(1))).div(PI.mul(k.mul(x).sub(1))); 17815var PackFloatNode = class extends TempNode { 17816 static get type() { 17817 return "PackFloatNode"; 17818 } 17819 /** 17820 * 17821 * @param {'snorm' | 'unorm' | 'float16'} encoding - The numeric encoding that describes how the float values are mapped to the integer range. 17822 * @param {Node} vectorNode - The vector node to be packed 17823 */ 17824 constructor(encoding, vectorNode) { 17825 super(); 17826 this.vectorNode = vectorNode; 17827 this.encoding = encoding; 17828 this.isPackFloatNode = true; 17829 } 17830 generateNodeType() { 17831 return "uint"; 17832 } 17833 generate(builder) { 17834 const inputType = this.vectorNode.getNodeType(builder); 17835 return `${builder.getFloatPackingMethod(this.encoding)}(${this.vectorNode.build(builder, inputType)})`; 17836 } 17837}; 17838var packSnorm2x16 = /* @__PURE__ */ nodeProxyIntent(PackFloatNode, "snorm").setParameterLength(1); 17839var packUnorm2x16 = /* @__PURE__ */ nodeProxyIntent(PackFloatNode, "unorm").setParameterLength(1); 17840var packHalf2x16 = /* @__PURE__ */ nodeProxyIntent(PackFloatNode, "float16").setParameterLength(1); 17841var UnpackFloatNode = class extends TempNode { 17842 static get type() { 17843 return "UnpackFloatNode"; 17844 } 17845 /** 17846 * 17847 * @param {'snorm' | 'unorm' | 'float16'} encoding - The numeric encoding that describes how the integer values are mapped to the float range 17848 * @param {Node} uintNode - The uint node to be unpacked 17849 */ 17850 constructor(encoding, uintNode) { 17851 super(); 17852 this.uintNode = uintNode; 17853 this.encoding = encoding; 17854 this.isUnpackFloatNode = true; 17855 } 17856 generateNodeType() { 17857 return "vec2"; 17858 } 17859 generate(builder) { 17860 const inputType = this.uintNode.getNodeType(builder); 17861 return `${builder.getFloatUnpackingMethod(this.encoding)}(${this.uintNode.build(builder, inputType)})`; 17862 } 17863}; 17864var unpackSnorm2x16 = /* @__PURE__ */ nodeProxyIntent(UnpackFloatNode, "snorm").setParameterLength(1); 17865var unpackUnorm2x16 = /* @__PURE__ */ nodeProxyIntent(UnpackFloatNode, "unorm").setParameterLength(1); 17866var unpackHalf2x16 = /* @__PURE__ */ nodeProxyIntent(UnpackFloatNode, "float16").setParameterLength(1); 17867var tri = /* @__PURE__ */ Fn(([x]) => { 17868 return x.fract().sub(0.5).abs(); 17869}).setLayout({ 17870 name: "tri", 17871 type: "float", 17872 inputs: [ 17873 { name: "x", type: "float" } 17874 ] 17875}); 17876var tri3 = /* @__PURE__ */ Fn(([p]) => { 17877 return vec3(tri(p.z.add(tri(p.y.mul(1)))), tri(p.z.add(tri(p.x.mul(1)))), tri(p.y.add(tri(p.x.mul(1))))); 17878}).setLayout({ 17879 name: "tri3", 17880 type: "vec3", 17881 inputs: [ 17882 { name: "p", type: "vec3" } 17883 ] 17884}); 17885var triNoise3D = /* @__PURE__ */ Fn(([position, speed, time3]) => { 17886 const p = vec3(position).toVar(); 17887 const z = float(1.4).toVar(); 17888 const rz = float(0).toVar(); 17889 const bp = vec3(p).toVar(); 17890 Loop({ start: float(0), end: float(3), type: "float", condition: "<=" }, () => { 17891 const dg = vec3(tri3(bp.mul(2))).toVar(); 17892 p.addAssign(dg.add(time3.mul(float(0.1).mul(speed)))); 17893 bp.mulAssign(1.8); 17894 z.mulAssign(1.5); 17895 p.mulAssign(1.2); 17896 const t = float(tri(p.z.add(tri(p.x.add(tri(p.y)))))).toVar(); 17897 rz.addAssign(t.div(z)); 17898 bp.addAssign(0.14); 17899 }); 17900 return rz; 17901}).setLayout({ 17902 name: "triNoise3D", 17903 type: "float", 17904 inputs: [ 17905 { name: "position", type: "vec3" }, 17906 { name: "speed", type: "float" }, 17907 { name: "time", type: "float" } 17908 ] 17909}); 17910var FunctionOverloadingNode = class extends Node2 { 17911 static get type() { 17912 return "FunctionOverloadingNode"; 17913 } 17914 /** 17915 * Constructs a new function overloading node. 17916 * 17917 * @param {Array<Function>} functionNodes - Array of `Fn` function definitions. 17918 * @param {...Node} parametersNodes - A list of parameter nodes. 17919 */ 17920 constructor(functionNodes = [], ...parametersNodes) { 17921 super(); 17922 this.functionNodes = functionNodes; 17923 this.parametersNodes = parametersNodes; 17924 this._candidateFn = null; 17925 this.global = true; 17926 } 17927 /** 17928 * This method is overwritten since the node type is inferred from 17929 * the function's return type. 17930 * 17931 * @param {NodeBuilder} builder - The current node builder. 17932 * @return {string} The node type. 17933 */ 17934 generateNodeType(builder) { 17935 const candidateFn = this.getCandidateFn(builder); 17936 return candidateFn.shaderNode.layout.type; 17937 } 17938 /** 17939 * Returns the candidate function for the current parameters. 17940 * 17941 * @param {NodeBuilder} builder - The current node builder. 17942 * @return {FunctionNode} The candidate function. 17943 */ 17944 getCandidateFn(builder) { 17945 const params = this.parametersNodes; 17946 let candidateFn = this._candidateFn; 17947 if (candidateFn === null) { 17948 let bestCandidateFn = null; 17949 let bestScore = -1; 17950 for (const functionNode of this.functionNodes) { 17951 const shaderNode = functionNode.shaderNode; 17952 const layout = shaderNode.layout; 17953 if (layout === null) { 17954 throw new Error("FunctionOverloadingNode: FunctionNode must be a layout."); 17955 } 17956 const inputs = layout.inputs; 17957 if (params.length === inputs.length) { 17958 let currentScore = 0; 17959 for (let i = 0; i < params.length; i++) { 17960 const param = params[i]; 17961 const input = inputs[i]; 17962 if (param.getNodeType(builder) === input.type) { 17963 currentScore++; 17964 } 17965 } 17966 if (currentScore > bestScore) { 17967 bestCandidateFn = functionNode; 17968 bestScore = currentScore; 17969 } 17970 } 17971 } 17972 this._candidateFn = candidateFn = bestCandidateFn; 17973 } 17974 return candidateFn; 17975 } 17976 /** 17977 * Sets up the node for the current parameters. 17978 * 17979 * @param {NodeBuilder} builder - The current node builder. 17980 * @return {Node} The setup node. 17981 */ 17982 setup(builder) { 17983 const candidateFn = this.getCandidateFn(builder); 17984 return candidateFn(...this.parametersNodes); 17985 } 17986}; 17987var overloadingBaseFn = /* @__PURE__ */ nodeProxy(FunctionOverloadingNode); 17988var overloadingFn = (functionNodes) => (...params) => overloadingBaseFn(functionNodes, ...params); 17989var time = /* @__PURE__ */ uniform(0).setGroup(renderGroup).onRenderUpdate((frame) => frame.time); 17990var deltaTime = /* @__PURE__ */ uniform(0).setGroup(renderGroup).onRenderUpdate((frame) => frame.deltaTime); 17991var frameId = /* @__PURE__ */ uniform(0, "uint").setGroup(renderGroup).onRenderUpdate((frame) => frame.frameId); 17992var oscSine = (t = time) => t.add(0.75).mul(Math.PI * 2).sin().mul(0.5).add(0.5); 17993var oscSquare = (t = time) => t.fract().round(); 17994var oscTriangle = (t = time) => t.add(0.5).fract().mul(2).sub(1).abs(); 17995var oscSawtooth = (t = time) => t.fract(); 17996function replaceDefaultUV(callback, node = null) { 17997 const getUV2 = typeof callback === "function" ? callback : () => callback; 17998 return context(node, { getUV: getUV2 }); 17999} 18000var rotateUV = /* @__PURE__ */ Fn(([uv3, rotation, center = vec2(0.5)]) => { 18001 return rotate(uv3.sub(center), rotation).add(center); 18002}); 18003var spherizeUV = /* @__PURE__ */ Fn(([uv3, strength, center = vec2(0.5)]) => { 18004 const delta = uv3.sub(center); 18005 const delta2 = delta.dot(delta); 18006 const delta4 = delta2.mul(delta2); 18007 const deltaOffset = delta4.mul(strength); 18008 return uv3.add(delta.mul(deltaOffset)); 18009}); 18010var billboarding = /* @__PURE__ */ Fn(({ position = null, horizontal = true, vertical = false }) => { 18011 let worldMatrix; 18012 if (position !== null) { 18013 worldMatrix = modelWorldMatrix.toVar(); 18014 worldMatrix[3][0] = position.x; 18015 worldMatrix[3][1] = position.y; 18016 worldMatrix[3][2] = position.z; 18017 } else { 18018 worldMatrix = modelWorldMatrix; 18019 } 18020 const modelViewMatrix3 = cameraViewMatrix.mul(worldMatrix); 18021 if (defined(horizontal)) { 18022 modelViewMatrix3[0][0] = modelWorldMatrix[0].length(); 18023 modelViewMatrix3[0][1] = 0; 18024 modelViewMatrix3[0][2] = 0; 18025 } 18026 if (defined(vertical)) { 18027 modelViewMatrix3[1][0] = 0; 18028 modelViewMatrix3[1][1] = modelWorldMatrix[1].length(); 18029 modelViewMatrix3[1][2] = 0; 18030 } 18031 modelViewMatrix3[2][0] = 0; 18032 modelViewMatrix3[2][1] = 0; 18033 modelViewMatrix3[2][2] = 1; 18034 return cameraProjectionMatrix.mul(modelViewMatrix3).mul(positionLocal); 18035}); 18036var viewportSafeUV = /* @__PURE__ */ Fn(([uv3 = null]) => { 18037 const depth3 = linearDepth(); 18038 const depthDiff = linearDepth(viewportDepthTexture(uv3)).sub(depth3); 18039 const finalUV = depthDiff.lessThan(0).select(screenUV, uv3); 18040 return finalUV; 18041}); 18042var spritesheetUV = /* @__PURE__ */ Fn(([countNode, uvNode = uv$1(), frameNode = float(0)]) => { 18043 const width = countNode.x; 18044 const height = countNode.y; 18045 const frameNum = frameNode.mod(width.mul(height)).floor(); 18046 const column = frameNum.mod(width); 18047 const row = height.sub(frameNum.add(1).div(width).ceil()); 18048 const scale2 = countNode.reciprocal(); 18049 const uvFrameOffset = vec2(column, row); 18050 return uvNode.add(uvFrameOffset).mul(scale2); 18051}); 18052var triplanarTextures = /* @__PURE__ */ Fn(([textureXNode, textureYNode = null, textureZNode = null, scaleNode = float(1), positionNode = positionLocal, normalNode = normalLocal]) => { 18053 let bf = normalNode.abs().normalize(); 18054 bf = bf.div(bf.dot(vec3(1))); 18055 const tx = positionNode.yz.mul(scaleNode); 18056 const ty = positionNode.zx.mul(scaleNode); 18057 const tz = positionNode.xy.mul(scaleNode); 18058 const textureX = textureXNode.value; 18059 const textureY = textureYNode !== null ? textureYNode.value : textureX; 18060 const textureZ = textureZNode !== null ? textureZNode.value : textureX; 18061 const cx = texture(textureX, tx).mul(bf.x); 18062 const cy = texture(textureY, ty).mul(bf.y); 18063 const cz = texture(textureZ, tz).mul(bf.z); 18064 return add(cx, cy, cz); 18065}); 18066var triplanarTexture = (...params) => triplanarTextures(...params); 18067var _reflectorPlane = new Plane(); 18068var _normal = new Vector3(); 18069var _reflectorWorldPosition = new Vector3(); 18070var _cameraWorldPosition = new Vector3(); 18071var _rotationMatrix = new Matrix4(); 18072var _lookAtPosition = new Vector3(0, 0, -1); 18073var clipPlane = new Vector4(); 18074var _view = new Vector3(); 18075var _target = new Vector3(); 18076var _q = new Vector4(); 18077var _size$2 = new Vector2(); 18078var _defaultRT = new RenderTarget(); 18079var _defaultUV = screenUV.flipX(); 18080_defaultRT.depthTexture = new DepthTexture(1, 1); 18081var _inReflector = false; 18082var ReflectorNode = class _ReflectorNode extends TextureNode { 18083 static get type() { 18084 return "ReflectorNode"; 18085 } 18086 /** 18087 * Constructs a new reflector node. 18088 * 18089 * @param {Object} [parameters={}] - An object holding configuration parameters. 18090 * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to. 18091 * @param {number} [parameters.resolutionScale=1] - The resolution scale. 18092 * @param {boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. 18093 * @param {boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. 18094 * @param {boolean} [parameters.depth=false] - Whether depth data should be generated or not. 18095 * @param {number} [parameters.samples] - Anti-Aliasing samples of the internal render-target. 18096 * @param {TextureNode} [parameters.defaultTexture] - The default texture node. 18097 * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. 18098 */ 18099 constructor(parameters = {}) { 18100 super(parameters.defaultTexture || _defaultRT.texture, _defaultUV); 18101 this._reflectorBaseNode = parameters.reflector || new ReflectorBaseNode(this, parameters); 18102 this._depthNode = null; 18103 this.setUpdateMatrix(false); 18104 } 18105 /** 18106 * A reference to the internal reflector node. 18107 * 18108 * @type {ReflectorBaseNode} 18109 */ 18110 get reflector() { 18111 return this._reflectorBaseNode; 18112 } 18113 /** 18114 * A reference to 3D object the reflector is linked to. 18115 * 18116 * @type {Object3D} 18117 */ 18118 get target() { 18119 return this._reflectorBaseNode.target; 18120 } 18121 /** 18122 * Returns a node representing the mirror's depth. That can be used 18123 * to implement more advanced reflection effects like distance attenuation. 18124 * 18125 * @return {Node} The depth node. 18126 */ 18127 getDepthNode() { 18128 if (this._depthNode === null) { 18129 if (this._reflectorBaseNode.depth !== true) { 18130 throw new Error("THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. "); 18131 } 18132 this._depthNode = new _ReflectorNode({ 18133 defaultTexture: _defaultRT.depthTexture, 18134 reflector: this._reflectorBaseNode 18135 }); 18136 } 18137 return this._depthNode; 18138 } 18139 setup(builder) { 18140 if (!builder.object.isQuadMesh) this._reflectorBaseNode.build(builder); 18141 return super.setup(builder); 18142 } 18143 clone() { 18144 const newNode = new this.constructor(this.reflectorNode); 18145 newNode.uvNode = this.uvNode; 18146 newNode.levelNode = this.levelNode; 18147 newNode.biasNode = this.biasNode; 18148 newNode.sampler = this.sampler; 18149 newNode.depthNode = this.depthNode; 18150 newNode.compareNode = this.compareNode; 18151 newNode.gradNode = this.gradNode; 18152 newNode.offsetNode = this.offsetNode; 18153 newNode._reflectorBaseNode = this._reflectorBaseNode; 18154 return newNode; 18155 } 18156 /** 18157 * Frees internal resources. Should be called when the node is no longer in use. 18158 */ 18159 dispose() { 18160 super.dispose(); 18161 this._reflectorBaseNode.dispose(); 18162 } 18163}; 18164var ReflectorBaseNode = class extends Node2 { 18165 static get type() { 18166 return "ReflectorBaseNode"; 18167 } 18168 /** 18169 * Constructs a new reflector base node. 18170 * 18171 * @param {TextureNode} textureNode - Represents the rendered reflections as a texture node. 18172 * @param {Object} [parameters={}] - An object holding configuration parameters. 18173 * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to. 18174 * @param {number} [parameters.resolutionScale=1] - The resolution scale. 18175 * @param {boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. 18176 * @param {boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. 18177 * @param {boolean} [parameters.depth=false] - Whether depth data should be generated or not. 18178 * @param {number} [parameters.samples] - Anti-Aliasing samples of the internal render-target. 18179 */ 18180 constructor(textureNode, parameters = {}) { 18181 super(); 18182 const { 18183 target = new Object3D(), 18184 resolutionScale = 1, 18185 generateMipmaps = false, 18186 bounces = true, 18187 depth: depth3 = false, 18188 samples = 0 18189 } = parameters; 18190 this.textureNode = textureNode; 18191 this.target = target; 18192 this.resolutionScale = resolutionScale; 18193 if (parameters.resolution !== void 0) { 18194 warnOnce('ReflectorNode: The "resolution" parameter has been renamed to "resolutionScale".'); 18195 this.resolutionScale = parameters.resolution; 18196 } 18197 this.generateMipmaps = generateMipmaps; 18198 this.bounces = bounces; 18199 this.depth = depth3; 18200 this.samples = samples; 18201 this.updateBeforeType = bounces ? NodeUpdateType.RENDER : NodeUpdateType.FRAME; 18202 this.virtualCameras = /* @__PURE__ */ new WeakMap(); 18203 this.renderTargets = /* @__PURE__ */ new Map(); 18204 this.forceUpdate = false; 18205 this.hasOutput = false; 18206 } 18207 /** 18208 * Updates the resolution of the internal render target. 18209 * 18210 * @private 18211 * @param {RenderTarget} renderTarget - The render target to resize. 18212 * @param {Renderer} renderer - The renderer that is used to determine the new size. 18213 */ 18214 _updateResolution(renderTarget, renderer) { 18215 const resolution = this.resolutionScale; 18216 renderer.getDrawingBufferSize(_size$2); 18217 renderTarget.setSize(Math.round(_size$2.width * resolution), Math.round(_size$2.height * resolution)); 18218 } 18219 setup(builder) { 18220 this._updateResolution(_defaultRT, builder.renderer); 18221 return super.setup(builder); 18222 } 18223 /** 18224 * Frees internal resources. Should be called when the node is no longer in use. 18225 */ 18226 dispose() { 18227 super.dispose(); 18228 for (const renderTarget of this.renderTargets.values()) { 18229 renderTarget.dispose(); 18230 } 18231 } 18232 /** 18233 * Returns a virtual camera for the given camera. The virtual camera is used to 18234 * render the scene from the reflector's view so correct reflections can be produced. 18235 * 18236 * @param {Camera} camera - The scene's camera. 18237 * @return {Camera} The corresponding virtual camera. 18238 */ 18239 getVirtualCamera(camera) { 18240 let virtualCamera = this.virtualCameras.get(camera); 18241 if (virtualCamera === void 0) { 18242 virtualCamera = camera.clone(); 18243 this.virtualCameras.set(camera, virtualCamera); 18244 } 18245 return virtualCamera; 18246 } 18247 /** 18248 * Returns a render target for the given camera. The reflections are rendered 18249 * into this render target. 18250 * 18251 * @param {Camera} camera - The scene's camera. 18252 * @return {RenderTarget} The render target. 18253 */ 18254 getRenderTarget(camera) { 18255 let renderTarget = this.renderTargets.get(camera); 18256 if (renderTarget === void 0) { 18257 renderTarget = new RenderTarget(0, 0, { type: HalfFloatType, samples: this.samples }); 18258 if (this.generateMipmaps === true) { 18259 renderTarget.texture.minFilter = LinearMipMapLinearFilter; 18260 renderTarget.texture.generateMipmaps = true; 18261 } 18262 if (this.depth === true) { 18263 renderTarget.depthTexture = new DepthTexture(); 18264 } 18265 this.renderTargets.set(camera, renderTarget); 18266 } 18267 return renderTarget; 18268 } 18269 updateBefore(frame) { 18270 if (this.bounces === false && _inReflector) return false; 18271 _inReflector = true; 18272 const { scene, camera, renderer, material } = frame; 18273 const { target } = this; 18274 const virtualCamera = this.getVirtualCamera(camera); 18275 const renderTarget = this.getRenderTarget(virtualCamera); 18276 renderer.getDrawingBufferSize(_size$2); 18277 this._updateResolution(renderTarget, renderer); 18278 _reflectorWorldPosition.setFromMatrixPosition(target.matrixWorld); 18279 _cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld); 18280 _rotationMatrix.extractRotation(target.matrixWorld); 18281 _normal.set(0, 0, 1); 18282 _normal.applyMatrix4(_rotationMatrix); 18283 _view.subVectors(_reflectorWorldPosition, _cameraWorldPosition); 18284 const isFacingAway = _view.dot(_normal) > 0; 18285 let needsClear = false; 18286 if (isFacingAway === true && this.forceUpdate === false) { 18287 if (this.hasOutput === false) { 18288 _inReflector = false; 18289 return; 18290 } 18291 needsClear = true; 18292 } 18293 _view.reflect(_normal).negate(); 18294 _view.add(_reflectorWorldPosition); 18295 _rotationMatrix.extractRotation(camera.matrixWorld); 18296 _lookAtPosition.set(0, 0, -1); 18297 _lookAtPosition.applyMatrix4(_rotationMatrix); 18298 _lookAtPosition.add(_cameraWorldPosition); 18299 _target.subVectors(_reflectorWorldPosition, _lookAtPosition); 18300 _target.reflect(_normal).negate(); 18301 _target.add(_reflectorWorldPosition); 18302 virtualCamera.coordinateSystem = camera.coordinateSystem; 18303 virtualCamera.position.copy(_view); 18304 virtualCamera.up.set(0, 1, 0); 18305 virtualCamera.up.applyMatrix4(_rotationMatrix); 18306 virtualCamera.up.reflect(_normal); 18307 virtualCamera.lookAt(_target); 18308 virtualCamera.near = camera.near; 18309 virtualCamera.far = camera.far; 18310 virtualCamera.updateMatrixWorld(); 18311 virtualCamera.projectionMatrix.copy(camera.projectionMatrix); 18312 _reflectorPlane.setFromNormalAndCoplanarPoint(_normal, _reflectorWorldPosition); 18313 _reflectorPlane.applyMatrix4(virtualCamera.matrixWorldInverse); 18314 clipPlane.set(_reflectorPlane.normal.x, _reflectorPlane.normal.y, _reflectorPlane.normal.z, _reflectorPlane.constant); 18315 const projectionMatrix = virtualCamera.projectionMatrix; 18316 _q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0]; 18317 _q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5]; 18318 _q.z = -1; 18319 _q.w = (1 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; 18320 clipPlane.multiplyScalar(1 / clipPlane.dot(_q)); 18321 const clipBias = 0; 18322 projectionMatrix.elements[2] = clipPlane.x; 18323 projectionMatrix.elements[6] = clipPlane.y; 18324 projectionMatrix.elements[10] = renderer.coordinateSystem === WebGPUCoordinateSystem ? clipPlane.z - clipBias : clipPlane.z + 1 - clipBias; 18325 projectionMatrix.elements[14] = clipPlane.w; 18326 this.textureNode.value = renderTarget.texture; 18327 if (this.depth === true) { 18328 this.textureNode.getDepthNode().value = renderTarget.depthTexture; 18329 } 18330 material.visible = false; 18331 const currentRenderTarget = renderer.getRenderTarget(); 18332 const currentMRT = renderer.getMRT(); 18333 const currentAutoClear = renderer.autoClear; 18334 renderer.setMRT(null); 18335 renderer.setRenderTarget(renderTarget); 18336 renderer.autoClear = true; 18337 const previousName = scene.name; 18338 scene.name = (scene.name || "Scene") + " [ Reflector ]"; 18339 if (needsClear) { 18340 renderer.clear(); 18341 this.hasOutput = false; 18342 } else { 18343 renderer.render(scene, virtualCamera); 18344 this.hasOutput = true; 18345 } 18346 scene.name = previousName; 18347 renderer.setMRT(currentMRT); 18348 renderer.setRenderTarget(currentRenderTarget); 18349 renderer.autoClear = currentAutoClear; 18350 material.visible = true; 18351 _inReflector = false; 18352 this.forceUpdate = false; 18353 } 18354 /** 18355 * The resolution scale. 18356 * 18357 * @deprecated 18358 * @type {number} 18359 * @default {1} 18360 */ 18361 get resolution() { 18362 warnOnce('ReflectorNode: The "resolution" property has been renamed to "resolutionScale".'); 18363 return this.resolutionScale; 18364 } 18365 set resolution(value) { 18366 warnOnce('ReflectorNode: The "resolution" property has been renamed to "resolutionScale".'); 18367 this.resolutionScale = value; 18368 } 18369}; 18370var reflector = (parameters) => new ReflectorNode(parameters); 18371var _camera = /* @__PURE__ */ new OrthographicCamera(-1, 1, 1, -1, 0, 1); 18372var QuadGeometry = class extends BufferGeometry { 18373 /** 18374 * Constructs a new quad geometry. 18375 * 18376 * @param {boolean} [flipY=false] - Whether the uv coordinates should be flipped along the vertical axis or not. 18377 */ 18378 constructor(flipY = false) { 18379 super(); 18380 const uv3 = flipY === false ? [0, -1, 0, 1, 2, 1] : [0, 2, 0, 0, 2, 0]; 18381 this.setAttribute("position", new Float32BufferAttribute([-1, 3, 0, -1, -1, 0, 3, -1, 0], 3)); 18382 this.setAttribute("uv", new Float32BufferAttribute(uv3, 2)); 18383 } 18384}; 18385var _geometry = /* @__PURE__ */ new QuadGeometry(); 18386var QuadMesh = class extends Mesh { 18387 /** 18388 * Constructs a new quad mesh. 18389 * 18390 * @param {?Material} [material=null] - The material to render the quad mesh with. 18391 */ 18392 constructor(material = null) { 18393 super(_geometry, material); 18394 this.camera = _camera; 18395 this.isQuadMesh = true; 18396 } 18397 /** 18398 * Async version of `render()`. 18399 * 18400 * @async 18401 * @deprecated 18402 * @param {Renderer} renderer - The renderer. 18403 * @return {Promise} A Promise that resolves when the render has been finished. 18404 */ 18405 async renderAsync(renderer) { 18406 warnOnce('QuadMesh: "renderAsync()" has been deprecated. Use "render()" and "await renderer.init();" when creating the renderer.'); 18407 await renderer.init(); 18408 renderer.render(this, _camera); 18409 } 18410 /** 18411 * Renders the quad mesh 18412 * 18413 * @param {Renderer} renderer - The renderer. 18414 */ 18415 render(renderer) { 18416 renderer.render(this, _camera); 18417 } 18418}; 18419var _size$1 = /* @__PURE__ */ new Vector2(); 18420var RTTNode = class extends TextureNode { 18421 static get type() { 18422 return "RTTNode"; 18423 } 18424 /** 18425 * Constructs a new RTT node. 18426 * 18427 * @param {Node} node - The node to render a texture with. 18428 * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. 18429 * @param {?number} [height=null] - The height of the internal render target. 18430 * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. 18431 */ 18432 constructor(node, width = null, height = null, options = { type: HalfFloatType }) { 18433 const renderTarget = new RenderTarget(width, height, options); 18434 super(renderTarget.texture, uv$1()); 18435 this.isRTTNode = true; 18436 this.node = node; 18437 this.width = width; 18438 this.height = height; 18439 this.pixelRatio = 1; 18440 this.renderTarget = renderTarget; 18441 this.textureNeedsUpdate = true; 18442 this.autoUpdate = true; 18443 this._rttNode = null; 18444 this._quadMesh = new QuadMesh(new NodeMaterial()); 18445 this.updateBeforeType = NodeUpdateType.RENDER; 18446 } 18447 /** 18448 * Whether the internal render target should automatically be resized or not. 18449 * 18450 * @type {boolean} 18451 * @readonly 18452 * @default true 18453 */ 18454 get autoResize() { 18455 return this.width === null; 18456 } 18457 setup(builder) { 18458 this._rttNode = this.node.context(builder.getSharedContext()); 18459 this._quadMesh.material.name = "RTT"; 18460 this._quadMesh.material.needsUpdate = true; 18461 return super.setup(builder); 18462 } 18463 /** 18464 * Sets the size of the internal render target 18465 * 18466 * @param {number} width - The width to set. 18467 * @param {number} height - The width to set. 18468 */ 18469 setSize(width, height) { 18470 this.width = width; 18471 this.height = height; 18472 const effectiveWidth = width * this.pixelRatio; 18473 const effectiveHeight = height * this.pixelRatio; 18474 this.renderTarget.setSize(effectiveWidth, effectiveHeight); 18475 this.textureNeedsUpdate = true; 18476 } 18477 /** 18478 * Sets the pixel ratio. This will also resize the render target. 18479 * 18480 * @param {number} pixelRatio - The pixel ratio to set. 18481 */ 18482 setPixelRatio(pixelRatio) { 18483 this.pixelRatio = pixelRatio; 18484 this.setSize(this.width, this.height); 18485 } 18486 updateBefore({ renderer }) { 18487 if (this.textureNeedsUpdate === false && this.autoUpdate === false) return; 18488 this.textureNeedsUpdate = false; 18489 if (this.autoResize === true) { 18490 const pixelRatio = renderer.getPixelRatio(); 18491 const size3 = renderer.getSize(_size$1); 18492 const effectiveWidth = Math.floor(size3.width * pixelRatio); 18493 const effectiveHeight = Math.floor(size3.height * pixelRatio); 18494 if (effectiveWidth !== this.renderTarget.width || effectiveHeight !== this.renderTarget.height) { 18495 this.renderTarget.setSize(effectiveWidth, effectiveHeight); 18496 this.textureNeedsUpdate = true; 18497 } 18498 } 18499 let name = "RTT"; 18500 if (this.node.name) { 18501 name = this.node.name + " [ " + name + " ]"; 18502 } 18503 this._quadMesh.material.fragmentNode = this._rttNode; 18504 this._quadMesh.name = name; 18505 const currentRenderTarget = renderer.getRenderTarget(); 18506 renderer.setRenderTarget(this.renderTarget); 18507 this._quadMesh.render(renderer); 18508 renderer.setRenderTarget(currentRenderTarget); 18509 } 18510 clone() { 18511 const newNode = new TextureNode(this.value, this.uvNode, this.levelNode); 18512 newNode.sampler = this.sampler; 18513 newNode.referenceNode = this; 18514 return newNode; 18515 } 18516}; 18517var rtt = (node, ...params) => new RTTNode(nodeObject(node), ...params); 18518var convertToTexture = (node, ...params) => { 18519 if (node.isSampleNode || node.isTextureNode) return node; 18520 if (node.isPassNode) return node.getTextureNode(); 18521 return rtt(node, ...params); 18522}; 18523var getViewPosition = /* @__PURE__ */ Fn(([screenPosition, depth3, projectionMatrixInverse], builder) => { 18524 let clipSpacePosition; 18525 if (builder.renderer.coordinateSystem === WebGPUCoordinateSystem) { 18526 screenPosition = vec2(screenPosition.x, screenPosition.y.oneMinus()).mul(2).sub(1); 18527 clipSpacePosition = vec4(vec3(screenPosition, depth3), 1); 18528 } else { 18529 clipSpacePosition = vec4(vec3(screenPosition.x, screenPosition.y.oneMinus(), depth3).mul(2).sub(1), 1); 18530 } 18531 const viewSpacePosition = vec4(projectionMatrixInverse.mul(clipSpacePosition)); 18532 return viewSpacePosition.xyz.div(viewSpacePosition.w); 18533}); 18534var getScreenPosition = /* @__PURE__ */ Fn(([viewPosition, projectionMatrix]) => { 18535 const sampleClipPos = projectionMatrix.mul(vec4(viewPosition, 1)); 18536 const sampleUv = sampleClipPos.xy.div(sampleClipPos.w).mul(0.5).add(0.5).toVar(); 18537 return vec2(sampleUv.x, sampleUv.y.oneMinus()); 18538}); 18539var getNormalFromDepth = /* @__PURE__ */ Fn(([uv3, depthTexture, projectionMatrixInverse]) => { 18540 const size3 = textureSize(textureLoad(depthTexture)); 18541 const p = ivec2(uv3.mul(size3)).toVar(); 18542 const c0 = textureLoad(depthTexture, p).toVar(); 18543 const l2 = textureLoad(depthTexture, p.sub(ivec2(2, 0))).toVar(); 18544 const l1 = textureLoad(depthTexture, p.sub(ivec2(1, 0))).toVar(); 18545 const r1 = textureLoad(depthTexture, p.add(ivec2(1, 0))).toVar(); 18546 const r2 = textureLoad(depthTexture, p.add(ivec2(2, 0))).toVar(); 18547 const b2 = textureLoad(depthTexture, p.add(ivec2(0, 2))).toVar(); 18548 const b1 = textureLoad(depthTexture, p.add(ivec2(0, 1))).toVar(); 18549 const t1 = textureLoad(depthTexture, p.sub(ivec2(0, 1))).toVar(); 18550 const t2 = textureLoad(depthTexture, p.sub(ivec2(0, 2))).toVar(); 18551 const dl = abs(sub(float(2).mul(l1).sub(l2), c0)).toVar(); 18552 const dr = abs(sub(float(2).mul(r1).sub(r2), c0)).toVar(); 18553 const db = abs(sub(float(2).mul(b1).sub(b2), c0)).toVar(); 18554 const dt = abs(sub(float(2).mul(t1).sub(t2), c0)).toVar(); 18555 const ce = getViewPosition(uv3, c0, projectionMatrixInverse).toVar(); 18556 const dpdx = dl.lessThan(dr).select(ce.sub(getViewPosition(uv3.sub(vec2(float(1).div(size3.x), 0)), l1, projectionMatrixInverse)), ce.negate().add(getViewPosition(uv3.add(vec2(float(1).div(size3.x), 0)), r1, projectionMatrixInverse))); 18557 const dpdy = db.lessThan(dt).select(ce.sub(getViewPosition(uv3.add(vec2(0, float(1).div(size3.y))), b1, projectionMatrixInverse)), ce.negate().add(getViewPosition(uv3.sub(vec2(0, float(1).div(size3.y))), t1, projectionMatrixInverse))); 18558 return normalize(cross(dpdx, dpdy)); 18559}); 18560var interleavedGradientNoise = Fn(([position]) => { 18561 return fract(float(52.9829189).mul(fract(dot(position, vec2(0.06711056, 583715e-8))))); 18562}).setLayout({ 18563 name: "interleavedGradientNoise", 18564 type: "float", 18565 inputs: [ 18566 { name: "position", type: "vec2" } 18567 ] 18568}); 18569var vogelDiskSample = Fn(([sampleIndex, samplesCount, phi]) => { 18570 const goldenAngle = float(2.399963229728653); 18571 const r = sqrt(float(sampleIndex).add(0.5).div(float(samplesCount))); 18572 const theta = float(sampleIndex).mul(goldenAngle).add(phi); 18573 return vec2(cos(theta), sin(theta)).mul(r); 18574}).setLayout({ 18575 name: "vogelDiskSample", 18576 type: "vec2", 18577 inputs: [ 18578 { name: "sampleIndex", type: "int" }, 18579 { name: "samplesCount", type: "int" }, 18580 { name: "phi", type: "float" } 18581 ] 18582}); 18583var SampleNode = class extends Node2 { 18584 /** 18585 * Returns the type of the node. 18586 * 18587 * @type {string} 18588 * @readonly 18589 * @static 18590 */ 18591 static get type() { 18592 return "SampleNode"; 18593 } 18594 /** 18595 * Creates an instance of SampleNode. 18596 * 18597 * @param {Function} callback - The function to be called when sampling. Should accept a UV node and return a value. 18598 * @param {?Node<vec2>} [uvNode=null] - The UV node to be used in the texture sampling. 18599 */ 18600 constructor(callback, uvNode = null) { 18601 super(); 18602 this.callback = callback; 18603 this.uvNode = uvNode; 18604 this.isSampleNode = true; 18605 } 18606 /** 18607 * Sets up the node by sampling with the default UV accessor. 18608 * 18609 * @returns {Node} The result of the callback function when called with the UV node. 18610 */ 18611 setup() { 18612 return this.sample(uv$1()); 18613 } 18614 /** 18615 * Calls the callback function with the provided UV node. 18616 * 18617 * @param {Node<vec2>} uv - The UV node or value to be passed to the callback. 18618 * @returns {Node} The result of the callback function. 18619 */ 18620 sample(uv3) { 18621 return this.callback(uv3); 18622 } 18623}; 18624var sample = (callback, uv3 = null) => new SampleNode(callback, nodeObject(uv3)); 18625var EventNode = class _EventNode extends Node2 { 18626 static get type() { 18627 return "EventNode"; 18628 } 18629 /** 18630 * Creates an EventNode. 18631 * 18632 * @param {string} eventType - The type of event 18633 * @param {Function} callback - The callback to execute on update. 18634 */ 18635 constructor(eventType, callback) { 18636 super("void"); 18637 this.eventType = eventType; 18638 this.callback = callback; 18639 if (eventType === _EventNode.OBJECT) { 18640 this.updateType = NodeUpdateType.OBJECT; 18641 } else if (eventType === _EventNode.MATERIAL) { 18642 this.updateType = NodeUpdateType.RENDER; 18643 } else if (eventType === _EventNode.FRAME) { 18644 this.updateType = NodeUpdateType.FRAME; 18645 } else if (eventType === _EventNode.BEFORE_OBJECT) { 18646 this.updateBeforeType = NodeUpdateType.OBJECT; 18647 } else if (eventType === _EventNode.BEFORE_MATERIAL) { 18648 this.updateBeforeType = NodeUpdateType.RENDER; 18649 } else if (eventType === _EventNode.BEFORE_FRAME) { 18650 this.updateBeforeType = NodeUpdateType.FRAME; 18651 } 18652 } 18653 update(frame) { 18654 this.callback(frame); 18655 } 18656 updateBefore(frame) { 18657 this.callback(frame); 18658 } 18659}; 18660EventNode.OBJECT = "object"; 18661EventNode.MATERIAL = "material"; 18662EventNode.FRAME = "frame"; 18663EventNode.BEFORE_OBJECT = "beforeObject"; 18664EventNode.BEFORE_MATERIAL = "beforeMaterial"; 18665EventNode.BEFORE_FRAME = "beforeFrame"; 18666var createEvent = (type, callback) => new EventNode(type, callback).toStack(); 18667var OnObjectUpdate = (callback) => createEvent(EventNode.OBJECT, callback); 18668var OnMaterialUpdate = (callback) => createEvent(EventNode.MATERIAL, callback); 18669var OnFrameUpdate = (callback) => createEvent(EventNode.FRAME, callback); 18670var OnBeforeObjectUpdate = (callback) => createEvent(EventNode.BEFORE_OBJECT, callback); 18671var OnBeforeMaterialUpdate = (callback) => createEvent(EventNode.BEFORE_MATERIAL, callback); 18672var OnBeforeFrameUpdate = (callback) => createEvent(EventNode.BEFORE_FRAME, callback); 18673var StorageInstancedBufferAttribute = class extends InstancedBufferAttribute { 18674 /** 18675 * Constructs a new storage instanced buffer attribute. 18676 * 18677 * @param {number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. 18678 * The subsequent parameters are then obsolete. 18679 * @param {number} itemSize - The item size. 18680 * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. 18681 */ 18682 constructor(count, itemSize, typeClass = Float32Array) { 18683 const array3 = ArrayBuffer.isView(count) ? count : new typeClass(count * itemSize); 18684 super(array3, itemSize); 18685 this.isStorageInstancedBufferAttribute = true; 18686 } 18687}; 18688var StorageBufferAttribute = class extends BufferAttribute { 18689 /** 18690 * Constructs a new storage buffer attribute. 18691 * 18692 * @param {number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. 18693 * The subsequent parameters are then obsolete. 18694 * @param {number} itemSize - The item size. 18695 * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. 18696 */ 18697 constructor(count, itemSize, typeClass = Float32Array) { 18698 const array3 = ArrayBuffer.isView(count) ? count : new typeClass(count * itemSize); 18699 super(array3, itemSize); 18700 this.isStorageBufferAttribute = true; 18701 } 18702}; 18703var attributeArray = (count, type = "float") => { 18704 let itemSize, typedArray; 18705 if (type.isStruct === true) { 18706 itemSize = type.layout.getLength(); 18707 typedArray = getTypedArrayFromType("float"); 18708 } else { 18709 itemSize = getLengthFromType(type); 18710 typedArray = getTypedArrayFromType(type); 18711 } 18712 const buffer3 = new StorageBufferAttribute(count, itemSize, typedArray); 18713 const node = storage(buffer3, type, count); 18714 return node; 18715}; 18716var instancedArray = (count, type = "float") => { 18717 let itemSize, typedArray; 18718 if (type.isStruct === true) { 18719 itemSize = type.layout.getLength(); 18720 typedArray = getTypedArrayFromType("float"); 18721 } else { 18722 itemSize = getLengthFromType(type); 18723 typedArray = getTypedArrayFromType(type); 18724 } 18725 const buffer3 = new StorageInstancedBufferAttribute(count, itemSize, typedArray); 18726 const node = storage(buffer3, type, buffer3.count); 18727 return node; 18728}; 18729var PointUVNode = class extends Node2 { 18730 static get type() { 18731 return "PointUVNode"; 18732 } 18733 /** 18734 * Constructs a new point uv node. 18735 */ 18736 constructor() { 18737 super("vec2"); 18738 this.isPointUVNode = true; 18739 } 18740 generate() { 18741 return "vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"; 18742 } 18743}; 18744var pointUV = /* @__PURE__ */ nodeImmutable(PointUVNode); 18745var _m1 = /* @__PURE__ */ new Matrix4(); 18746var backgroundBlurriness = /* @__PURE__ */ uniform(0).setGroup(renderGroup).onRenderUpdate(({ scene }) => scene.backgroundBlurriness); 18747var backgroundIntensity = /* @__PURE__ */ uniform(1).setGroup(renderGroup).onRenderUpdate(({ scene }) => scene.backgroundIntensity); 18748var backgroundRotation = /* @__PURE__ */ uniform(new Matrix4()).setGroup(renderGroup).onRenderUpdate(({ scene }) => { 18749 const background = scene.background; 18750 if (background !== null && background.isTexture && background.mapping !== UVMapping) { 18751 _m1.makeRotationFromEuler(scene.backgroundRotation).transpose(); 18752 } else { 18753 _m1.identity(); 18754 } 18755 return _m1; 18756}); 18757var StorageTextureNode = class extends TextureNode { 18758 static get type() { 18759 return "StorageTextureNode"; 18760 } 18761 /** 18762 * Constructs a new storage texture node. 18763 * 18764 * @param {StorageTexture} value - The storage texture. 18765 * @param {Node<vec2|vec3>} uvNode - The uv node. 18766 * @param {?Node} [storeNode=null] - The value node that should be stored in the texture. 18767 */ 18768 constructor(value, uvNode, storeNode = null) { 18769 super(value, uvNode); 18770 this.storeNode = storeNode; 18771 this.mipLevel = 0; 18772 this.isStorageTextureNode = true; 18773 this.access = NodeAccess.WRITE_ONLY; 18774 } 18775 /** 18776 * Overwrites the default implementation to return a fixed value `'storageTexture'`. 18777 * 18778 * @param {NodeBuilder} builder - The current node builder. 18779 * @return {string} The input type. 18780 */ 18781 getInputType() { 18782 return "storageTexture"; 18783 } 18784 setup(builder) { 18785 super.setup(builder); 18786 const properties = builder.getNodeProperties(this); 18787 properties.storeNode = this.storeNode; 18788 return properties; 18789 } 18790 /** 18791 * Defines the node access. 18792 * 18793 * @param {string} value - The node access. 18794 * @return {StorageTextureNode} A reference to this node. 18795 */ 18796 setAccess(value) { 18797 this.access = value; 18798 return this; 18799 } 18800 /** 18801 * Sets the mip level to write to. 18802 * 18803 * @param {number} level - The mip level. 18804 * @return {StorageTextureNode} A reference to this node. 18805 */ 18806 setMipLevel(level) { 18807 this.mipLevel = level; 18808 return this; 18809 } 18810 /** 18811 * Generates the code snippet of the storage node. If no `storeNode` 18812 * is defined, the texture node is generated as normal texture. 18813 * 18814 * @param {NodeBuilder} builder - The current node builder. 18815 * @param {string} output - The current output. 18816 * @return {string} The generated code snippet. 18817 */ 18818 generate(builder, output3) { 18819 if (this.storeNode !== null) { 18820 this.generateStore(builder); 18821 return ""; 18822 } 18823 return super.generate(builder, output3); 18824 } 18825 /** 18826 * Generates the snippet for the storage texture. 18827 * 18828 * @param {NodeBuilder} builder - The current node builder. 18829 * @param {string} textureProperty - The texture property. 18830 * @param {string} uvSnippet - The uv snippet. 18831 * @param {?string} levelSnippet - The level snippet. 18832 * @param {?string} biasSnippet - The bias snippet. 18833 * @param {?string} depthSnippet - The depth snippet. 18834 * @param {?string} compareSnippet - The compare snippet. 18835 * @param {?Array<string>} gradSnippet - The grad snippet. 18836 * @param {?string} offsetSnippet - The offset snippet. 18837 * @return {string} The generated code snippet. 18838 */ 18839 generateSnippet(builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet) { 18840 const texture3 = this.value; 18841 return builder.generateStorageTextureLoad(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet); 18842 } 18843 /** 18844 * Convenience method for configuring a read/write node access. 18845 * 18846 * @return {StorageTextureNode} A reference to this node. 18847 */ 18848 toReadWrite() { 18849 return this.setAccess(NodeAccess.READ_WRITE); 18850 } 18851 /** 18852 * Convenience method for configuring a read-only node access. 18853 * 18854 * @return {StorageTextureNode} A reference to this node. 18855 */ 18856 toReadOnly() { 18857 return this.setAccess(NodeAccess.READ_ONLY); 18858 } 18859 /** 18860 * Convenience method for configuring a write-only node access. 18861 * 18862 * @return {StorageTextureNode} A reference to this node. 18863 */ 18864 toWriteOnly() { 18865 return this.setAccess(NodeAccess.WRITE_ONLY); 18866 } 18867 /** 18868 * Generates the code snippet of the storage texture node. 18869 * 18870 * @param {NodeBuilder} builder - The current node builder. 18871 */ 18872 generateStore(builder) { 18873 const properties = builder.getNodeProperties(this); 18874 const { uvNode, storeNode, depthNode } = properties; 18875 const textureProperty = super.generate(builder, "property"); 18876 const uvSnippet = uvNode.build(builder, this.value.is3DTexture === true ? "uvec3" : "uvec2"); 18877 const storeSnippet = storeNode.build(builder, "vec4"); 18878 const depthSnippet = depthNode ? depthNode.build(builder, "int") : null; 18879 const snippet = builder.generateTextureStore(this.value, textureProperty, uvSnippet, depthSnippet, storeSnippet); 18880 builder.addLineFlowCode(snippet, this); 18881 } 18882 clone() { 18883 const newNode = super.clone(); 18884 newNode.storeNode = this.storeNode; 18885 newNode.mipLevel = this.mipLevel; 18886 newNode.access = this.access; 18887 return newNode; 18888 } 18889}; 18890var storageTexture = /* @__PURE__ */ nodeProxy(StorageTextureNode).setParameterLength(1, 3); 18891var textureStore = (value, uvNode, storeNode) => { 18892 let node; 18893 if (value.isStorageTextureNode === true) { 18894 node = value.clone(); 18895 node.uvNode = uvNode; 18896 node.storeNode = storeNode; 18897 } else { 18898 node = storageTexture(value, uvNode, storeNode); 18899 } 18900 if (storeNode !== null) node.toStack(); 18901 return node; 18902}; 18903var normal = Fn(({ texture: texture3, uv: uv3 }) => { 18904 const epsilon = 1e-4; 18905 const ret = vec3().toVar(); 18906 If(uv3.x.lessThan(epsilon), () => { 18907 ret.assign(vec3(1, 0, 0)); 18908 }).ElseIf(uv3.y.lessThan(epsilon), () => { 18909 ret.assign(vec3(0, 1, 0)); 18910 }).ElseIf(uv3.z.lessThan(epsilon), () => { 18911 ret.assign(vec3(0, 0, 1)); 18912 }).ElseIf(uv3.x.greaterThan(1 - epsilon), () => { 18913 ret.assign(vec3(-1, 0, 0)); 18914 }).ElseIf(uv3.y.greaterThan(1 - epsilon), () => { 18915 ret.assign(vec3(0, -1, 0)); 18916 }).ElseIf(uv3.z.greaterThan(1 - epsilon), () => { 18917 ret.assign(vec3(0, 0, -1)); 18918 }).Else(() => { 18919 const step3 = 0.01; 18920 const x = texture3.sample(uv3.add(vec3(-step3, 0, 0))).r.sub(texture3.sample(uv3.add(vec3(step3, 0, 0))).r); 18921 const y = texture3.sample(uv3.add(vec3(0, -step3, 0))).r.sub(texture3.sample(uv3.add(vec3(0, step3, 0))).r); 18922 const z = texture3.sample(uv3.add(vec3(0, 0, -step3))).r.sub(texture3.sample(uv3.add(vec3(0, 0, step3))).r); 18923 ret.assign(vec3(x, y, z)); 18924 }); 18925 return ret.normalize(); 18926}); 18927var Texture3DNode = class extends TextureNode { 18928 static get type() { 18929 return "Texture3DNode"; 18930 } 18931 /** 18932 * Constructs a new 3D texture node. 18933 * 18934 * @param {Data3DTexture} value - The 3D texture. 18935 * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node. 18936 * @param {?Node<int>} [levelNode=null] - The level node. 18937 */ 18938 constructor(value, uvNode = null, levelNode = null) { 18939 super(value, uvNode, levelNode); 18940 this.isTexture3DNode = true; 18941 } 18942 /** 18943 * Overwrites the default implementation to return a fixed value `'texture3D'`. 18944 * 18945 * @param {NodeBuilder} builder - The current node builder. 18946 * @return {string} The input type. 18947 */ 18948 getInputType() { 18949 return "texture3D"; 18950 } 18951 /** 18952 * Returns a default uv node which is in context of 3D textures a three-dimensional 18953 * uv node. 18954 * 18955 * @return {Node<vec3>} The default uv node. 18956 */ 18957 getDefaultUV() { 18958 return vec3(0.5, 0.5, 0.5); 18959 } 18960 /** 18961 * Overwritten with an empty implementation since the `updateMatrix` flag is ignored 18962 * for 3D textures. The uv transformation matrix is not applied to 3D textures. 18963 * 18964 * @param {boolean} value - The update toggle. 18965 */ 18966 setUpdateMatrix() { 18967 } 18968 // Ignore .updateMatrix for 3d TextureNode 18969 /** 18970 * Generates the uv code snippet. 18971 * 18972 * @param {NodeBuilder} builder - The current node builder. 18973 * @param {Node} uvNode - The uv node to generate code for. 18974 * @return {string} The generated code snippet. 18975 */ 18976 generateUV(builder, uvNode) { 18977 return uvNode.build(builder, this.sampler === true ? "vec3" : "ivec3"); 18978 } 18979 /** 18980 * Generates the offset code snippet. 18981 * 18982 * @param {NodeBuilder} builder - The current node builder. 18983 * @param {Node} offsetNode - The offset node to generate code for. 18984 * @return {string} The generated code snippet. 18985 */ 18986 generateOffset(builder, offsetNode) { 18987 return offsetNode.build(builder, "ivec3"); 18988 } 18989 /** 18990 * Computes the normal for the given uv. These texture coordiantes represent a 18991 * position inside the 3D texture. Unlike geometric normals, this normal 18992 * represents a slope or gradient of scalar data inside the 3D texture. 18993 * 18994 * @param {Node<vec3>} uvNode - The uv node that defines a position in the 3D texture. 18995 * @return {Node<vec3>} The normal representing the slope/gradient in the data. 18996 */ 18997 normal(uvNode) { 18998 return normal({ texture: this, uv: uvNode }); 18999 } 19000}; 19001var texture3D = /* @__PURE__ */ nodeProxy(Texture3DNode).setParameterLength(1, 3); 19002var texture3DLoad = (...params) => texture3D(...params).setSampler(false); 19003var texture3DLevel = (value, uvNode, levelNode) => texture3D(value, uvNode).level(levelNode); 19004var UserDataNode = class extends ReferenceNode { 19005 static get type() { 19006 return "UserDataNode"; 19007 } 19008 /** 19009 * Constructs a new user data node. 19010 * 19011 * @param {string} property - The property name that should be referenced by the node. 19012 * @param {string} inputType - The node data type of the reference. 19013 * @param {?Object} [userData=null] - A reference to the `userData` object. If not provided, the `userData` property of the 3D object that uses the node material is evaluated. 19014 */ 19015 constructor(property3, inputType, userData3 = null) { 19016 super(property3, inputType, userData3); 19017 this.userData = userData3; 19018 } 19019 /** 19020 * Overwritten to make sure {@link ReferenceNode#reference} points to the correct 19021 * `userData` field. 19022 * 19023 * @param {(NodeFrame|NodeBuilder)} state - The current state to evaluate. 19024 * @return {Object} A reference to the `userData` field. 19025 */ 19026 updateReference(state) { 19027 this.reference = this.userData !== null ? this.userData : state.object.userData; 19028 return this.reference; 19029 } 19030}; 19031var userData = (name, inputType, userData3) => new UserDataNode(name, inputType, userData3); 19032var _objectData = /* @__PURE__ */ new WeakMap(); 19033var VelocityNode = class extends TempNode { 19034 static get type() { 19035 return "VelocityNode"; 19036 } 19037 /** 19038 * Constructs a new vertex color node. 19039 */ 19040 constructor() { 19041 super("vec2"); 19042 this.projectionMatrix = null; 19043 this.updateType = NodeUpdateType.OBJECT; 19044 this.updateAfterType = NodeUpdateType.OBJECT; 19045 this.previousModelWorldMatrix = uniform(new Matrix4()); 19046 this.previousProjectionMatrix = uniform(new Matrix4()).setGroup(renderGroup); 19047 this.previousCameraViewMatrix = uniform(new Matrix4()); 19048 } 19049 /** 19050 * Sets the given projection matrix. 19051 * 19052 * @param {Matrix4} projectionMatrix - The projection matrix to set. 19053 */ 19054 setProjectionMatrix(projectionMatrix) { 19055 this.projectionMatrix = projectionMatrix; 19056 } 19057 /** 19058 * Updates velocity specific uniforms. 19059 * 19060 * @param {NodeFrame} frame - A reference to the current node frame. 19061 */ 19062 update({ frameId: frameId3, camera, object }) { 19063 const previousModelMatrix = getPreviousMatrix(object); 19064 this.previousModelWorldMatrix.value.copy(previousModelMatrix); 19065 const cameraData = getData(camera); 19066 if (cameraData.frameId !== frameId3) { 19067 cameraData.frameId = frameId3; 19068 if (cameraData.previousProjectionMatrix === void 0) { 19069 cameraData.previousProjectionMatrix = new Matrix4(); 19070 cameraData.previousCameraViewMatrix = new Matrix4(); 19071 cameraData.currentProjectionMatrix = new Matrix4(); 19072 cameraData.currentCameraViewMatrix = new Matrix4(); 19073 cameraData.previousProjectionMatrix.copy(this.projectionMatrix || camera.projectionMatrix); 19074 cameraData.previousCameraViewMatrix.copy(camera.matrixWorldInverse); 19075 } else { 19076 cameraData.previousProjectionMatrix.copy(cameraData.currentProjectionMatrix); 19077 cameraData.previousCameraViewMatrix.copy(cameraData.currentCameraViewMatrix); 19078 } 19079 cameraData.currentProjectionMatrix.copy(this.projectionMatrix || camera.projectionMatrix); 19080 cameraData.currentCameraViewMatrix.copy(camera.matrixWorldInverse); 19081 this.previousProjectionMatrix.value.copy(cameraData.previousProjectionMatrix); 19082 this.previousCameraViewMatrix.value.copy(cameraData.previousCameraViewMatrix); 19083 } 19084 } 19085 /** 19086 * Overwritten to updated velocity specific uniforms. 19087 * 19088 * @param {NodeFrame} frame - A reference to the current node frame. 19089 */ 19090 updateAfter({ object }) { 19091 getPreviousMatrix(object).copy(object.matrixWorld); 19092 } 19093 /** 19094 * Implements the velocity computation based on the previous and current vertex data. 19095 * 19096 * @param {NodeBuilder} builder - A reference to the current node builder. 19097 * @return {Node<vec2>} The motion vector. 19098 */ 19099 setup() { 19100 const projectionMatrix = this.projectionMatrix === null ? cameraProjectionMatrix : uniform(this.projectionMatrix); 19101 const previousModelViewMatrix = this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix); 19102 const clipPositionCurrent = projectionMatrix.mul(modelViewMatrix).mul(positionLocal); 19103 const clipPositionPrevious = this.previousProjectionMatrix.mul(previousModelViewMatrix).mul(positionPrevious); 19104 const ndcPositionCurrent = clipPositionCurrent.xy.div(clipPositionCurrent.w); 19105 const ndcPositionPrevious = clipPositionPrevious.xy.div(clipPositionPrevious.w); 19106 const velocity3 = sub(ndcPositionCurrent, ndcPositionPrevious); 19107 return velocity3; 19108 } 19109}; 19110function getData(object) { 19111 let objectData = _objectData.get(object); 19112 if (objectData === void 0) { 19113 objectData = {}; 19114 _objectData.set(object, objectData); 19115 } 19116 return objectData; 19117} 19118function getPreviousMatrix(object, index = 0) { 19119 const objectData = getData(object); 19120 let matrix = objectData[index]; 19121 if (matrix === void 0) { 19122 objectData[index] = matrix = new Matrix4(); 19123 objectData[index].copy(object.matrixWorld); 19124 } 19125 return matrix; 19126} 19127var velocity = /* @__PURE__ */ nodeImmutable(VelocityNode); 19128var grayscale = /* @__PURE__ */ Fn(([color3]) => { 19129 return luminance(color3.rgb); 19130}); 19131var saturation = /* @__PURE__ */ Fn(([color3, adjustment = float(1)]) => { 19132 return adjustment.mix(luminance(color3.rgb), color3.rgb); 19133}); 19134var vibrance = /* @__PURE__ */ Fn(([color3, adjustment = float(1)]) => { 19135 const average = add(color3.r, color3.g, color3.b).div(3); 19136 const mx = color3.r.max(color3.g.max(color3.b)); 19137 const amt = mx.sub(average).mul(adjustment).mul(-3); 19138 return mix(color3.rgb, mx, amt); 19139}); 19140var hue = /* @__PURE__ */ Fn(([color3, adjustment = float(1)]) => { 19141 const k = vec3(0.57735, 0.57735, 0.57735); 19142 const cosAngle = adjustment.cos(); 19143 return vec3(color3.rgb.mul(cosAngle).add(k.cross(color3.rgb).mul(adjustment.sin()).add(k.mul(dot(k, color3.rgb).mul(cosAngle.oneMinus()))))); 19144}); 19145var luminance = (color3, luminanceCoefficients = vec3(ColorManagement.getLuminanceCoefficients(new Vector3()))) => dot(color3, luminanceCoefficients); 19146var cdl = /* @__PURE__ */ Fn(([ 19147 color3, 19148 slope = vec3(1), 19149 offset3 = vec3(0), 19150 power = vec3(1), 19151 saturation3 = float(1), 19152 // ASC CDL v1.2 explicitly requires Rec. 709 luminance coefficients. 19153 luminanceCoefficients = vec3(ColorManagement.getLuminanceCoefficients(new Vector3(), LinearSRGBColorSpace)) 19154]) => { 19155 const luma = color3.rgb.dot(vec3(luminanceCoefficients)); 19156 const v = max$1(color3.rgb.mul(slope).add(offset3), 0).toVar(); 19157 const pv = v.pow(power).toVar(); 19158 If(v.r.greaterThan(0), () => { 19159 v.r.assign(pv.r); 19160 }); 19161 If(v.g.greaterThan(0), () => { 19162 v.g.assign(pv.g); 19163 }); 19164 If(v.b.greaterThan(0), () => { 19165 v.b.assign(pv.b); 19166 }); 19167 v.assign(luma.add(v.sub(luma).mul(saturation3))); 19168 return vec4(v.rgb, color3.a); 19169}); 19170var posterize = Fn(([source, steps]) => { 19171 return source.mul(steps).floor().div(steps); 19172}); 19173var _sharedFramebuffer = null; 19174var ViewportSharedTextureNode = class extends ViewportTextureNode { 19175 static get type() { 19176 return "ViewportSharedTextureNode"; 19177 } 19178 /** 19179 * Constructs a new viewport shared texture node. 19180 * 19181 * @param {Node} [uvNode=screenUV] - The uv node. 19182 * @param {?Node} [levelNode=null] - The level node. 19183 */ 19184 constructor(uvNode = screenUV, levelNode = null) { 19185 if (_sharedFramebuffer === null) { 19186 _sharedFramebuffer = new FramebufferTexture(); 19187 } 19188 super(uvNode, levelNode, _sharedFramebuffer); 19189 } 19190 /** 19191 * Overwritten so the method always returns the unique shared 19192 * framebuffer texture. 19193 * 19194 * @return {FramebufferTexture} The shared framebuffer texture. 19195 */ 19196 getTextureForReference() { 19197 return _sharedFramebuffer; 19198 } 19199 updateReference() { 19200 return this; 19201 } 19202}; 19203var viewportSharedTexture = /* @__PURE__ */ nodeProxy(ViewportSharedTextureNode).setParameterLength(0, 2); 19204var _size = /* @__PURE__ */ new Vector2(); 19205var PassTextureNode = class extends TextureNode { 19206 static get type() { 19207 return "PassTextureNode"; 19208 } 19209 /** 19210 * Constructs a new pass texture node. 19211 * 19212 * @param {PassNode} passNode - The pass node. 19213 * @param {Texture} texture - The output texture. 19214 */ 19215 constructor(passNode, texture3) { 19216 super(texture3); 19217 this.passNode = passNode; 19218 this.isPassTextureNode = true; 19219 this.setUpdateMatrix(false); 19220 } 19221 setup(builder) { 19222 const properties = builder.getNodeProperties(this); 19223 properties.passNode = this.passNode; 19224 return super.setup(builder); 19225 } 19226 clone() { 19227 return new this.constructor(this.passNode, this.value); 19228 } 19229}; 19230var PassMultipleTextureNode = class extends PassTextureNode { 19231 static get type() { 19232 return "PassMultipleTextureNode"; 19233 } 19234 /** 19235 * Constructs a new pass texture node. 19236 * 19237 * @param {PassNode} passNode - The pass node. 19238 * @param {string} textureName - The output texture name. 19239 * @param {boolean} [previousTexture=false] - Whether previous frame data should be used or not. 19240 */ 19241 constructor(passNode, textureName, previousTexture = false) { 19242 super(passNode, null); 19243 this.textureName = textureName; 19244 this.previousTexture = previousTexture; 19245 this.isPassMultipleTextureNode = true; 19246 } 19247 /** 19248 * Updates the texture reference of this node. 19249 */ 19250 updateTexture() { 19251 this.value = this.previousTexture ? this.passNode.getPreviousTexture(this.textureName) : this.passNode.getTexture(this.textureName); 19252 } 19253 setup(builder) { 19254 this.updateTexture(); 19255 return super.setup(builder); 19256 } 19257 clone() { 19258 const newNode = new this.constructor(this.passNode, this.textureName, this.previousTexture); 19259 newNode.uvNode = this.uvNode; 19260 newNode.levelNode = this.levelNode; 19261 newNode.biasNode = this.biasNode; 19262 newNode.sampler = this.sampler; 19263 newNode.depthNode = this.depthNode; 19264 newNode.compareNode = this.compareNode; 19265 newNode.gradNode = this.gradNode; 19266 newNode.offsetNode = this.offsetNode; 19267 return newNode; 19268 } 19269}; 19270var PassNode = class _PassNode extends TempNode { 19271 static get type() { 19272 return "PassNode"; 19273 } 19274 /** 19275 * Constructs a new pass node. 19276 * 19277 * @param {('color'|'depth')} scope - The scope of the pass. The scope determines whether the node outputs color or depth. 19278 * @param {Scene} scene - A reference to the scene. 19279 * @param {Camera} camera - A reference to the camera. 19280 * @param {Object} options - Options for the internal render target. 19281 */ 19282 constructor(scope, scene, camera, options = {}) { 19283 super("vec4"); 19284 this.scope = scope; 19285 this.scene = scene; 19286 this.camera = camera; 19287 this.options = options; 19288 this._pixelRatio = 1; 19289 this._width = 1; 19290 this._height = 1; 19291 const depthTexture = new DepthTexture(); 19292 depthTexture.isRenderTargetTexture = true; 19293 depthTexture.name = "depth"; 19294 const renderTarget = new RenderTarget(this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType, ...options }); 19295 renderTarget.texture.name = "output"; 19296 renderTarget.depthTexture = depthTexture; 19297 this.renderTarget = renderTarget; 19298 this.overrideMaterial = null; 19299 this.transparent = true; 19300 this.opaque = true; 19301 this.contextNode = null; 19302 this._contextNodeCache = null; 19303 this._textures = { 19304 output: renderTarget.texture, 19305 depth: depthTexture 19306 }; 19307 this._textureNodes = {}; 19308 this._linearDepthNodes = {}; 19309 this._viewZNodes = {}; 19310 this._previousTextures = {}; 19311 this._previousTextureNodes = {}; 19312 this._cameraNear = uniform(0); 19313 this._cameraFar = uniform(0); 19314 this._mrt = null; 19315 this._layers = null; 19316 this._resolutionScale = 1; 19317 this._viewport = null; 19318 this._scissor = null; 19319 this.isPassNode = true; 19320 this.updateBeforeType = NodeUpdateType.FRAME; 19321 this.global = true; 19322 } 19323 /** 19324 * Sets the resolution scale for the pass. 19325 * The resolution scale is a factor that is multiplied with the renderer's width and height. 19326 * 19327 * @param {number} resolutionScale - The resolution scale to set. A value of `1` means full resolution. 19328 * @return {PassNode} A reference to this pass. 19329 */ 19330 setResolutionScale(resolutionScale) { 19331 this._resolutionScale = resolutionScale; 19332 return this; 19333 } 19334 /** 19335 * Gets the current resolution scale of the pass. 19336 * 19337 * @return {number} The current resolution scale. A value of `1` means full resolution. 19338 */ 19339 getResolutionScale() { 19340 return this._resolutionScale; 19341 } 19342 /** 19343 * Sets the resolution for the pass. 19344 * The resolution is a factor that is multiplied with the renderer's width and height. 19345 * 19346 * @param {number} resolution - The resolution to set. A value of `1` means full resolution. 19347 * @return {PassNode} A reference to this pass. 19348 * @deprecated since r181. Use {@link PassNode#setResolutionScale `setResolutionScale()`} instead. 19349 */ 19350 setResolution(resolution) { 19351 warn("PassNode: .setResolution() is deprecated. Use .setResolutionScale() instead."); 19352 return this.setResolutionScale(resolution); 19353 } 19354 /** 19355 * Gets the current resolution of the pass. 19356 * 19357 * @return {number} The current resolution. A value of `1` means full resolution. 19358 * @deprecated since r181. Use {@link PassNode#getResolutionScale `getResolutionScale()`} instead. 19359 */ 19360 getResolution() { 19361 warn("PassNode: .getResolution() is deprecated. Use .getResolutionScale() instead."); 19362 return this.getResolutionScale(); 19363 } 19364 /** 19365 * Sets the layer configuration that should be used when rendering the pass. 19366 * 19367 * @param {Layers} layers - The layers object to set. 19368 * @return {PassNode} A reference to this pass. 19369 */ 19370 setLayers(layers2) { 19371 this._layers = layers2; 19372 return this; 19373 } 19374 /** 19375 * Gets the current layer configuration of the pass. 19376 * 19377 * @return {?Layers} . 19378 */ 19379 getLayers() { 19380 return this._layers; 19381 } 19382 /** 19383 * Sets the given MRT node to setup MRT for this pass. 19384 * 19385 * @param {MRTNode} mrt - The MRT object. 19386 * @return {PassNode} A reference to this pass. 19387 */ 19388 setMRT(mrt3) { 19389 this._mrt = mrt3; 19390 return this; 19391 } 19392 /** 19393 * Returns the current MRT node. 19394 * 19395 * @return {MRTNode} The current MRT node. 19396 */ 19397 getMRT() { 19398 return this._mrt; 19399 } 19400 /** 19401 * Returns the texture for the given output name. 19402 * 19403 * @param {string} name - The output name to get the texture for. 19404 * @return {Texture} The texture. 19405 */ 19406 getTexture(name) { 19407 let texture3 = this._textures[name]; 19408 if (texture3 === void 0) { 19409 const refTexture = this.renderTarget.texture; 19410 texture3 = refTexture.clone(); 19411 texture3.name = name; 19412 this._textures[name] = texture3; 19413 this.renderTarget.textures.push(texture3); 19414 } 19415 return texture3; 19416 } 19417 /** 19418 * Returns the texture holding the data of the previous frame for the given output name. 19419 * 19420 * @param {string} name - The output name to get the texture for. 19421 * @return {Texture} The texture holding the data of the previous frame. 19422 */ 19423 getPreviousTexture(name) { 19424 let texture3 = this._previousTextures[name]; 19425 if (texture3 === void 0) { 19426 texture3 = this.getTexture(name).clone(); 19427 this._previousTextures[name] = texture3; 19428 } 19429 return texture3; 19430 } 19431 /** 19432 * Switches current and previous textures for the given output name. 19433 * 19434 * @param {string} name - The output name. 19435 */ 19436 toggleTexture(name) { 19437 const prevTexture = this._previousTextures[name]; 19438 if (prevTexture !== void 0) { 19439 const texture3 = this._textures[name]; 19440 const index = this.renderTarget.textures.indexOf(texture3); 19441 this.renderTarget.textures[index] = prevTexture; 19442 this._textures[name] = prevTexture; 19443 this._previousTextures[name] = texture3; 19444 this._textureNodes[name].updateTexture(); 19445 this._previousTextureNodes[name].updateTexture(); 19446 } 19447 } 19448 /** 19449 * Returns the texture node for the given output name. 19450 * 19451 * @param {string} [name='output'] - The output name to get the texture node for. 19452 * @return {TextureNode} The texture node. 19453 */ 19454 getTextureNode(name = "output") { 19455 let textureNode = this._textureNodes[name]; 19456 if (textureNode === void 0) { 19457 textureNode = new PassMultipleTextureNode(this, name); 19458 textureNode.updateTexture(); 19459 this._textureNodes[name] = textureNode; 19460 } 19461 return textureNode; 19462 } 19463 /** 19464 * Returns the previous texture node for the given output name. 19465 * 19466 * @param {string} [name='output'] - The output name to get the previous texture node for. 19467 * @return {TextureNode} The previous texture node. 19468 */ 19469 getPreviousTextureNode(name = "output") { 19470 let textureNode = this._previousTextureNodes[name]; 19471 if (textureNode === void 0) { 19472 if (this._textureNodes[name] === void 0) this.getTextureNode(name); 19473 textureNode = new PassMultipleTextureNode(this, name, true); 19474 textureNode.updateTexture(); 19475 this._previousTextureNodes[name] = textureNode; 19476 } 19477 return textureNode; 19478 } 19479 /** 19480 * Returns a viewZ node of this pass. 19481 * 19482 * @param {string} [name='depth'] - The output name to get the viewZ node for. In most cases the default `'depth'` can be used however the parameter exists for custom depth outputs. 19483 * @return {Node} The viewZ node. 19484 */ 19485 getViewZNode(name = "depth") { 19486 let viewZNode = this._viewZNodes[name]; 19487 if (viewZNode === void 0) { 19488 const cameraNear3 = this._cameraNear; 19489 const cameraFar3 = this._cameraFar; 19490 this._viewZNodes[name] = viewZNode = perspectiveDepthToViewZ(this.getTextureNode(name), cameraNear3, cameraFar3); 19491 } 19492 return viewZNode; 19493 } 19494 /** 19495 * Returns a linear depth node of this pass. 19496 * 19497 * @param {string} [name='depth'] - The output name to get the linear depth node for. In most cases the default `'depth'` can be used however the parameter exists for custom depth outputs. 19498 * @return {Node} The linear depth node. 19499 */ 19500 getLinearDepthNode(name = "depth") { 19501 let linearDepthNode = this._linearDepthNodes[name]; 19502 if (linearDepthNode === void 0) { 19503 const cameraNear3 = this._cameraNear; 19504 const cameraFar3 = this._cameraFar; 19505 const viewZNode = this.getViewZNode(name); 19506 this._linearDepthNodes[name] = linearDepthNode = viewZToOrthographicDepth(viewZNode, cameraNear3, cameraFar3); 19507 } 19508 return linearDepthNode; 19509 } 19510 /** 19511 * Precompiles the pass. 19512 * 19513 * Note that this method must be called after the pass configuration is complete. 19514 * So calls like `setMRT()` and `getTextureNode()` must proceed the precompilation. 19515 * 19516 * @async 19517 * @param {Renderer} renderer - The renderer. 19518 * @return {Promise} A Promise that resolves when the compile has been finished. 19519 * @see {@link Renderer#compileAsync} 19520 */ 19521 async compileAsync(renderer) { 19522 const currentRenderTarget = renderer.getRenderTarget(); 19523 const currentMRT = renderer.getMRT(); 19524 renderer.setRenderTarget(this.renderTarget); 19525 renderer.setMRT(this._mrt); 19526 await renderer.compileAsync(this.scene, this.camera); 19527 renderer.setRenderTarget(currentRenderTarget); 19528 renderer.setMRT(currentMRT); 19529 } 19530 setup({ renderer }) { 19531 this.renderTarget.samples = this.options.samples === void 0 ? renderer.samples : this.options.samples; 19532 this.renderTarget.texture.type = renderer.getOutputBufferType(); 19533 if (renderer.reversedDepthBuffer === true) { 19534 this.renderTarget.depthTexture.type = FloatType; 19535 } 19536 return this.scope === _PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode(); 19537 } 19538 updateBefore(frame) { 19539 const { renderer } = frame; 19540 const { scene } = this; 19541 let camera; 19542 let pixelRatio; 19543 const outputRenderTarget = renderer.getOutputRenderTarget(); 19544 if (outputRenderTarget && outputRenderTarget.isXRRenderTarget === true) { 19545 pixelRatio = 1; 19546 camera = renderer.xr.getCamera(); 19547 renderer.xr.updateCamera(camera); 19548 _size.set(outputRenderTarget.width, outputRenderTarget.height); 19549 } else { 19550 camera = this.camera; 19551 pixelRatio = renderer.getPixelRatio(); 19552 renderer.getSize(_size); 19553 } 19554 this._pixelRatio = pixelRatio; 19555 this.setSize(_size.width, _size.height); 19556 const currentRenderTarget = renderer.getRenderTarget(); 19557 const currentMRT = renderer.getMRT(); 19558 const currentAutoClear = renderer.autoClear; 19559 const currentTransparent = renderer.transparent; 19560 const currentOpaque = renderer.opaque; 19561 const currentMask = camera.layers.mask; 19562 const currentContextNode = renderer.contextNode; 19563 const currentOverrideMaterial = scene.overrideMaterial; 19564 this._cameraNear.value = camera.near; 19565 this._cameraFar.value = camera.far; 19566 if (this._layers !== null) { 19567 camera.layers.mask = this._layers.mask; 19568 } 19569 for (const name in this._previousTextures) { 19570 this.toggleTexture(name); 19571 } 19572 if (this.overrideMaterial !== null) { 19573 scene.overrideMaterial = this.overrideMaterial; 19574 } 19575 renderer.setRenderTarget(this.renderTarget); 19576 renderer.setMRT(this._mrt); 19577 renderer.autoClear = true; 19578 renderer.transparent = this.transparent; 19579 renderer.opaque = this.opaque; 19580 if (this.contextNode !== null) { 19581 if (this._contextNodeCache === null || this._contextNodeCache.version !== this.version) { 19582 this._contextNodeCache = { 19583 version: this.version, 19584 context: context({ ...renderer.contextNode.getFlowContextData(), ...this.contextNode.getFlowContextData() }) 19585 }; 19586 } 19587 renderer.contextNode = this._contextNodeCache.context; 19588 } 19589 const currentSceneName = scene.name; 19590 scene.name = this.name ? this.name : scene.name; 19591 renderer.render(scene, camera); 19592 scene.name = currentSceneName; 19593 scene.overrideMaterial = currentOverrideMaterial; 19594 renderer.setRenderTarget(currentRenderTarget); 19595 renderer.setMRT(currentMRT); 19596 renderer.autoClear = currentAutoClear; 19597 renderer.transparent = currentTransparent; 19598 renderer.opaque = currentOpaque; 19599 renderer.contextNode = currentContextNode; 19600 camera.layers.mask = currentMask; 19601 } 19602 /** 19603 * Sets the size of the pass's render target. Honors the pixel ratio. 19604 * 19605 * @param {number} width - The width to set. 19606 * @param {number} height - The height to set. 19607 */ 19608 setSize(width, height) { 19609 this._width = width; 19610 this._height = height; 19611 const effectiveWidth = Math.floor(this._width * this._pixelRatio * this._resolutionScale); 19612 const effectiveHeight = Math.floor(this._height * this._pixelRatio * this._resolutionScale); 19613 this.renderTarget.setSize(effectiveWidth, effectiveHeight); 19614 if (this._scissor !== null) { 19615 this.renderTarget.scissor.copy(this._scissor).multiplyScalar(this._pixelRatio * this._resolutionScale).floor(); 19616 this.renderTarget.scissorTest = true; 19617 } else { 19618 this.renderTarget.scissorTest = false; 19619 } 19620 if (this._viewport !== null) { 19621 this.renderTarget.viewport.copy(this._viewport).multiplyScalar(this._pixelRatio * this._resolutionScale).floor(); 19622 } 19623 } 19624 /** 19625 * This method allows to define the pass's scissor rectangle. By default, the scissor rectangle is kept 19626 * in sync with the pass's dimensions. To reverse the process and use auto-sizing again, call the method 19627 * with `null` as the single argument. 19628 * 19629 * @param {?(number | Vector4)} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. 19630 * Instead of passing four arguments, the method also works with a single four-dimensional vector. 19631 * @param {number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. 19632 * @param {number} width - The width of the scissor box in logical pixel unit. 19633 * @param {number} height - The height of the scissor box in logical pixel unit. 19634 */ 19635 setScissor(x, y, width, height) { 19636 if (x === null) { 19637 this._scissor = null; 19638 } else { 19639 if (this._scissor === null) this._scissor = new Vector4(); 19640 if (x.isVector4) { 19641 this._scissor.copy(x); 19642 } else { 19643 this._scissor.set(x, y, width, height); 19644 } 19645 } 19646 } 19647 /** 19648 * This method allows to define the pass's viewport. By default, the viewport is kept in sync 19649 * with the pass's dimensions. To reverse the process and use auto-sizing again, call the method 19650 * with `null` as the single argument. 19651 * 19652 * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. 19653 * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. 19654 * @param {number} width - The width of the viewport in logical pixel unit. 19655 * @param {number} height - The height of the viewport in logical pixel unit. 19656 */ 19657 setViewport(x, y, width, height) { 19658 if (x === null) { 19659 this._viewport = null; 19660 } else { 19661 if (this._viewport === null) this._viewport = new Vector4(); 19662 if (x.isVector4) { 19663 this._viewport.copy(x); 19664 } else { 19665 this._viewport.set(x, y, width, height); 19666 } 19667 } 19668 } 19669 /** 19670 * Sets the pixel ratio the pass's render target and updates the size. 19671 * 19672 * @param {number} pixelRatio - The pixel ratio to set. 19673 */ 19674 setPixelRatio(pixelRatio) { 19675 this._pixelRatio = pixelRatio; 19676 this.setSize(this._width, this._height); 19677 } 19678 /** 19679 * Frees internal resources. Should be called when the node is no longer in use. 19680 */ 19681 dispose() { 19682 this.renderTarget.dispose(); 19683 } 19684}; 19685PassNode.COLOR = "color"; 19686PassNode.DEPTH = "depth"; 19687var pass = (scene, camera, options) => new PassNode(PassNode.COLOR, scene, camera, options); 19688var passTexture = (pass3, texture3) => new PassTextureNode(pass3, texture3); 19689var depthPass = (scene, camera, options) => new PassNode(PassNode.DEPTH, scene, camera, options); 19690var ToonOutlinePassNode = class extends PassNode { 19691 static get type() { 19692 return "ToonOutlinePassNode"; 19693 } 19694 /** 19695 * Constructs a new outline pass node. 19696 * 19697 * @param {Scene} scene - A reference to the scene. 19698 * @param {Camera} camera - A reference to the camera. 19699 * @param {Node} colorNode - Defines the outline's color. 19700 * @param {Node} thicknessNode - Defines the outline's thickness. 19701 * @param {Node} alphaNode - Defines the outline's alpha. 19702 */ 19703 constructor(scene, camera, colorNode, thicknessNode, alphaNode) { 19704 super(PassNode.COLOR, scene, camera); 19705 this.colorNode = colorNode; 19706 this.thicknessNode = thicknessNode; 19707 this.alphaNode = alphaNode; 19708 this._materialCache = /* @__PURE__ */ new WeakMap(); 19709 this.name = "Outline Pass"; 19710 } 19711 updateBefore(frame) { 19712 const { renderer } = frame; 19713 const currentRenderObjectFunction = renderer.getRenderObjectFunction(); 19714 renderer.setRenderObjectFunction((object, scene, camera, geometry, material, group, lightsNode, clippingContext) => { 19715 if (material.isMeshToonMaterial || material.isMeshToonNodeMaterial) { 19716 if (material.wireframe === false) { 19717 const outlineMaterial = this._getOutlineMaterial(material); 19718 renderer.renderObject(object, scene, camera, geometry, outlineMaterial, group, lightsNode, clippingContext); 19719 } 19720 } 19721 renderer.renderObject(object, scene, camera, geometry, material, group, lightsNode, clippingContext); 19722 }); 19723 super.updateBefore(frame); 19724 renderer.setRenderObjectFunction(currentRenderObjectFunction); 19725 } 19726 /** 19727 * Creates the material used for outline rendering. 19728 * 19729 * @private 19730 * @return {NodeMaterial} The outline material. 19731 */ 19732 _createMaterial() { 19733 const material = new NodeMaterial(); 19734 material.isMeshToonOutlineMaterial = true; 19735 material.name = "Toon_Outline"; 19736 material.side = BackSide; 19737 const outlineNormal = normalLocal.negate(); 19738 const mvp = cameraProjectionMatrix.mul(modelViewMatrix); 19739 const ratio = float(1); 19740 const pos = mvp.mul(vec4(positionLocal, 1)); 19741 const pos2 = mvp.mul(vec4(positionLocal.add(outlineNormal), 1)); 19742 const norm = normalize(pos.sub(pos2)); 19743 material.vertexNode = pos.add(norm.mul(this.thicknessNode).mul(pos.w).mul(ratio)); 19744 material.colorNode = vec4(this.colorNode, this.alphaNode); 19745 return material; 19746 } 19747 /** 19748 * For the given toon material, this method returns a corresponding 19749 * outline material. 19750 * 19751 * @private 19752 * @param {(MeshToonMaterial|MeshToonNodeMaterial)} originalMaterial - The toon material. 19753 * @return {NodeMaterial} The outline material. 19754 */ 19755 _getOutlineMaterial(originalMaterial) { 19756 let outlineMaterial = this._materialCache.get(originalMaterial); 19757 if (outlineMaterial === void 0) { 19758 outlineMaterial = this._createMaterial(); 19759 this._materialCache.set(originalMaterial, outlineMaterial); 19760 } 19761 return outlineMaterial; 19762 } 19763}; 19764var toonOutlinePass = (scene, camera, color3 = new Color(0, 0, 0), thickness3 = 3e-3, alpha = 1) => new ToonOutlinePassNode(scene, camera, nodeObject(color3), nodeObject(thickness3), nodeObject(alpha)); 19765var linearToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19766 return color3.mul(exposure).clamp(); 19767}).setLayout({ 19768 name: "linearToneMapping", 19769 type: "vec3", 19770 inputs: [ 19771 { name: "color", type: "vec3" }, 19772 { name: "exposure", type: "float" } 19773 ] 19774}); 19775var reinhardToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19776 color3 = color3.mul(exposure); 19777 return color3.div(color3.add(1)).clamp(); 19778}).setLayout({ 19779 name: "reinhardToneMapping", 19780 type: "vec3", 19781 inputs: [ 19782 { name: "color", type: "vec3" }, 19783 { name: "exposure", type: "float" } 19784 ] 19785}); 19786var cineonToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19787 color3 = color3.mul(exposure); 19788 color3 = color3.sub(4e-3).max(0); 19789 const a = color3.mul(color3.mul(6.2).add(0.5)); 19790 const b = color3.mul(color3.mul(6.2).add(1.7)).add(0.06); 19791 return a.div(b).pow(2.2); 19792}).setLayout({ 19793 name: "cineonToneMapping", 19794 type: "vec3", 19795 inputs: [ 19796 { name: "color", type: "vec3" }, 19797 { name: "exposure", type: "float" } 19798 ] 19799}); 19800var RRTAndODTFit = /* @__PURE__ */ Fn(([color3]) => { 19801 const a = color3.mul(color3.add(0.0245786)).sub(90537e-9); 19802 const b = color3.mul(color3.add(0.432951).mul(0.983729)).add(0.238081); 19803 return a.div(b); 19804}); 19805var acesFilmicToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19806 const ACESInputMat = mat3( 19807 0.59719, 19808 0.35458, 19809 0.04823, 19810 0.076, 19811 0.90834, 19812 0.01566, 19813 0.0284, 19814 0.13383, 19815 0.83777 19816 ); 19817 const ACESOutputMat = mat3( 19818 1.60475, 19819 -0.53108, 19820 -0.07367, 19821 -0.10208, 19822 1.10813, 19823 -605e-5, 19824 -327e-5, 19825 -0.07276, 19826 1.07602 19827 ); 19828 color3 = color3.mul(exposure).div(0.6); 19829 color3 = ACESInputMat.mul(color3); 19830 color3 = RRTAndODTFit(color3); 19831 color3 = ACESOutputMat.mul(color3); 19832 return color3.clamp(); 19833}).setLayout({ 19834 name: "acesFilmicToneMapping", 19835 type: "vec3", 19836 inputs: [ 19837 { name: "color", type: "vec3" }, 19838 { name: "exposure", type: "float" } 19839 ] 19840}); 19841var LINEAR_REC2020_TO_LINEAR_SRGB = /* @__PURE__ */ mat3(vec3(1.6605, -0.1246, -0.0182), vec3(-0.5876, 1.1329, -0.1006), vec3(-0.0728, -83e-4, 1.1187)); 19842var LINEAR_SRGB_TO_LINEAR_REC2020 = /* @__PURE__ */ mat3(vec3(0.6274, 0.0691, 0.0164), vec3(0.3293, 0.9195, 0.088), vec3(0.0433, 0.0113, 0.8956)); 19843var agxDefaultContrastApprox = /* @__PURE__ */ Fn(([x_immutable]) => { 19844 const x = vec3(x_immutable).toVar(); 19845 const x2 = vec3(x.mul(x)).toVar(); 19846 const x4 = vec3(x2.mul(x2)).toVar(); 19847 return float(15.5).mul(x4.mul(x2)).sub(mul(40.14, x4.mul(x))).add(mul(31.96, x4).sub(mul(6.868, x2.mul(x))).add(mul(0.4298, x2).add(mul(0.1191, x).sub(232e-5)))); 19848}); 19849var agxToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19850 const colortone = vec3(color3).toVar(); 19851 const AgXInsetMatrix = mat3(vec3(0.856627153315983, 0.137318972929847, 0.11189821299995), vec3(0.0951212405381588, 0.761241990602591, 0.0767994186031903), vec3(0.0482516061458583, 0.101439036467562, 0.811302368396859)); 19852 const AgXOutsetMatrix = mat3(vec3(1.1271005818144368, -0.1413297634984383, -0.14132976349843826), vec3(-0.11060664309660323, 1.157823702216272, -0.11060664309660294), vec3(-0.016493938717834573, -0.016493938717834257, 1.2519364065950405)); 19853 const AgxMinEv = float(-12.47393); 19854 const AgxMaxEv = float(4.026069); 19855 colortone.mulAssign(exposure); 19856 colortone.assign(LINEAR_SRGB_TO_LINEAR_REC2020.mul(colortone)); 19857 colortone.assign(AgXInsetMatrix.mul(colortone)); 19858 colortone.assign(max$1(colortone, 1e-10)); 19859 colortone.assign(log22(colortone)); 19860 colortone.assign(colortone.sub(AgxMinEv).div(AgxMaxEv.sub(AgxMinEv))); 19861 colortone.assign(clamp(colortone, 0, 1)); 19862 colortone.assign(agxDefaultContrastApprox(colortone)); 19863 colortone.assign(AgXOutsetMatrix.mul(colortone)); 19864 colortone.assign(pow(max$1(vec3(0), colortone), vec3(2.2))); 19865 colortone.assign(LINEAR_REC2020_TO_LINEAR_SRGB.mul(colortone)); 19866 colortone.assign(clamp(colortone, 0, 1)); 19867 return colortone; 19868}).setLayout({ 19869 name: "agxToneMapping", 19870 type: "vec3", 19871 inputs: [ 19872 { name: "color", type: "vec3" }, 19873 { name: "exposure", type: "float" } 19874 ] 19875}); 19876var neutralToneMapping = /* @__PURE__ */ Fn(([color3, exposure]) => { 19877 const StartCompression = float(0.8 - 0.04); 19878 const Desaturation = float(0.15); 19879 color3 = color3.mul(exposure); 19880 const x = min$1(color3.r, min$1(color3.g, color3.b)); 19881 const offset3 = select(x.lessThan(0.08), x.sub(mul(6.25, x.mul(x))), 0.04); 19882 color3.subAssign(offset3); 19883 const peak = max$1(color3.r, max$1(color3.g, color3.b)); 19884 If(peak.lessThan(StartCompression), () => { 19885 return color3; 19886 }); 19887 const d = sub(1, StartCompression); 19888 const newPeak = sub(1, d.mul(d).div(peak.add(d.sub(StartCompression)))); 19889 color3.mulAssign(newPeak.div(peak)); 19890 const g = sub(1, div(1, Desaturation.mul(peak.sub(newPeak)).add(1))); 19891 return mix(color3, vec3(newPeak), g); 19892}).setLayout({ 19893 name: "neutralToneMapping", 19894 type: "vec3", 19895 inputs: [ 19896 { name: "color", type: "vec3" }, 19897 { name: "exposure", type: "float" } 19898 ] 19899}); 19900var CodeNode = class extends Node2 { 19901 static get type() { 19902 return "CodeNode"; 19903 } 19904 /** 19905 * Constructs a new code node. 19906 * 19907 * @param {string} [code=''] - The native code. 19908 * @param {Array<Node>} [includes=[]] - An array of includes. 19909 * @param {('js'|'wgsl'|'glsl')} [language=''] - The used language. 19910 */ 19911 constructor(code3 = "", includes = [], language = "") { 19912 super("code"); 19913 this.isCodeNode = true; 19914 this.global = true; 19915 this.code = code3; 19916 this.includes = includes; 19917 this.language = language; 19918 } 19919 /** 19920 * Sets the includes of this code node. 19921 * 19922 * @param {Array<Node>} includes - The includes to set. 19923 * @return {CodeNode} A reference to this node. 19924 */ 19925 setIncludes(includes) { 19926 this.includes = includes; 19927 return this; 19928 } 19929 /** 19930 * Returns the includes of this code node. 19931 * 19932 * @param {NodeBuilder} builder - The current node builder. 19933 * @return {Array<Node>} The includes. 19934 */ 19935 getIncludes() { 19936 return this.includes; 19937 } 19938 generate(builder) { 19939 const includes = this.getIncludes(builder); 19940 for (const include of includes) { 19941 include.build(builder); 19942 } 19943 const nodeCode = builder.getCodeFromNode(this, this.getNodeType(builder)); 19944 nodeCode.code = this.code; 19945 return nodeCode.code; 19946 } 19947 serialize(data) { 19948 super.serialize(data); 19949 data.code = this.code; 19950 data.language = this.language; 19951 } 19952 deserialize(data) { 19953 super.deserialize(data); 19954 this.code = data.code; 19955 this.language = data.language; 19956 } 19957}; 19958var code = /* @__PURE__ */ nodeProxy(CodeNode).setParameterLength(1, 3); 19959var js = (src, includes) => code(src, includes, "js"); 19960var wgsl = (src, includes) => code(src, includes, "wgsl"); 19961var glsl = (src, includes) => code(src, includes, "glsl"); 19962var FunctionNode = class extends CodeNode { 19963 static get type() { 19964 return "FunctionNode"; 19965 } 19966 /** 19967 * Constructs a new function node. 19968 * 19969 * @param {string} [code=''] - The native code. 19970 * @param {Array<Node>} [includes=[]] - An array of includes. 19971 * @param {('js'|'wgsl'|'glsl')} [language=''] - The used language. 19972 */ 19973 constructor(code3 = "", includes = [], language = "") { 19974 super(code3, includes, language); 19975 } 19976 /** 19977 * Returns the type of this function node. 19978 * 19979 * @param {NodeBuilder} builder - The current node builder. 19980 * @return {string} The type. 19981 */ 19982 generateNodeType(builder) { 19983 return this.getNodeFunction(builder).type; 19984 } 19985 /** 19986 * Returns the type of a member of this function node. 19987 * 19988 * @param {NodeBuilder} builder - The current node builder. 19989 * @param {string} name - The name of the member. 19990 * @return {string} The type of the member. 19991 */ 19992 getMemberType(builder, name) { 19993 const type = this.getNodeType(builder); 19994 const structType = builder.getStructTypeNode(type); 19995 return structType.getMemberType(builder, name); 19996 } 19997 /** 19998 * Returns the inputs of this function node. 19999 * 20000 * @param {NodeBuilder} builder - The current node builder. 20001 * @return {Array<NodeFunctionInput>} The inputs. 20002 */ 20003 getInputs(builder) { 20004 return this.getNodeFunction(builder).inputs; 20005 } 20006 /** 20007 * Returns the node function for this function node. 20008 * 20009 * @param {NodeBuilder} builder - The current node builder. 20010 * @return {NodeFunction} The node function. 20011 */ 20012 getNodeFunction(builder) { 20013 const nodeData = builder.getDataFromNode(this); 20014 let nodeFunction = nodeData.nodeFunction; 20015 if (nodeFunction === void 0) { 20016 nodeFunction = builder.parser.parseFunction(this.code); 20017 nodeData.nodeFunction = nodeFunction; 20018 } 20019 return nodeFunction; 20020 } 20021 generate(builder, output3) { 20022 super.generate(builder); 20023 const nodeFunction = this.getNodeFunction(builder); 20024 const name = nodeFunction.name; 20025 const type = nodeFunction.type; 20026 const nodeCode = builder.getCodeFromNode(this, type); 20027 if (name !== "") { 20028 nodeCode.name = name; 20029 } 20030 const propertyName = builder.getPropertyName(nodeCode); 20031 const code3 = this.getNodeFunction(builder).getCode(propertyName); 20032 nodeCode.code = code3 + "\n"; 20033 if (output3 === "property") { 20034 return propertyName; 20035 } else { 20036 return builder.format(`${propertyName}()`, type, output3); 20037 } 20038 } 20039}; 20040var nativeFn = (code3, includes = [], language = "") => { 20041 for (let i = 0; i < includes.length; i++) { 20042 const include = includes[i]; 20043 if (typeof include === "function") { 20044 includes[i] = include.functionNode; 20045 } 20046 } 20047 const functionNode = new FunctionNode(code3, includes, language); 20048 const fn = (...params) => functionNode.call(...params); 20049 fn.functionNode = functionNode; 20050 return fn; 20051}; 20052var glslFn = (code3, includes) => nativeFn(code3, includes, "glsl"); 20053var wgslFn = (code3, includes) => nativeFn(code3, includes, "wgsl"); 20054function getViewZNode(builder) { 20055 let viewZ; 20056 const getViewZ = builder.context.getViewZ; 20057 if (getViewZ !== void 0) { 20058 viewZ = getViewZ(this); 20059 } 20060 return (viewZ || positionView.z).negate(); 20061} 20062var rangeFogFactor = Fn(([near, far], builder) => { 20063 const viewZ = getViewZNode(builder); 20064 return smoothstep(near, far, viewZ); 20065}); 20066var densityFogFactor = Fn(([density], builder) => { 20067 const viewZ = getViewZNode(builder); 20068 return density.mul(density, viewZ, viewZ).negate().exp().oneMinus(); 20069}); 20070var exponentialHeightFogFactor = Fn(([density, height], builder) => { 20071 const viewZ = getViewZNode(builder); 20072 const distance3 = height.sub(positionWorld.y).max(0).toConst(); 20073 const m = distance3.mul(viewZ).toConst(); 20074 return density.mul(density, m, m).negate().exp().oneMinus(); 20075}); 20076var fog = Fn(([color3, factor]) => { 20077 return vec4(factor.toFloat().mix(output.rgb, color3.toVec3()), output.a); 20078}); 20079var min = null; 20080var max = null; 20081var RangeNode = class extends Node2 { 20082 static get type() { 20083 return "RangeNode"; 20084 } 20085 /** 20086 * Constructs a new range node. 20087 * 20088 * @param {Node<any>} [minNode=float()] - A node defining the lower bound of the range. 20089 * @param {Node<any>} [maxNode=float()] - A node defining the upper bound of the range. 20090 */ 20091 constructor(minNode = float(), maxNode = float()) { 20092 super(); 20093 this.minNode = minNode; 20094 this.maxNode = maxNode; 20095 } 20096 /** 20097 * Returns the vector length which is computed based on the range definition. 20098 * 20099 * @param {NodeBuilder} builder - The current node builder. 20100 * @return {number} The vector length. 20101 */ 20102 getVectorLength(builder) { 20103 const minNode = this.getConstNode(this.minNode); 20104 const maxNode = this.getConstNode(this.maxNode); 20105 const minLength = builder.getTypeLength(getValueType(minNode.value)); 20106 const maxLength = builder.getTypeLength(getValueType(maxNode.value)); 20107 return minLength > maxLength ? minLength : maxLength; 20108 } 20109 /** 20110 * This method is overwritten since the node type is inferred from range definition. 20111 * 20112 * @param {NodeBuilder} builder - The current node builder. 20113 * @return {string} The node type. 20114 */ 20115 generateNodeType(builder) { 20116 return builder.object.count > 1 ? builder.getTypeFromLength(this.getVectorLength(builder)) : "float"; 20117 } 20118 /** 20119 * Returns a constant node from the given node by traversing it. 20120 * 20121 * @param {Node} node - The node to traverse. 20122 * @returns {Node} The constant node, if found. 20123 */ 20124 getConstNode(node) { 20125 let output3 = null; 20126 node.traverse((n) => { 20127 if (n.isConstNode === true) { 20128 output3 = n; 20129 } 20130 }); 20131 if (output3 === null) { 20132 throw new NodeError('THREE.TSL: No "ConstNode" found in node graph.', this.stackTrace); 20133 } 20134 return output3; 20135 } 20136 setup(builder) { 20137 const object = builder.object; 20138 let output3 = null; 20139 if (object.count > 1) { 20140 const minNode = this.getConstNode(this.minNode); 20141 const maxNode = this.getConstNode(this.maxNode); 20142 const minValue = minNode.value; 20143 const maxValue = maxNode.value; 20144 const minLength = builder.getTypeLength(getValueType(minValue)); 20145 const maxLength = builder.getTypeLength(getValueType(maxValue)); 20146 min = min || new Vector4(); 20147 max = max || new Vector4(); 20148 min.setScalar(0); 20149 max.setScalar(0); 20150 if (minLength === 1) min.setScalar(minValue); 20151 else if (minValue.isColor) min.set(minValue.r, minValue.g, minValue.b, 1); 20152 else min.set(minValue.x, minValue.y, minValue.z || 0, minValue.w || 0); 20153 if (maxLength === 1) max.setScalar(maxValue); 20154 else if (maxValue.isColor) max.set(maxValue.r, maxValue.g, maxValue.b, 1); 20155 else max.set(maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0); 20156 const stride = 4; 20157 const length3 = stride * object.count; 20158 const array3 = new Float32Array(length3); 20159 for (let i = 0; i < length3; i++) { 20160 const index = i % stride; 20161 const minElementValue = min.getComponent(index); 20162 const maxElementValue = max.getComponent(index); 20163 array3[i] = MathUtils.lerp(minElementValue, maxElementValue, Math.random()); 20164 } 20165 const nodeType = this.getNodeType(builder); 20166 const uniformBufferSize = object.count * 4 * 4; 20167 if (uniformBufferSize <= builder.getUniformBufferLimit()) { 20168 output3 = buffer(array3, "vec4", object.count).element(instanceIndex).convert(nodeType); 20169 } else { 20170 const bufferAttribute3 = new InstancedBufferAttribute(array3, 4); 20171 builder.geometry.setAttribute("__range" + this.id, bufferAttribute3); 20172 output3 = instancedBufferAttribute(bufferAttribute3).convert(nodeType); 20173 } 20174 } else { 20175 output3 = float(0); 20176 } 20177 return output3; 20178 } 20179}; 20180var range = /* @__PURE__ */ nodeProxy(RangeNode).setParameterLength(2); 20181var ComputeBuiltinNode = class extends Node2 { 20182 static get type() { 20183 return "ComputeBuiltinNode"; 20184 } 20185 /** 20186 * Constructs a new compute builtin node. 20187 * 20188 * @param {string} builtinName - The built-in name. 20189 * @param {string} nodeType - The node type. 20190 */ 20191 constructor(builtinName, nodeType) { 20192 super(nodeType); 20193 this._builtinName = builtinName; 20194 } 20195 /** 20196 * This method is overwritten since hash is derived from the built-in name. 20197 * 20198 * @param {NodeBuilder} builder - The current node builder. 20199 * @return {string} The hash. 20200 */ 20201 getHash(builder) { 20202 return this.getBuiltinName(builder); 20203 } 20204 /** 20205 * This method is overwritten since the node type is simply derived from `nodeType`.. 20206 * 20207 * @param {NodeBuilder} builder - The current node builder. 20208 * @return {string} The node type. 20209 */ 20210 generateNodeType() { 20211 return this.nodeType; 20212 } 20213 /** 20214 * Sets the builtin name. 20215 * 20216 * @param {string} builtinName - The built-in name. 20217 * @return {ComputeBuiltinNode} A reference to this node. 20218 */ 20219 setBuiltinName(builtinName) { 20220 this._builtinName = builtinName; 20221 return this; 20222 } 20223 /** 20224 * Returns the builtin name. 20225 * 20226 * @param {NodeBuilder} builder - The current node builder. 20227 * @return {string} The builtin name. 20228 */ 20229 getBuiltinName() { 20230 return this._builtinName; 20231 } 20232 /** 20233 * Whether the current node builder has the builtin or not. 20234 * 20235 * @param {NodeBuilder} builder - The current node builder. 20236 * @return {boolean} Whether the builder has the builtin or not. 20237 */ 20238 hasBuiltin(builder) { 20239 return builder.hasBuiltin(this._builtinName); 20240 } 20241 generate(builder, output3) { 20242 const builtinName = this.getBuiltinName(builder); 20243 const nodeType = this.getNodeType(builder); 20244 if (builder.shaderStage === "compute") { 20245 return builder.format(builtinName, nodeType, output3); 20246 } else { 20247 warn(`ComputeBuiltinNode: Compute built-in value ${builtinName} can not be accessed in the ${builder.shaderStage} stage`); 20248 return builder.generateConst(nodeType); 20249 } 20250 } 20251 serialize(data) { 20252 super.serialize(data); 20253 data.global = this.global; 20254 data._builtinName = this._builtinName; 20255 } 20256 deserialize(data) { 20257 super.deserialize(data); 20258 this.global = data.global; 20259 this._builtinName = data._builtinName; 20260 } 20261}; 20262var computeBuiltin = (name, nodeType) => new ComputeBuiltinNode(name, nodeType); 20263var numWorkgroups = /* @__PURE__ */ computeBuiltin("numWorkgroups", "uvec3"); 20264var workgroupId = /* @__PURE__ */ computeBuiltin("workgroupId", "uvec3"); 20265var globalId = /* @__PURE__ */ computeBuiltin("globalId", "uvec3"); 20266var localId = /* @__PURE__ */ computeBuiltin("localId", "uvec3"); 20267var subgroupSize = /* @__PURE__ */ computeBuiltin("subgroupSize", "uint"); 20268var BarrierNode = class extends Node2 { 20269 /** 20270 * Constructs a new barrier node. 20271 * 20272 * @param {string} scope - The scope defines the behavior of the node. 20273 */ 20274 constructor(scope) { 20275 super(); 20276 this.scope = scope; 20277 this.isBarrierNode = true; 20278 } 20279 setup(builder) { 20280 builder.allowEarlyReturns = false; 20281 builder.allowGlobalVariables = false; 20282 } 20283 generate(builder) { 20284 const { scope } = this; 20285 const { renderer } = builder; 20286 if (renderer.backend.isWebGLBackend === true) { 20287 builder.addFlowCode(` // ${scope}Barrier 20288`); 20289 } else { 20290 builder.addLineFlowCode(`${scope}Barrier()`, this); 20291 } 20292 } 20293}; 20294var barrier = nodeProxy(BarrierNode); 20295var workgroupBarrier = () => barrier("workgroup").toStack(); 20296var storageBarrier = () => barrier("storage").toStack(); 20297var textureBarrier = () => barrier("texture").toStack(); 20298var WorkgroupInfoElementNode = class extends ArrayElementNode { 20299 /** 20300 * Constructs a new workgroup info element node. 20301 * 20302 * @param {Node} workgroupInfoNode - The workgroup info node. 20303 * @param {Node} indexNode - The index node that defines the element access. 20304 */ 20305 constructor(workgroupInfoNode, indexNode) { 20306 super(workgroupInfoNode, indexNode); 20307 this.isWorkgroupInfoElementNode = true; 20308 } 20309 generate(builder, output3) { 20310 let snippet; 20311 const isAssignContext = builder.context.assign; 20312 snippet = super.generate(builder); 20313 if (isAssignContext !== true) { 20314 const type = this.getNodeType(builder); 20315 snippet = builder.format(snippet, type, output3); 20316 } 20317 return snippet; 20318 } 20319}; 20320var WorkgroupInfoNode = class extends Node2 { 20321 /** 20322 * Constructs a new buffer scoped to type scope. 20323 * 20324 * @param {string} scope - TODO. 20325 * @param {string} bufferType - The data type of a 'workgroup' scoped buffer element. 20326 * @param {number} [bufferCount=0] - The number of elements in the buffer. 20327 */ 20328 constructor(scope, bufferType, bufferCount = 0) { 20329 super(bufferType); 20330 this.bufferType = bufferType; 20331 this.bufferCount = bufferCount; 20332 this.isWorkgroupInfoNode = true; 20333 this.elementType = bufferType; 20334 this.scope = scope; 20335 this.name = ""; 20336 } 20337 /** 20338 * Sets the name of this node. 20339 * 20340 * @param {string} name - The name to set. 20341 * @return {WorkgroupInfoNode} A reference to this node. 20342 */ 20343 setName(name) { 20344 this.name = name; 20345 return this; 20346 } 20347 /** 20348 * Sets the name/label of this node. 20349 * 20350 * @deprecated 20351 * @param {string} name - The name to set. 20352 * @return {WorkgroupInfoNode} A reference to this node. 20353 */ 20354 label(name) { 20355 warn('TSL: "label()" has been deprecated. Use "setName()" instead.', new StackTrace()); 20356 return this.setName(name); 20357 } 20358 /** 20359 * Sets the scope of this node. 20360 * 20361 * @param {string} scope - The scope to set. 20362 * @return {WorkgroupInfoNode} A reference to this node. 20363 */ 20364 setScope(scope) { 20365 this.scope = scope; 20366 return this; 20367 } 20368 /** 20369 * The data type of the array buffer. 20370 * 20371 * @return {string} The element type. 20372 */ 20373 getElementType() { 20374 return this.elementType; 20375 } 20376 /** 20377 * Overwrites the default implementation since the input type 20378 * is inferred from the scope. 20379 * 20380 * @param {NodeBuilder} builder - The current node builder. 20381 * @return {string} The input type. 20382 */ 20383 getInputType() { 20384 return `${this.scope}Array`; 20385 } 20386 /** 20387 * This method can be used to access elements via an index node. 20388 * 20389 * @param {IndexNode} indexNode - indexNode. 20390 * @return {WorkgroupInfoElementNode} A reference to an element. 20391 */ 20392 element(indexNode) { 20393 return new WorkgroupInfoElementNode(this, indexNode); 20394 } 20395 generate(builder) { 20396 const name = this.name !== "" ? this.name : `${this.scope}Array_${this.id}`; 20397 return builder.getScopedArray(name, this.scope.toLowerCase(), this.bufferType, this.bufferCount); 20398 } 20399}; 20400var workgroupArray = (type, count) => new WorkgroupInfoNode("Workgroup", type, count); 20401var AtomicFunctionNode = class extends Node2 { 20402 static get type() { 20403 return "AtomicFunctionNode"; 20404 } 20405 /** 20406 * Constructs a new atomic function node. 20407 * 20408 * @param {string} method - The signature of the atomic function to construct. 20409 * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. 20410 * @param {Node} valueNode - The value that mutates the atomic variable. 20411 */ 20412 constructor(method, pointerNode, valueNode) { 20413 super("uint"); 20414 this.method = method; 20415 this.pointerNode = pointerNode; 20416 this.valueNode = valueNode; 20417 this.parents = true; 20418 } 20419 /** 20420 * Overwrites the default implementation to return the type of 20421 * the pointer node. 20422 * 20423 * @param {NodeBuilder} builder - The current node builder. 20424 * @return {string} The input type. 20425 */ 20426 getInputType(builder) { 20427 return this.pointerNode.getNodeType(builder); 20428 } 20429 /** 20430 * Overwritten since the node type is inferred from the input type. 20431 * 20432 * @param {NodeBuilder} builder - The current node builder. 20433 * @return {string} The node type. 20434 */ 20435 generateNodeType(builder) { 20436 return this.getInputType(builder); 20437 } 20438 generate(builder) { 20439 const properties = builder.getNodeProperties(this); 20440 const parents = properties.parents; 20441 const method = this.method; 20442 const type = this.getNodeType(builder); 20443 const inputType = this.getInputType(builder); 20444 const a = this.pointerNode; 20445 const b = this.valueNode; 20446 const params = []; 20447 params.push(`&${a.build(builder, inputType)}`); 20448 if (b !== null) { 20449 params.push(b.build(builder, inputType)); 20450 } 20451 const methodSnippet = `${builder.getMethod(method, type)}( ${params.join(", ")} )`; 20452 const isVoid = parents ? parents.length === 1 && parents[0].isStackNode === true : false; 20453 if (isVoid) { 20454 builder.addLineFlowCode(methodSnippet, this); 20455 } else { 20456 if (properties.constNode === void 0) { 20457 properties.constNode = expression(methodSnippet, type).toConst(); 20458 } 20459 return properties.constNode.build(builder); 20460 } 20461 } 20462}; 20463AtomicFunctionNode.ATOMIC_LOAD = "atomicLoad"; 20464AtomicFunctionNode.ATOMIC_STORE = "atomicStore"; 20465AtomicFunctionNode.ATOMIC_ADD = "atomicAdd"; 20466AtomicFunctionNode.ATOMIC_SUB = "atomicSub"; 20467AtomicFunctionNode.ATOMIC_MAX = "atomicMax"; 20468AtomicFunctionNode.ATOMIC_MIN = "atomicMin"; 20469AtomicFunctionNode.ATOMIC_AND = "atomicAnd"; 20470AtomicFunctionNode.ATOMIC_OR = "atomicOr"; 20471AtomicFunctionNode.ATOMIC_XOR = "atomicXor"; 20472var atomicNode = nodeProxy(AtomicFunctionNode); 20473var atomicFunc = (method, pointerNode, valueNode) => { 20474 return atomicNode(method, pointerNode, valueNode).toStack(); 20475}; 20476var atomicLoad = (pointerNode) => atomicFunc(AtomicFunctionNode.ATOMIC_LOAD, pointerNode, null); 20477var atomicStore = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode); 20478var atomicAdd = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode); 20479var atomicSub = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode); 20480var atomicMax = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode); 20481var atomicMin = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode); 20482var atomicAnd = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode); 20483var atomicOr = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode); 20484var atomicXor = (pointerNode, valueNode) => atomicFunc(AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode); 20485var SubgroupFunctionNode = class _SubgroupFunctionNode extends TempNode { 20486 static get type() { 20487 return "SubgroupFunctionNode"; 20488 } 20489 /** 20490 * Constructs a new function node. 20491 * 20492 * @param {string} method - The subgroup/wave intrinsic method to construct. 20493 * @param {Node} [aNode=null] - The method's first argument. 20494 * @param {Node} [bNode=null] - The method's second argument. 20495 */ 20496 constructor(method, aNode = null, bNode = null) { 20497 super(); 20498 this.method = method; 20499 this.aNode = aNode; 20500 this.bNode = bNode; 20501 } 20502 getInputType(builder) { 20503 const aType = this.aNode ? this.aNode.getNodeType(builder) : null; 20504 const bType = this.bNode ? this.bNode.getNodeType(builder) : null; 20505 const aLen = builder.isMatrix(aType) ? 0 : builder.getTypeLength(aType); 20506 const bLen = builder.isMatrix(bType) ? 0 : builder.getTypeLength(bType); 20507 if (aLen > bLen) { 20508 return aType; 20509 } else { 20510 return bType; 20511 } 20512 } 20513 generateNodeType(builder) { 20514 const method = this.method; 20515 if (method === _SubgroupFunctionNode.SUBGROUP_ELECT) { 20516 return "bool"; 20517 } else if (method === _SubgroupFunctionNode.SUBGROUP_BALLOT) { 20518 return "uvec4"; 20519 } else { 20520 return this.getInputType(builder); 20521 } 20522 } 20523 generate(builder, output3) { 20524 const method = this.method; 20525 const type = this.getNodeType(builder); 20526 const inputType = this.getInputType(builder); 20527 const a = this.aNode; 20528 const b = this.bNode; 20529 const params = []; 20530 if (method === _SubgroupFunctionNode.SUBGROUP_BROADCAST || method === _SubgroupFunctionNode.SUBGROUP_SHUFFLE || method === _SubgroupFunctionNode.QUAD_BROADCAST) { 20531 const bType = b.getNodeType(builder); 20532 params.push( 20533 a.build(builder, type), 20534 b.build(builder, bType === "float" ? "int" : type) 20535 ); 20536 } else if (method === _SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR || method === _SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN || method === _SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP) { 20537 params.push( 20538 a.build(builder, type), 20539 b.build(builder, "uint") 20540 ); 20541 } else { 20542 if (a !== null) params.push(a.build(builder, inputType)); 20543 if (b !== null) params.push(b.build(builder, inputType)); 20544 } 20545 const paramsString = params.length === 0 ? "()" : `( ${params.join(", ")} )`; 20546 return builder.format(`${builder.getMethod(method, type)}${paramsString}`, type, output3); 20547 } 20548 serialize(data) { 20549 super.serialize(data); 20550 data.method = this.method; 20551 } 20552 deserialize(data) { 20553 super.deserialize(data); 20554 this.method = data.method; 20555 } 20556}; 20557SubgroupFunctionNode.SUBGROUP_ELECT = "subgroupElect"; 20558SubgroupFunctionNode.SUBGROUP_BALLOT = "subgroupBallot"; 20559SubgroupFunctionNode.SUBGROUP_ADD = "subgroupAdd"; 20560SubgroupFunctionNode.SUBGROUP_INCLUSIVE_ADD = "subgroupInclusiveAdd"; 20561SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_AND = "subgroupExclusiveAdd"; 20562SubgroupFunctionNode.SUBGROUP_MUL = "subgroupMul"; 20563SubgroupFunctionNode.SUBGROUP_INCLUSIVE_MUL = "subgroupInclusiveMul"; 20564SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_MUL = "subgroupExclusiveMul"; 20565SubgroupFunctionNode.SUBGROUP_AND = "subgroupAnd"; 20566SubgroupFunctionNode.SUBGROUP_OR = "subgroupOr"; 20567SubgroupFunctionNode.SUBGROUP_XOR = "subgroupXor"; 20568SubgroupFunctionNode.SUBGROUP_MIN = "subgroupMin"; 20569SubgroupFunctionNode.SUBGROUP_MAX = "subgroupMax"; 20570SubgroupFunctionNode.SUBGROUP_ALL = "subgroupAll"; 20571SubgroupFunctionNode.SUBGROUP_ANY = "subgroupAny"; 20572SubgroupFunctionNode.SUBGROUP_BROADCAST_FIRST = "subgroupBroadcastFirst"; 20573SubgroupFunctionNode.QUAD_SWAP_X = "quadSwapX"; 20574SubgroupFunctionNode.QUAD_SWAP_Y = "quadSwapY"; 20575SubgroupFunctionNode.QUAD_SWAP_DIAGONAL = "quadSwapDiagonal"; 20576SubgroupFunctionNode.SUBGROUP_BROADCAST = "subgroupBroadcast"; 20577SubgroupFunctionNode.SUBGROUP_SHUFFLE = "subgroupShuffle"; 20578SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR = "subgroupShuffleXor"; 20579SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP = "subgroupShuffleUp"; 20580SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN = "subgroupShuffleDown"; 20581SubgroupFunctionNode.QUAD_BROADCAST = "quadBroadcast"; 20582var subgroupElect = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ELECT).setParameterLength(0); 20583var subgroupBallot = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BALLOT).setParameterLength(1); 20584var subgroupAdd = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ADD).setParameterLength(1); 20585var subgroupInclusiveAdd = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_INCLUSIVE_ADD).setParameterLength(1); 20586var subgroupExclusiveAdd = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_AND).setParameterLength(1); 20587var subgroupMul = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MUL).setParameterLength(1); 20588var subgroupInclusiveMul = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_INCLUSIVE_MUL).setParameterLength(1); 20589var subgroupExclusiveMul = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_MUL).setParameterLength(1); 20590var subgroupAnd = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_AND).setParameterLength(1); 20591var subgroupOr = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_OR).setParameterLength(1); 20592var subgroupXor = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_XOR).setParameterLength(1); 20593var subgroupMin = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MIN).setParameterLength(1); 20594var subgroupMax = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MAX).setParameterLength(1); 20595var subgroupAll = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ALL).setParameterLength(0); 20596var subgroupAny = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ANY).setParameterLength(0); 20597var subgroupBroadcastFirst = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BROADCAST_FIRST).setParameterLength(2); 20598var quadSwapX = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_X).setParameterLength(1); 20599var quadSwapY = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_Y).setParameterLength(1); 20600var quadSwapDiagonal = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_DIAGONAL).setParameterLength(1); 20601var subgroupBroadcast = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BROADCAST).setParameterLength(2); 20602var subgroupShuffle = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE).setParameterLength(2); 20603var subgroupShuffleXor = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR).setParameterLength(2); 20604var subgroupShuffleUp = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP).setParameterLength(2); 20605var subgroupShuffleDown = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN).setParameterLength(2); 20606var quadBroadcast = /* @__PURE__ */ nodeProxyIntent(SubgroupFunctionNode, SubgroupFunctionNode.QUAD_BROADCAST).setParameterLength(1); 20607var uniformsLib; 20608function getLightData(light) { 20609 uniformsLib = uniformsLib || /* @__PURE__ */ new WeakMap(); 20610 let uniforms = uniformsLib.get(light); 20611 if (uniforms === void 0) uniformsLib.set(light, uniforms = {}); 20612 return uniforms; 20613} 20614function lightShadowMatrix(light) { 20615 const data = getLightData(light); 20616 return data.shadowMatrix || (data.shadowMatrix = uniform("mat4").setGroup(renderGroup).onRenderUpdate((frame) => { 20617 if (light.castShadow !== true || frame.renderer.shadowMap.enabled === false) { 20618 if (light.shadow.camera.coordinateSystem !== frame.camera.coordinateSystem) { 20619 light.shadow.camera.coordinateSystem = frame.camera.coordinateSystem; 20620 light.shadow.camera.updateProjectionMatrix(); 20621 } 20622 light.shadow.updateMatrices(light); 20623 } 20624 return light.shadow.matrix; 20625 })); 20626} 20627function lightProjectionUV(light, position = positionWorld) { 20628 const spotLightCoord = lightShadowMatrix(light).mul(position); 20629 const projectionUV = spotLightCoord.xyz.div(spotLightCoord.w); 20630 return projectionUV; 20631} 20632function lightPosition(light) { 20633 const data = getLightData(light); 20634 return data.position || (data.position = uniform(new Vector3()).setGroup(renderGroup).onRenderUpdate((_, self2) => self2.value.setFromMatrixPosition(light.matrixWorld))); 20635} 20636function lightTargetPosition(light) { 20637 const data = getLightData(light); 20638 return data.targetPosition || (data.targetPosition = uniform(new Vector3()).setGroup(renderGroup).onRenderUpdate((_, self2) => self2.value.setFromMatrixPosition(light.target.matrixWorld))); 20639} 20640function lightViewPosition(light) { 20641 const data = getLightData(light); 20642 return data.viewPosition || (data.viewPosition = uniform(new Vector3()).setGroup(renderGroup).onRenderUpdate(({ camera }, self2) => { 20643 self2.value = self2.value || new Vector3(); 20644 self2.value.setFromMatrixPosition(light.matrixWorld); 20645 self2.value.applyMatrix4(camera.matrixWorldInverse); 20646 })); 20647} 20648var lightTargetDirection = (light) => cameraViewMatrix.transformDirection(lightPosition(light).sub(lightTargetPosition(light))); 20649var sortLights = (lights3) => { 20650 return lights3.sort((a, b) => a.id - b.id); 20651}; 20652var getLightNodeById = (id, lightNodes) => { 20653 for (const lightNode of lightNodes) { 20654 if (lightNode.isAnalyticLightNode && lightNode.light.id === id) { 20655 return lightNode; 20656 } 20657 } 20658 return null; 20659}; 20660var _lightsNodeRef = /* @__PURE__ */ new WeakMap(); 20661var _hashData = []; 20662var LightsNode = class extends Node2 { 20663 static get type() { 20664 return "LightsNode"; 20665 } 20666 /** 20667 * Constructs a new lights node. 20668 */ 20669 constructor() { 20670 super("vec3"); 20671 this.totalDiffuseNode = property("vec3", "totalDiffuse"); 20672 this.totalSpecularNode = property("vec3", "totalSpecular"); 20673 this.outgoingLightNode = property("vec3", "outgoingLight"); 20674 this._lights = []; 20675 this._lightNodes = null; 20676 this._lightNodesHash = null; 20677 this.global = true; 20678 } 20679 /** 20680 * Overwrites the default {@link Node#customCacheKey} implementation by including 20681 * light data into the cache key. 20682 * 20683 * @return {number} The custom cache key. 20684 */ 20685 customCacheKey() { 20686 const lights3 = this._lights; 20687 for (let i = 0; i < lights3.length; i++) { 20688 const light = lights3[i]; 20689 _hashData.push(light.id); 20690 _hashData.push(light.castShadow ? 1 : 0); 20691 if (light.isSpotLight === true) { 20692 const hashMap = light.map !== null ? light.map.id : -1; 20693 const hashColorNode = light.colorNode ? light.colorNode.getCacheKey() : -1; 20694 _hashData.push(hashMap, hashColorNode); 20695 } 20696 } 20697 const cacheKey = hashArray(_hashData); 20698 _hashData.length = 0; 20699 return cacheKey; 20700 } 20701 /** 20702 * Computes a hash value for identifying the current light nodes setup. 20703 * 20704 * @param {NodeBuilder} builder - A reference to the current node builder. 20705 * @return {string} The computed hash. 20706 */ 20707 getHash(builder) { 20708 if (this._lightNodesHash === null) { 20709 if (this._lightNodes === null) this.setupLightsNode(builder); 20710 const hash3 = []; 20711 for (const lightNode of this._lightNodes) { 20712 hash3.push(lightNode.getHash()); 20713 } 20714 this._lightNodesHash = "lights-" + hash3.join(","); 20715 } 20716 return this._lightNodesHash; 20717 } 20718 analyze(builder) { 20719 const properties = builder.getNodeProperties(this); 20720 for (const node of properties.nodes) { 20721 node.build(builder); 20722 } 20723 properties.outputNode.build(builder); 20724 } 20725 /** 20726 * Creates lighting nodes for each scene light. This makes it possible to further 20727 * process lights in the node system. 20728 * 20729 * @param {NodeBuilder} builder - A reference to the current node builder. 20730 */ 20731 setupLightsNode(builder) { 20732 const lightNodes = []; 20733 const previousLightNodes = this._lightNodes; 20734 const lights3 = sortLights(this._lights); 20735 const nodeLibrary = builder.renderer.library; 20736 for (const light of lights3) { 20737 if (light.isNode) { 20738 lightNodes.push(nodeObject(light)); 20739 } else { 20740 let lightNode = null; 20741 if (previousLightNodes !== null) { 20742 lightNode = getLightNodeById(light.id, previousLightNodes); 20743 } 20744 if (lightNode === null) { 20745 const lightNodeClass = nodeLibrary.getLightNodeClass(light.constructor); 20746 if (lightNodeClass === null) { 20747 warn(`LightsNode.setupNodeLights: Light node not found for ${light.constructor.name}`); 20748 continue; 20749 } 20750 if (_lightsNodeRef.has(light) === false) { 20751 _lightsNodeRef.set(light, new lightNodeClass(light)); 20752 } 20753 lightNode = _lightsNodeRef.get(light); 20754 } 20755 lightNodes.push(lightNode); 20756 } 20757 } 20758 this._lightNodes = lightNodes; 20759 } 20760 /** 20761 * Sets up a direct light in the lighting model. 20762 * 20763 * @param {Object} builder - The builder object containing the context and stack. 20764 * @param {Object} lightNode - The light node. 20765 * @param {Object} lightData - The light object containing color and direction properties. 20766 */ 20767 setupDirectLight(builder, lightNode, lightData) { 20768 const { lightingModel, reflectedLight } = builder.context; 20769 lightingModel.direct({ 20770 ...lightData, 20771 lightNode, 20772 reflectedLight 20773 }, builder); 20774 } 20775 setupDirectRectAreaLight(builder, lightNode, lightData) { 20776 const { lightingModel, reflectedLight } = builder.context; 20777 lightingModel.directRectArea({ 20778 ...lightData, 20779 lightNode, 20780 reflectedLight 20781 }, builder); 20782 } 20783 /** 20784 * Setups the internal lights by building all respective 20785 * light nodes. 20786 * 20787 * @param {NodeBuilder} builder - A reference to the current node builder. 20788 * @param {Array<LightingNode>} lightNodes - An array of lighting nodes. 20789 */ 20790 setupLights(builder, lightNodes) { 20791 for (const lightNode of lightNodes) { 20792 lightNode.build(builder); 20793 } 20794 } 20795 getLightNodes(builder) { 20796 if (this._lightNodes === null) this.setupLightsNode(builder); 20797 return this._lightNodes; 20798 } 20799 /** 20800 * The implementation makes sure that for each light in the scene 20801 * there is a corresponding light node. By building the light nodes 20802 * and evaluating the lighting model the outgoing light is computed. 20803 * 20804 * @param {NodeBuilder} builder - A reference to the current node builder. 20805 * @return {Node<vec3>} A node representing the outgoing light. 20806 */ 20807 setup(builder) { 20808 const currentLightsNode = builder.lightsNode; 20809 builder.lightsNode = this; 20810 let outgoingLightNode = this.outgoingLightNode; 20811 const context3 = builder.context; 20812 const lightingModel = context3.lightingModel; 20813 const properties = builder.getNodeProperties(this); 20814 if (lightingModel) { 20815 const { totalDiffuseNode, totalSpecularNode } = this; 20816 context3.outgoingLight = outgoingLightNode; 20817 const stack3 = builder.addStack(); 20818 properties.nodes = stack3.nodes; 20819 lightingModel.start(builder); 20820 const { backdrop, backdropAlpha } = context3; 20821 const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context3.reflectedLight; 20822 let totalDiffuse = directDiffuse.add(indirectDiffuse); 20823 if (backdrop !== null) { 20824 if (backdropAlpha !== null) { 20825 totalDiffuse = vec3(backdropAlpha.mix(totalDiffuse, backdrop)); 20826 } else { 20827 totalDiffuse = vec3(backdrop); 20828 } 20829 } 20830 totalDiffuseNode.assign(totalDiffuse); 20831 totalSpecularNode.assign(directSpecular.add(indirectSpecular)); 20832 outgoingLightNode.assign(totalDiffuseNode.add(totalSpecularNode)); 20833 lightingModel.finish(builder); 20834 outgoingLightNode = outgoingLightNode.bypass(builder.removeStack()); 20835 } else { 20836 properties.nodes = []; 20837 } 20838 builder.lightsNode = currentLightsNode; 20839 return outgoingLightNode; 20840 } 20841 /** 20842 * Configures this node with an array of lights. 20843 * 20844 * @param {Array<Light>} lights - An array of lights. 20845 * @return {LightsNode} A reference to this node. 20846 */ 20847 setLights(lights3) { 20848 this._lights = lights3; 20849 this._lightNodes = null; 20850 this._lightNodesHash = null; 20851 return this; 20852 } 20853 /** 20854 * Returns an array of the scene's lights. 20855 * 20856 * @return {Array<Light>} The scene's lights. 20857 */ 20858 getLights() { 20859 return this._lights; 20860 } 20861 /** 20862 * Whether the scene has lights or not. 20863 * 20864 * @type {boolean} 20865 */ 20866 get hasLights() { 20867 return this._lights.length > 0; 20868 } 20869}; 20870var lights = (lights3 = []) => new LightsNode().setLights(lights3); 20871var ShadowBaseNode = class extends Node2 { 20872 static get type() { 20873 return "ShadowBaseNode"; 20874 } 20875 /** 20876 * Constructs a new shadow base node. 20877 * 20878 * @param {Light} light - The shadow casting light. 20879 */ 20880 constructor(light) { 20881 super(); 20882 this.light = light; 20883 this.updateBeforeType = NodeUpdateType.RENDER; 20884 this.isShadowBaseNode = true; 20885 } 20886 /** 20887 * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. 20888 * 20889 * @param {NodeBuilder} object - A configuration object that must at least hold a material reference. 20890 */ 20891 setupShadowPosition({ context: context3, material }) { 20892 shadowPositionWorld.assign(material.receivedShadowPositionNode || context3.shadowPositionWorld || positionWorld); 20893 } 20894}; 20895var shadowPositionWorld = /* @__PURE__ */ property("vec3", "shadowPositionWorld"); 20896function saveRendererState(renderer, state = {}) { 20897 state.toneMapping = renderer.toneMapping; 20898 state.toneMappingExposure = renderer.toneMappingExposure; 20899 state.outputColorSpace = renderer.outputColorSpace; 20900 state.renderTarget = renderer.getRenderTarget(); 20901 state.activeCubeFace = renderer.getActiveCubeFace(); 20902 state.activeMipmapLevel = renderer.getActiveMipmapLevel(); 20903 state.renderObjectFunction = renderer.getRenderObjectFunction(); 20904 state.pixelRatio = renderer.getPixelRatio(); 20905 state.mrt = renderer.getMRT(); 20906 state.clearColor = renderer.getClearColor(state.clearColor || new Color()); 20907 state.clearAlpha = renderer.getClearAlpha(); 20908 state.autoClear = renderer.autoClear; 20909 state.scissorTest = renderer.getScissorTest(); 20910 return state; 20911} 20912function resetRendererState(renderer, state) { 20913 state = saveRendererState(renderer, state); 20914 renderer.setMRT(null); 20915 renderer.setRenderObjectFunction(null); 20916 renderer.setClearColor(0, 1); 20917 renderer.autoClear = true; 20918 return state; 20919} 20920function restoreRendererState(renderer, state) { 20921 renderer.toneMapping = state.toneMapping; 20922 renderer.toneMappingExposure = state.toneMappingExposure; 20923 renderer.outputColorSpace = state.outputColorSpace; 20924 renderer.setRenderTarget(state.renderTarget, state.activeCubeFace, state.activeMipmapLevel); 20925 renderer.setRenderObjectFunction(state.renderObjectFunction); 20926 renderer.setPixelRatio(state.pixelRatio); 20927 renderer.setMRT(state.mrt); 20928 renderer.setClearColor(state.clearColor, state.clearAlpha); 20929 renderer.autoClear = state.autoClear; 20930 renderer.setScissorTest(state.scissorTest); 20931} 20932function saveSceneState(scene, state = {}) { 20933 state.background = scene.background; 20934 state.backgroundNode = scene.backgroundNode; 20935 state.overrideMaterial = scene.overrideMaterial; 20936 return state; 20937} 20938function resetSceneState(scene, state) { 20939 state = saveSceneState(scene, state); 20940 scene.background = null; 20941 scene.backgroundNode = null; 20942 scene.overrideMaterial = null; 20943 return state; 20944} 20945function restoreSceneState(scene, state) { 20946 scene.background = state.background; 20947 scene.backgroundNode = state.backgroundNode; 20948 scene.overrideMaterial = state.overrideMaterial; 20949} 20950function resetRendererAndSceneState(renderer, scene, state) { 20951 state = resetRendererState(renderer, state); 20952 state = resetSceneState(scene, state); 20953 return state; 20954} 20955function restoreRendererAndSceneState(renderer, scene, state) { 20956 restoreRendererState(renderer, state); 20957 restoreSceneState(scene, state); 20958} 20959var shadowMaterialLib = /* @__PURE__ */ new WeakMap(); 20960var BasicShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, shadowCoord, depthLayer }) => { 20961 let basic = texture(depthTexture, shadowCoord.xy).setName("t_basic"); 20962 if (depthTexture.isArrayTexture) { 20963 basic = basic.depth(depthLayer); 20964 } 20965 return basic.compare(shadowCoord.z); 20966}); 20967var PCFShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, shadowCoord, shadow: shadow3, depthLayer }) => { 20968 const depthCompare = (uv3, compare5) => { 20969 let depth3 = texture(depthTexture, uv3); 20970 if (depthTexture.isArrayTexture) { 20971 depth3 = depth3.depth(depthLayer); 20972 } 20973 return depth3.compare(compare5); 20974 }; 20975 const mapSize = reference("mapSize", "vec2", shadow3).setGroup(renderGroup); 20976 const radius = reference("radius", "float", shadow3).setGroup(renderGroup); 20977 const texelSize = vec2(1).div(mapSize); 20978 const radiusScaled = radius.mul(texelSize.x); 20979 const phi = interleavedGradientNoise(screenCoordinate.xy).mul(6.28318530718); 20980 return add( 20981 depthCompare(shadowCoord.xy.add(vogelDiskSample(0, 5, phi).mul(radiusScaled)), shadowCoord.z), 20982 depthCompare(shadowCoord.xy.add(vogelDiskSample(1, 5, phi).mul(radiusScaled)), shadowCoord.z), 20983 depthCompare(shadowCoord.xy.add(vogelDiskSample(2, 5, phi).mul(radiusScaled)), shadowCoord.z), 20984 depthCompare(shadowCoord.xy.add(vogelDiskSample(3, 5, phi).mul(radiusScaled)), shadowCoord.z), 20985 depthCompare(shadowCoord.xy.add(vogelDiskSample(4, 5, phi).mul(radiusScaled)), shadowCoord.z) 20986 ).mul(1 / 5); 20987}); 20988var PCFSoftShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, shadowCoord, shadow: shadow3, depthLayer }) => { 20989 const depthCompare = (uv4, compare5) => { 20990 let depth3 = texture(depthTexture, uv4); 20991 if (depthTexture.isArrayTexture) { 20992 depth3 = depth3.depth(depthLayer); 20993 } 20994 return depth3.compare(compare5); 20995 }; 20996 const mapSize = reference("mapSize", "vec2", shadow3).setGroup(renderGroup); 20997 const texelSize = vec2(1).div(mapSize); 20998 const dx = texelSize.x; 20999 const dy = texelSize.y; 21000 const uv3 = shadowCoord.xy; 21001 const f = fract(uv3.mul(mapSize).add(0.5)); 21002 uv3.subAssign(f.mul(texelSize)); 21003 return add( 21004 depthCompare(uv3, shadowCoord.z), 21005 depthCompare(uv3.add(vec2(dx, 0)), shadowCoord.z), 21006 depthCompare(uv3.add(vec2(0, dy)), shadowCoord.z), 21007 depthCompare(uv3.add(texelSize), shadowCoord.z), 21008 mix( 21009 depthCompare(uv3.add(vec2(dx.negate(), 0)), shadowCoord.z), 21010 depthCompare(uv3.add(vec2(dx.mul(2), 0)), shadowCoord.z), 21011 f.x 21012 ), 21013 mix( 21014 depthCompare(uv3.add(vec2(dx.negate(), dy)), shadowCoord.z), 21015 depthCompare(uv3.add(vec2(dx.mul(2), dy)), shadowCoord.z), 21016 f.x 21017 ), 21018 mix( 21019 depthCompare(uv3.add(vec2(0, dy.negate())), shadowCoord.z), 21020 depthCompare(uv3.add(vec2(0, dy.mul(2))), shadowCoord.z), 21021 f.y 21022 ), 21023 mix( 21024 depthCompare(uv3.add(vec2(dx, dy.negate())), shadowCoord.z), 21025 depthCompare(uv3.add(vec2(dx, dy.mul(2))), shadowCoord.z), 21026 f.y 21027 ), 21028 mix( 21029 mix( 21030 depthCompare(uv3.add(vec2(dx.negate(), dy.negate())), shadowCoord.z), 21031 depthCompare(uv3.add(vec2(dx.mul(2), dy.negate())), shadowCoord.z), 21032 f.x 21033 ), 21034 mix( 21035 depthCompare(uv3.add(vec2(dx.negate(), dy.mul(2))), shadowCoord.z), 21036 depthCompare(uv3.add(vec2(dx.mul(2), dy.mul(2))), shadowCoord.z), 21037 f.x 21038 ), 21039 f.y 21040 ) 21041 ).mul(1 / 9); 21042}); 21043var VSMShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, shadowCoord, depthLayer }, builder) => { 21044 let distribution = texture(depthTexture).sample(shadowCoord.xy); 21045 if (depthTexture.isArrayTexture) { 21046 distribution = distribution.depth(depthLayer); 21047 } 21048 distribution = distribution.rg; 21049 const mean = distribution.x; 21050 const variance = max$1(1e-7, distribution.y.mul(distribution.y)); 21051 const hardShadow = builder.renderer.reversedDepthBuffer ? step(mean, shadowCoord.z) : step(shadowCoord.z, mean); 21052 const output3 = float(1).toVar(); 21053 If(hardShadow.notEqual(1), () => { 21054 const d = shadowCoord.z.sub(mean); 21055 let p_max = variance.div(variance.add(d.mul(d))); 21056 p_max = clamp(sub(p_max, 0.3).div(0.65)); 21057 output3.assign(max$1(hardShadow, p_max)); 21058 }); 21059 return output3; 21060}); 21061var getShadowMaterial = (light) => { 21062 let material = shadowMaterialLib.get(light); 21063 if (material === void 0) { 21064 material = new NodeMaterial(); 21065 material.colorNode = vec4(0, 0, 0, 1); 21066 material.isShadowPassMaterial = true; 21067 material.name = "ShadowMaterial"; 21068 material.blending = NoBlending; 21069 material.fog = false; 21070 shadowMaterialLib.set(light, material); 21071 } 21072 return material; 21073}; 21074var disposeShadowMaterial = (light) => { 21075 const material = shadowMaterialLib.get(light); 21076 if (material !== void 0) { 21077 material.dispose(); 21078 shadowMaterialLib.delete(light); 21079 } 21080}; 21081var _shadowRenderObjectLibrary = /* @__PURE__ */ new ChainMap(); 21082var _shadowRenderObjectKeys = []; 21083var getShadowRenderObjectFunction = (renderer, shadow3, shadowType, useVelocity) => { 21084 _shadowRenderObjectKeys[0] = renderer; 21085 _shadowRenderObjectKeys[1] = shadow3; 21086 let renderObjectFunction = _shadowRenderObjectLibrary.get(_shadowRenderObjectKeys); 21087 if (renderObjectFunction === void 0 || (renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity)) { 21088 renderObjectFunction = (object, scene, _camera2, geometry, material, group, ...params) => { 21089 if (object.castShadow === true || object.receiveShadow && shadowType === VSMShadowMap) { 21090 if (useVelocity) { 21091 getDataFromObject(object).useVelocity = true; 21092 } 21093 object.onBeforeShadow(renderer, object, _camera2, shadow3.camera, geometry, scene.overrideMaterial, group); 21094 renderer.renderObject(object, scene, _camera2, geometry, material, group, ...params); 21095 object.onAfterShadow(renderer, object, _camera2, shadow3.camera, geometry, scene.overrideMaterial, group); 21096 } 21097 }; 21098 renderObjectFunction.shadowType = shadowType; 21099 renderObjectFunction.useVelocity = useVelocity; 21100 _shadowRenderObjectLibrary.set(_shadowRenderObjectKeys, renderObjectFunction); 21101 } 21102 _shadowRenderObjectKeys[0] = null; 21103 _shadowRenderObjectKeys[1] = null; 21104 return renderObjectFunction; 21105}; 21106var VSMPassVertical = /* @__PURE__ */ Fn(({ samples, radius, size: size3, shadowPass, depthLayer }) => { 21107 const mean = float(0).toVar("meanVertical"); 21108 const squaredMean = float(0).toVar("squareMeanVertical"); 21109 const uvStride = samples.lessThanEqual(float(1)).select(float(0), float(2).div(samples.sub(1))); 21110 const uvStart = samples.lessThanEqual(float(1)).select(float(0), float(-1)); 21111 Loop({ start: int(0), end: int(samples), type: "int", condition: "<" }, ({ i }) => { 21112 const uvOffset = uvStart.add(float(i).mul(uvStride)); 21113 let depth3 = shadowPass.sample(add(screenCoordinate.xy, vec2(0, uvOffset).mul(radius)).div(size3)); 21114 if (shadowPass.value.isArrayTexture) { 21115 depth3 = depth3.depth(depthLayer); 21116 } 21117 depth3 = depth3.x; 21118 mean.addAssign(depth3); 21119 squaredMean.addAssign(depth3.mul(depth3)); 21120 }); 21121 mean.divAssign(samples); 21122 squaredMean.divAssign(samples); 21123 const std_dev = sqrt(squaredMean.sub(mean.mul(mean)).max(0)); 21124 return vec2(mean, std_dev); 21125}); 21126var VSMPassHorizontal = /* @__PURE__ */ Fn(({ samples, radius, size: size3, shadowPass, depthLayer }) => { 21127 const mean = float(0).toVar("meanHorizontal"); 21128 const squaredMean = float(0).toVar("squareMeanHorizontal"); 21129 const uvStride = samples.lessThanEqual(float(1)).select(float(0), float(2).div(samples.sub(1))); 21130 const uvStart = samples.lessThanEqual(float(1)).select(float(0), float(-1)); 21131 Loop({ start: int(0), end: int(samples), type: "int", condition: "<" }, ({ i }) => { 21132 const uvOffset = uvStart.add(float(i).mul(uvStride)); 21133 let distribution = shadowPass.sample(add(screenCoordinate.xy, vec2(uvOffset, 0).mul(radius)).div(size3)); 21134 if (shadowPass.value.isArrayTexture) { 21135 distribution = distribution.depth(depthLayer); 21136 } 21137 mean.addAssign(distribution.x); 21138 squaredMean.addAssign(add(distribution.y.mul(distribution.y), distribution.x.mul(distribution.x))); 21139 }); 21140 mean.divAssign(samples); 21141 squaredMean.divAssign(samples); 21142 const std_dev = sqrt(squaredMean.sub(mean.mul(mean)).max(0)); 21143 return vec2(mean, std_dev); 21144}); 21145var _shadowFilterLib = [BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilter, VSMShadowFilter]; 21146var _rendererState; 21147var _quadMesh = /* @__PURE__ */ new QuadMesh(); 21148var ShadowNode = class extends ShadowBaseNode { 21149 static get type() { 21150 return "ShadowNode"; 21151 } 21152 /** 21153 * Constructs a new shadow node. 21154 * 21155 * @param {Light} light - The shadow casting light. 21156 * @param {?LightShadow} [shadow=null] - An optional light shadow. 21157 */ 21158 constructor(light, shadow3 = null) { 21159 super(light); 21160 this.shadow = shadow3 || light.shadow; 21161 this.shadowMap = null; 21162 this.vsmShadowMapVertical = null; 21163 this.vsmShadowMapHorizontal = null; 21164 this.vsmMaterialVertical = null; 21165 this.vsmMaterialHorizontal = null; 21166 this._node = null; 21167 this._currentShadowType = null; 21168 this._cameraFrameId = /* @__PURE__ */ new WeakMap(); 21169 this.isShadowNode = true; 21170 this.depthLayer = 0; 21171 } 21172 /** 21173 * Setups the shadow filtering. 21174 * 21175 * @param {NodeBuilder} builder - A reference to the current node builder. 21176 * @param {Object} inputs - A configuration object that defines the shadow filtering. 21177 * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. 21178 * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. 21179 * @param {Node<vec3>} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. 21180 * @param {LightShadow} inputs.shadow - The light shadow. 21181 * @return {Node<float>} The result node of the shadow filtering. 21182 */ 21183 setupShadowFilter(builder, { filterFn, depthTexture, shadowCoord, shadow: shadow3, depthLayer }) { 21184 const frustumTest = shadowCoord.x.greaterThanEqual(0).and(shadowCoord.x.lessThanEqual(1)).and(shadowCoord.y.greaterThanEqual(0)).and(shadowCoord.y.lessThanEqual(1)).and(shadowCoord.z.lessThanEqual(1)); 21185 const shadowNode = filterFn({ depthTexture, shadowCoord, shadow: shadow3, depthLayer }); 21186 return frustumTest.select(shadowNode, float(1)); 21187 } 21188 /** 21189 * Setups the shadow coordinates. 21190 * 21191 * @param {NodeBuilder} builder - A reference to the current node builder. 21192 * @param {Node<vec3>} shadowPosition - A node representing the shadow position. 21193 * @return {Node<vec3>} The shadow coordinates. 21194 */ 21195 setupShadowCoord(builder, shadowPosition) { 21196 const { shadow: shadow3 } = this; 21197 const { renderer } = builder; 21198 const bias = shadow3.biasNode || reference("bias", "float", shadow3).setGroup(renderGroup); 21199 let shadowCoord = shadowPosition; 21200 let coordZ; 21201 if (shadow3.camera.isOrthographicCamera || renderer.logarithmicDepthBuffer !== true) { 21202 shadowCoord = shadowCoord.xyz.div(shadowCoord.w); 21203 coordZ = shadowCoord.z; 21204 } else { 21205 const w = shadowCoord.w; 21206 shadowCoord = shadowCoord.xy.div(w); 21207 const cameraNearLocal = reference("near", "float", shadow3.camera).setGroup(renderGroup); 21208 const cameraFarLocal = reference("far", "float", shadow3.camera).setGroup(renderGroup); 21209 coordZ = viewZToLogarithmicDepth(w.negate(), cameraNearLocal, cameraFarLocal); 21210 } 21211 shadowCoord = vec3( 21212 shadowCoord.x, 21213 shadowCoord.y.oneMinus(), 21214 // follow webgpu standards 21215 renderer.reversedDepthBuffer ? coordZ.sub(bias) : coordZ.add(bias) 21216 ); 21217 return shadowCoord; 21218 } 21219 /** 21220 * Returns the shadow filtering function for the given shadow type. 21221 * 21222 * @param {number} type - The shadow type. 21223 * @return {Function} The filtering function. 21224 */ 21225 getShadowFilterFn(type) { 21226 return _shadowFilterLib[type]; 21227 } 21228 setupRenderTarget(shadow3, builder) { 21229 const depthTexture = new DepthTexture(shadow3.mapSize.width, shadow3.mapSize.height); 21230 depthTexture.name = "ShadowDepthTexture"; 21231 depthTexture.compareFunction = builder.renderer.reversedDepthBuffer ? GreaterEqualCompare : LessEqualCompare; 21232 const shadowMap = builder.createRenderTarget(shadow3.mapSize.width, shadow3.mapSize.height); 21233 shadowMap.texture.name = "ShadowMap"; 21234 shadowMap.texture.type = shadow3.mapType; 21235 shadowMap.depthTexture = depthTexture; 21236 return { shadowMap, depthTexture }; 21237 } 21238 /** 21239 * Setups the shadow output node. 21240 * 21241 * @param {NodeBuilder} builder - A reference to the current node builder. 21242 * @return {Node<vec3>} The shadow output node. 21243 */ 21244 setupShadow(builder) { 21245 const { renderer, camera } = builder; 21246 const { light, shadow: shadow3 } = this; 21247 const { depthTexture, shadowMap } = this.setupRenderTarget(shadow3, builder); 21248 const shadowMapType = renderer.shadowMap.type; 21249 const hasTextureCompare = renderer.hasCompatibility(Compatibility.TEXTURE_COMPARE); 21250 if ((shadowMapType === PCFShadowMap || shadowMapType === PCFSoftShadowMap) && hasTextureCompare) { 21251 depthTexture.minFilter = LinearFilter; 21252 depthTexture.magFilter = LinearFilter; 21253 } else { 21254 depthTexture.minFilter = NearestFilter; 21255 depthTexture.magFilter = NearestFilter; 21256 } 21257 shadow3.camera.coordinateSystem = camera.coordinateSystem; 21258 shadow3.camera.updateProjectionMatrix(); 21259 if (shadowMapType === VSMShadowMap && shadow3.isPointLightShadow !== true) { 21260 depthTexture.compareFunction = null; 21261 if (shadowMap.depth > 1) { 21262 if (!shadowMap._vsmShadowMapVertical) { 21263 shadowMap._vsmShadowMapVertical = builder.createRenderTarget(shadow3.mapSize.width, shadow3.mapSize.height, { format: RGFormat, type: HalfFloatType, depth: shadowMap.depth, depthBuffer: false }); 21264 shadowMap._vsmShadowMapVertical.texture.name = "VSMVertical"; 21265 } 21266 this.vsmShadowMapVertical = shadowMap._vsmShadowMapVertical; 21267 if (!shadowMap._vsmShadowMapHorizontal) { 21268 shadowMap._vsmShadowMapHorizontal = builder.createRenderTarget(shadow3.mapSize.width, shadow3.mapSize.height, { format: RGFormat, type: HalfFloatType, depth: shadowMap.depth, depthBuffer: false }); 21269 shadowMap._vsmShadowMapHorizontal.texture.name = "VSMHorizontal"; 21270 } 21271 this.vsmShadowMapHorizontal = shadowMap._vsmShadowMapHorizontal; 21272 } else { 21273 this.vsmShadowMapVertical = builder.createRenderTarget(shadow3.mapSize.width, shadow3.mapSize.height, { format: RGFormat, type: HalfFloatType, depthBuffer: false }); 21274 this.vsmShadowMapHorizontal = builder.createRenderTarget(shadow3.mapSize.width, shadow3.mapSize.height, { format: RGFormat, type: HalfFloatType, depthBuffer: false }); 21275 } 21276 let shadowPassVertical = texture(depthTexture); 21277 if (depthTexture.isArrayTexture) { 21278 shadowPassVertical = shadowPassVertical.depth(this.depthLayer); 21279 } 21280 let shadowPassHorizontal = texture(this.vsmShadowMapVertical.texture); 21281 if (depthTexture.isArrayTexture) { 21282 shadowPassHorizontal = shadowPassHorizontal.depth(this.depthLayer); 21283 } 21284 const samples = reference("blurSamples", "float", shadow3).setGroup(renderGroup); 21285 const radius = reference("radius", "float", shadow3).setGroup(renderGroup); 21286 const size3 = reference("mapSize", "vec2", shadow3).setGroup(renderGroup); 21287 let material = this.vsmMaterialVertical || (this.vsmMaterialVertical = new NodeMaterial()); 21288 material.fragmentNode = VSMPassVertical({ samples, radius, size: size3, shadowPass: shadowPassVertical, depthLayer: this.depthLayer }).context(builder.getSharedContext()); 21289 material.name = "VSMVertical"; 21290 material = this.vsmMaterialHorizontal || (this.vsmMaterialHorizontal = new NodeMaterial()); 21291 material.fragmentNode = VSMPassHorizontal({ samples, radius, size: size3, shadowPass: shadowPassHorizontal, depthLayer: this.depthLayer }).context(builder.getSharedContext()); 21292 material.name = "VSMHorizontal"; 21293 } 21294 const shadowIntensity = reference("intensity", "float", shadow3).setGroup(renderGroup); 21295 const normalBias = reference("normalBias", "float", shadow3).setGroup(renderGroup); 21296 const shadowMatrix = lightShadowMatrix(light); 21297 const shadowNormalBias = normalWorld.mul(normalBias); 21298 let shadowPosition; 21299 if (!renderer.highPrecision || builder.material.receivedShadowPositionNode || builder.context.shadowPositionWorld) { 21300 shadowPosition = shadowMatrix.mul(shadowPositionWorld.add(shadowNormalBias)); 21301 } else { 21302 const highpShadowModelMatrix = uniform("mat4").onObjectUpdate(({ object }, self2) => { 21303 return self2.value.multiplyMatrices(shadowMatrix.value, object.matrixWorld); 21304 }); 21305 shadowPosition = highpShadowModelMatrix.mul(positionLocal).add(shadowMatrix.mul(vec4(shadowNormalBias, 0))); 21306 } 21307 const shadowCoord = this.setupShadowCoord(builder, shadowPosition); 21308 const filterFn = shadow3.filterNode || this.getShadowFilterFn(renderer.shadowMap.type) || null; 21309 if (filterFn === null) { 21310 throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet."); 21311 } 21312 const shadowDepthTexture = shadowMapType === VSMShadowMap && shadow3.isPointLightShadow !== true ? this.vsmShadowMapHorizontal.texture : depthTexture; 21313 const shadowNode = this.setupShadowFilter(builder, { filterFn, shadowTexture: shadowMap.texture, depthTexture: shadowDepthTexture, shadowCoord, shadow: shadow3, depthLayer: this.depthLayer }); 21314 let shadowColor; 21315 if (renderer.shadowMap.transmitted === true) { 21316 if (shadowMap.texture.isCubeTexture) { 21317 shadowColor = cubeTexture(shadowMap.texture, shadowCoord.xyz); 21318 } else { 21319 shadowColor = texture(shadowMap.texture, shadowCoord); 21320 if (depthTexture.isArrayTexture) { 21321 shadowColor = shadowColor.depth(this.depthLayer); 21322 } 21323 } 21324 } 21325 let shadowOutput; 21326 if (shadowColor) { 21327 shadowOutput = mix(1, shadowNode.rgb.mix(shadowColor, 1), shadowIntensity.mul(shadowColor.a)).toVar(); 21328 } else { 21329 shadowOutput = mix(1, shadowNode, shadowIntensity).toVar(); 21330 } 21331 this.shadowMap = shadowMap; 21332 this.shadow.map = shadowMap; 21333 const inspectName = `${this.light.type} Shadow [ ${this.light.name || "ID: " + this.light.id} ]`; 21334 if (shadowColor) { 21335 shadowOutput.toInspector(`${inspectName} / Color`, () => { 21336 if (this.shadowMap.texture.isCubeTexture) { 21337 return cubeTexture(this.shadowMap.texture); 21338 } 21339 return texture(this.shadowMap.texture); 21340 }); 21341 } 21342 return shadowOutput.toInspector(`${inspectName} / Depth`, () => { 21343 if (this.shadowMap.texture.isCubeTexture) { 21344 return cubeTexture(this.shadowMap.texture).r.oneMinus(); 21345 } 21346 return textureLoad(this.shadowMap.depthTexture, uv$1().mul(textureSize(texture(this.shadowMap.depthTexture)))).r.oneMinus(); 21347 }); 21348 } 21349 /** 21350 * The implementation performs the setup of the output node. An output is only 21351 * produces if shadow mapping is globally enabled in the renderer. 21352 * 21353 * @param {NodeBuilder} builder - A reference to the current node builder. 21354 * @return {ShaderCallNodeInternal} The output node. 21355 */ 21356 setup(builder) { 21357 if (builder.renderer.shadowMap.enabled === false) return; 21358 return Fn(() => { 21359 const currentShadowType = builder.renderer.shadowMap.type; 21360 if (this._currentShadowType !== currentShadowType) { 21361 this._reset(); 21362 this._node = null; 21363 } 21364 let node = this._node; 21365 this.setupShadowPosition(builder); 21366 if (node === null) { 21367 this._node = node = this.setupShadow(builder); 21368 this._currentShadowType = currentShadowType; 21369 } 21370 if (builder.material.receivedShadowNode) { 21371 node = builder.material.receivedShadowNode(node); 21372 } 21373 return node; 21374 })(); 21375 } 21376 /** 21377 * Renders the shadow. The logic of this function could be included 21378 * into {@link ShadowNode#updateShadow} however more specialized shadow 21379 * nodes might require a custom shadow map rendering. By having a 21380 * dedicated method, it's easier to overwrite the default behavior. 21381 * 21382 * @param {NodeFrame} frame - A reference to the current node frame. 21383 */ 21384 renderShadow(frame) { 21385 const { shadow: shadow3, shadowMap, light } = this; 21386 const { renderer, scene } = frame; 21387 shadow3.updateMatrices(light); 21388 shadowMap.setSize(shadow3.mapSize.width, shadow3.mapSize.height, shadowMap.depth); 21389 const currentSceneName = scene.name; 21390 scene.name = `Shadow Map [ ${light.name || "ID: " + light.id} ]`; 21391 renderer.render(scene, shadow3.camera); 21392 scene.name = currentSceneName; 21393 } 21394 /** 21395 * Updates the shadow. 21396 * 21397 * @param {NodeFrame} frame - A reference to the current node frame. 21398 */ 21399 updateShadow(frame) { 21400 const { shadowMap, light, shadow: shadow3 } = this; 21401 const { renderer, scene, camera } = frame; 21402 const shadowType = renderer.shadowMap.type; 21403 const depthVersion = shadowMap.depthTexture.version; 21404 this._depthVersionCached = depthVersion; 21405 const _shadowCameraLayer = shadow3.camera.layers.mask; 21406 if ((shadow3.camera.layers.mask & 4294967294) === 0) { 21407 shadow3.camera.layers.mask = camera.layers.mask; 21408 } 21409 const currentRenderObjectFunction = renderer.getRenderObjectFunction(); 21410 const currentMRT = renderer.getMRT(); 21411 const useVelocity = currentMRT ? currentMRT.has("velocity") : false; 21412 _rendererState = resetRendererAndSceneState(renderer, scene, _rendererState); 21413 scene.overrideMaterial = getShadowMaterial(light); 21414 renderer.setRenderObjectFunction(getShadowRenderObjectFunction(renderer, shadow3, shadowType, useVelocity)); 21415 renderer.setClearColor(0, 0); 21416 renderer.setRenderTarget(shadowMap); 21417 this.renderShadow(frame); 21418 renderer.setRenderObjectFunction(currentRenderObjectFunction); 21419 if (shadowType === VSMShadowMap && shadow3.isPointLightShadow !== true) { 21420 this.vsmPass(renderer); 21421 } 21422 shadow3.camera.layers.mask = _shadowCameraLayer; 21423 restoreRendererAndSceneState(renderer, scene, _rendererState); 21424 } 21425 /** 21426 * For VSM additional render passes are required. 21427 * 21428 * @param {Renderer} renderer - A reference to the current renderer. 21429 */ 21430 vsmPass(renderer) { 21431 const { shadow: shadow3 } = this; 21432 const depth3 = this.shadowMap.depth; 21433 this.vsmShadowMapVertical.setSize(shadow3.mapSize.width, shadow3.mapSize.height, depth3); 21434 this.vsmShadowMapHorizontal.setSize(shadow3.mapSize.width, shadow3.mapSize.height, depth3); 21435 renderer.setRenderTarget(this.vsmShadowMapVertical); 21436 _quadMesh.material = this.vsmMaterialVertical; 21437 _quadMesh.render(renderer); 21438 renderer.setRenderTarget(this.vsmShadowMapHorizontal); 21439 _quadMesh.material = this.vsmMaterialHorizontal; 21440 _quadMesh.render(renderer); 21441 } 21442 /** 21443 * Frees the internal resources of this shadow node. 21444 */ 21445 dispose() { 21446 this._reset(); 21447 super.dispose(); 21448 } 21449 /** 21450 * Resets the resouce state of this shadow node. 21451 * 21452 * @private 21453 */ 21454 _reset() { 21455 this._currentShadowType = null; 21456 disposeShadowMaterial(this.light); 21457 if (this.shadowMap) { 21458 this.shadowMap.dispose(); 21459 this.shadowMap = null; 21460 } 21461 if (this.vsmShadowMapVertical !== null) { 21462 this.vsmShadowMapVertical.dispose(); 21463 this.vsmShadowMapVertical = null; 21464 this.vsmMaterialVertical.dispose(); 21465 this.vsmMaterialVertical = null; 21466 } 21467 if (this.vsmShadowMapHorizontal !== null) { 21468 this.vsmShadowMapHorizontal.dispose(); 21469 this.vsmShadowMapHorizontal = null; 21470 this.vsmMaterialHorizontal.dispose(); 21471 this.vsmMaterialHorizontal = null; 21472 } 21473 } 21474 /** 21475 * The implementation performs the update of the shadow map if necessary. 21476 * 21477 * @param {NodeFrame} frame - A reference to the current node frame. 21478 */ 21479 updateBefore(frame) { 21480 const { shadow: shadow3 } = this; 21481 let needsUpdate = shadow3.needsUpdate || shadow3.autoUpdate; 21482 if (needsUpdate) { 21483 if (this._cameraFrameId[frame.camera] === frame.frameId) { 21484 needsUpdate = false; 21485 } 21486 this._cameraFrameId[frame.camera] = frame.frameId; 21487 } 21488 if (needsUpdate) { 21489 this.updateShadow(frame); 21490 if (this.shadowMap.depthTexture.version === this._depthVersionCached) { 21491 shadow3.needsUpdate = false; 21492 } 21493 } 21494 } 21495}; 21496var shadow = (light, shadow3) => new ShadowNode(light, shadow3); 21497var _clearColor$1 = /* @__PURE__ */ new Color(); 21498var _projScreenMatrix$1 = /* @__PURE__ */ new Matrix4(); 21499var _lightPositionWorld = /* @__PURE__ */ new Vector3(); 21500var _lookTarget = /* @__PURE__ */ new Vector3(); 21501var _cubeDirectionsWebGPU = [ 21502 /* @__PURE__ */ new Vector3(1, 0, 0), 21503 /* @__PURE__ */ new Vector3(-1, 0, 0), 21504 /* @__PURE__ */ new Vector3(0, -1, 0), 21505 /* @__PURE__ */ new Vector3(0, 1, 0), 21506 /* @__PURE__ */ new Vector3(0, 0, 1), 21507 /* @__PURE__ */ new Vector3(0, 0, -1) 21508]; 21509var _cubeUpsWebGPU = [ 21510 /* @__PURE__ */ new Vector3(0, -1, 0), 21511 /* @__PURE__ */ new Vector3(0, -1, 0), 21512 /* @__PURE__ */ new Vector3(0, 0, -1), 21513 /* @__PURE__ */ new Vector3(0, 0, 1), 21514 /* @__PURE__ */ new Vector3(0, -1, 0), 21515 /* @__PURE__ */ new Vector3(0, -1, 0) 21516]; 21517var _cubeDirectionsWebGL = [ 21518 /* @__PURE__ */ new Vector3(1, 0, 0), 21519 /* @__PURE__ */ new Vector3(-1, 0, 0), 21520 /* @__PURE__ */ new Vector3(0, 1, 0), 21521 /* @__PURE__ */ new Vector3(0, -1, 0), 21522 /* @__PURE__ */ new Vector3(0, 0, 1), 21523 /* @__PURE__ */ new Vector3(0, 0, -1) 21524]; 21525var _cubeUpsWebGL = [ 21526 /* @__PURE__ */ new Vector3(0, -1, 0), 21527 /* @__PURE__ */ new Vector3(0, -1, 0), 21528 /* @__PURE__ */ new Vector3(0, 0, 1), 21529 /* @__PURE__ */ new Vector3(0, 0, -1), 21530 /* @__PURE__ */ new Vector3(0, -1, 0), 21531 /* @__PURE__ */ new Vector3(0, -1, 0) 21532]; 21533var BasicPointShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, bd3D, dp }) => { 21534 return cubeTexture(depthTexture, bd3D).compare(dp); 21535}); 21536var PointShadowFilter = /* @__PURE__ */ Fn(({ depthTexture, bd3D, dp, shadow: shadow3 }) => { 21537 const radius = reference("radius", "float", shadow3).setGroup(renderGroup); 21538 const mapSize = reference("mapSize", "vec2", shadow3).setGroup(renderGroup); 21539 const texelSize = radius.div(mapSize.x); 21540 const absDir = abs(bd3D); 21541 const tangent = normalize(cross(bd3D, absDir.x.greaterThan(absDir.z).select(vec3(0, 1, 0), vec3(1, 0, 0)))); 21542 const bitangent = cross(bd3D, tangent); 21543 const phi = interleavedGradientNoise(screenCoordinate.xy).mul(6.28318530718); 21544 const sample0 = vogelDiskSample(0, 5, phi); 21545 const sample1 = vogelDiskSample(1, 5, phi); 21546 const sample22 = vogelDiskSample(2, 5, phi); 21547 const sample3 = vogelDiskSample(3, 5, phi); 21548 const sample4 = vogelDiskSample(4, 5, phi); 21549 return cubeTexture(depthTexture, bd3D.add(tangent.mul(sample0.x).add(bitangent.mul(sample0.y)).mul(texelSize))).compare(dp).add(cubeTexture(depthTexture, bd3D.add(tangent.mul(sample1.x).add(bitangent.mul(sample1.y)).mul(texelSize))).compare(dp)).add(cubeTexture(depthTexture, bd3D.add(tangent.mul(sample22.x).add(bitangent.mul(sample22.y)).mul(texelSize))).compare(dp)).add(cubeTexture(depthTexture, bd3D.add(tangent.mul(sample3.x).add(bitangent.mul(sample3.y)).mul(texelSize))).compare(dp)).add(cubeTexture(depthTexture, bd3D.add(tangent.mul(sample4.x).add(bitangent.mul(sample4.y)).mul(texelSize))).compare(dp)).mul(1 / 5); 21550}); 21551var pointShadowFilter = /* @__PURE__ */ Fn(({ filterFn, depthTexture, shadowCoord, shadow: shadow3 }, builder) => { 21552 const shadowPosition = shadowCoord.xyz.toConst(); 21553 const shadowPositionAbs = shadowPosition.abs().toConst(); 21554 const viewZ = shadowPositionAbs.x.max(shadowPositionAbs.y).max(shadowPositionAbs.z); 21555 const shadowCameraNear = uniform("float").setGroup(renderGroup).onRenderUpdate(() => shadow3.camera.near); 21556 const shadowCameraFar = uniform("float").setGroup(renderGroup).onRenderUpdate(() => shadow3.camera.far); 21557 const bias = reference("bias", "float", shadow3).setGroup(renderGroup); 21558 const result = float(1).toVar(); 21559 If(viewZ.sub(shadowCameraFar).lessThanEqual(0).and(viewZ.sub(shadowCameraNear).greaterThanEqual(0)), () => { 21560 let dp; 21561 if (builder.renderer.reversedDepthBuffer) { 21562 dp = viewZToReversedPerspectiveDepth(viewZ.negate(), shadowCameraNear, shadowCameraFar); 21563 dp.subAssign(bias); 21564 } else { 21565 dp = viewZToPerspectiveDepth(viewZ.negate(), shadowCameraNear, shadowCameraFar); 21566 dp.addAssign(bias); 21567 } 21568 const bd3D = shadowPosition.normalize(); 21569 result.assign(filterFn({ depthTexture, bd3D, dp, shadow: shadow3 })); 21570 }); 21571 return result; 21572}); 21573var PointShadowNode = class extends ShadowNode { 21574 static get type() { 21575 return "PointShadowNode"; 21576 } 21577 /** 21578 * Constructs a new point shadow node. 21579 * 21580 * @param {PointLight} light - The shadow casting point light. 21581 * @param {?PointLightShadow} [shadow=null] - An optional point light shadow. 21582 */ 21583 constructor(light, shadow3 = null) { 21584 super(light, shadow3); 21585 } 21586 /** 21587 * Overwrites the default implementation to return point light shadow specific 21588 * filtering functions. 21589 * 21590 * @param {number} type - The shadow type. 21591 * @return {Function} The filtering function. 21592 */ 21593 getShadowFilterFn(type) { 21594 return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter; 21595 } 21596 /** 21597 * Overwrites the default implementation so the unaltered shadow position is used. 21598 * 21599 * @param {NodeBuilder} builder - A reference to the current node builder. 21600 * @param {Node<vec3>} shadowPosition - A node representing the shadow position. 21601 * @return {Node<vec3>} The shadow coordinates. 21602 */ 21603 setupShadowCoord(builder, shadowPosition) { 21604 return shadowPosition; 21605 } 21606 /** 21607 * Overwrites the default implementation to only use point light specific 21608 * shadow filter functions. 21609 * 21610 * @param {NodeBuilder} builder - A reference to the current node builder. 21611 * @param {Object} inputs - A configuration object that defines the shadow filtering. 21612 * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. 21613 * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's depth texture. 21614 * @param {Node<vec3>} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. 21615 * @param {LightShadow} inputs.shadow - The light shadow. 21616 * @return {Node<float>} The result node of the shadow filtering. 21617 */ 21618 setupShadowFilter(builder, { filterFn, depthTexture, shadowCoord, shadow: shadow3 }) { 21619 return pointShadowFilter({ filterFn, depthTexture, shadowCoord, shadow: shadow3 }); 21620 } 21621 /** 21622 * Overwrites the default implementation to create a CubeRenderTarget with CubeDepthTexture. 21623 * 21624 * @param {LightShadow} shadow - The light shadow object. 21625 * @param {NodeBuilder} builder - A reference to the current node builder. 21626 * @return {Object} An object containing the shadow map and depth texture. 21627 */ 21628 setupRenderTarget(shadow3, builder) { 21629 const depthTexture = new CubeDepthTexture(shadow3.mapSize.width); 21630 depthTexture.name = "PointShadowDepthTexture"; 21631 depthTexture.compareFunction = builder.renderer.reversedDepthBuffer ? GreaterEqualCompare : LessEqualCompare; 21632 const shadowMap = builder.createCubeRenderTarget(shadow3.mapSize.width); 21633 shadowMap.texture.name = "PointShadowMap"; 21634 shadowMap.depthTexture = depthTexture; 21635 return { shadowMap, depthTexture }; 21636 } 21637 /** 21638 * Overwrites the default implementation with point light specific 21639 * rendering code. 21640 * 21641 * @param {NodeFrame} frame - A reference to the current node frame. 21642 */ 21643 renderShadow(frame) { 21644 const { shadow: shadow3, shadowMap, light } = this; 21645 const { renderer, scene } = frame; 21646 const camera = shadow3.camera; 21647 const shadowMatrix = shadow3.matrix; 21648 const isWebGPU = renderer.coordinateSystem === WebGPUCoordinateSystem; 21649 const cubeDirections = isWebGPU ? _cubeDirectionsWebGPU : _cubeDirectionsWebGL; 21650 const cubeUps = isWebGPU ? _cubeUpsWebGPU : _cubeUpsWebGL; 21651 shadowMap.setSize(shadow3.mapSize.width, shadow3.mapSize.width); 21652 const previousAutoClear = renderer.autoClear; 21653 const previousClearColor = renderer.getClearColor(_clearColor$1); 21654 const previousClearAlpha = renderer.getClearAlpha(); 21655 renderer.autoClear = false; 21656 renderer.setClearColor(shadow3.clearColor, shadow3.clearAlpha); 21657 for (let face = 0; face < 6; face++) { 21658 renderer.setRenderTarget(shadowMap, face); 21659 renderer.clear(); 21660 const far = light.distance || camera.far; 21661 if (far !== camera.far) { 21662 camera.far = far; 21663 camera.updateProjectionMatrix(); 21664 } 21665 _lightPositionWorld.setFromMatrixPosition(light.matrixWorld); 21666 camera.position.copy(_lightPositionWorld); 21667 _lookTarget.copy(camera.position); 21668 _lookTarget.add(cubeDirections[face]); 21669 camera.up.copy(cubeUps[face]); 21670 camera.lookAt(_lookTarget); 21671 camera.updateMatrixWorld(); 21672 shadowMatrix.makeTranslation(-_lightPositionWorld.x, -_lightPositionWorld.y, -_lightPositionWorld.z); 21673 _projScreenMatrix$1.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 21674 shadow3._frustum.setFromProjectionMatrix(_projScreenMatrix$1, camera.coordinateSystem, camera.reversedDepth); 21675 const currentSceneName = scene.name; 21676 scene.name = `Point Light Shadow [ ${light.name || "ID: " + light.id} ] - Face ${face + 1}`; 21677 renderer.render(scene, camera); 21678 scene.name = currentSceneName; 21679 } 21680 renderer.autoClear = previousAutoClear; 21681 renderer.setClearColor(previousClearColor, previousClearAlpha); 21682 } 21683}; 21684var pointShadow = (light, shadow3) => new PointShadowNode(light, shadow3); 21685var AnalyticLightNode = class extends LightingNode { 21686 static get type() { 21687 return "AnalyticLightNode"; 21688 } 21689 /** 21690 * Constructs a new analytic light node. 21691 * 21692 * @param {?Light} [light=null] - The light source. 21693 */ 21694 constructor(light = null) { 21695 super(); 21696 this.light = light; 21697 this.color = new Color(); 21698 this.colorNode = light && light.colorNode || uniform(this.color).setGroup(renderGroup); 21699 this.baseColorNode = null; 21700 this.shadowNode = null; 21701 this.shadowColorNode = null; 21702 this.isAnalyticLightNode = true; 21703 this.updateType = NodeUpdateType.FRAME; 21704 if (light && light.shadow) { 21705 this._shadowDisposeListener = () => { 21706 this.disposeShadow(); 21707 }; 21708 light.addEventListener("dispose", this._shadowDisposeListener); 21709 } 21710 } 21711 dispose() { 21712 if (this._shadowDisposeListener) { 21713 this.light.removeEventListener("dispose", this._shadowDisposeListener); 21714 } 21715 super.dispose(); 21716 } 21717 /** 21718 * Frees internal resources related to shadows. 21719 */ 21720 disposeShadow() { 21721 if (this.shadowNode !== null) { 21722 this.shadowNode.dispose(); 21723 this.shadowNode = null; 21724 } 21725 this.shadowColorNode = null; 21726 if (this.baseColorNode !== null) { 21727 this.colorNode = this.baseColorNode; 21728 this.baseColorNode = null; 21729 } 21730 } 21731 getHash() { 21732 return this.light.uuid; 21733 } 21734 /** 21735 * Returns a node representing a direction vector which points from the current 21736 * position in view space to the light's position in view space. 21737 * 21738 * @param {NodeBuilder} builder - The builder object used for setting up the light. 21739 * @return {Node<vec3>} The light vector node. 21740 */ 21741 getLightVector(builder) { 21742 return lightViewPosition(this.light).sub(builder.context.positionView || positionView); 21743 } 21744 /** 21745 * Sets up the direct lighting for the analytic light node. 21746 * 21747 * @abstract 21748 * @param {NodeBuilder} builder - The builder object used for setting up the light. 21749 * @return {Object|undefined} The direct light data (color and direction). 21750 */ 21751 setupDirect() { 21752 } 21753 /** 21754 * Sets up the direct rect area lighting for the analytic light node. 21755 * 21756 * @abstract 21757 * @param {NodeBuilder} builder - The builder object used for setting up the light. 21758 * @return {Object|undefined} The direct rect area light data. 21759 */ 21760 setupDirectRectArea() { 21761 } 21762 /** 21763 * Setups the shadow node for this light. The method exists so concrete light classes 21764 * can setup different types of shadow nodes. 21765 * 21766 * @return {ShadowNode} The created shadow node. 21767 */ 21768 setupShadowNode() { 21769 return shadow(this.light); 21770 } 21771 /** 21772 * Setups the shadow for this light. This method is only executed if the light 21773 * cast shadows and the current build object receives shadows. It incorporates 21774 * shadows into the lighting computation. 21775 * 21776 * @param {NodeBuilder} builder - The current node builder. 21777 */ 21778 setupShadow(builder) { 21779 const { renderer } = builder; 21780 if (renderer.shadowMap.enabled === false) return; 21781 let shadowColorNode = this.shadowColorNode; 21782 if (shadowColorNode === null) { 21783 const customShadowNode = this.light.shadow.shadowNode; 21784 let shadowNode; 21785 if (customShadowNode !== void 0) { 21786 shadowNode = nodeObject(customShadowNode); 21787 } else { 21788 shadowNode = this.setupShadowNode(); 21789 } 21790 this.shadowNode = shadowNode; 21791 this.shadowColorNode = shadowColorNode = this.colorNode.mul(shadowNode); 21792 this.baseColorNode = this.colorNode; 21793 } 21794 if (builder.context.getShadow) { 21795 shadowColorNode = builder.context.getShadow(this, builder); 21796 } 21797 this.colorNode = shadowColorNode; 21798 } 21799 /** 21800 * Unlike most other nodes, lighting nodes do not return a output node in {@link Node#setup}. 21801 * The main purpose of lighting nodes is to configure the current {@link LightingModel} and/or 21802 * invocate the respective interface methods. 21803 * 21804 * @param {NodeBuilder} builder - The current node builder. 21805 */ 21806 setup(builder) { 21807 this.colorNode = this.baseColorNode || this.colorNode; 21808 if (this.light.castShadow) { 21809 if (builder.object.receiveShadow) { 21810 this.setupShadow(builder); 21811 } 21812 } else if (this.shadowNode !== null) { 21813 this.shadowNode.dispose(); 21814 this.shadowNode = null; 21815 this.shadowColorNode = null; 21816 } 21817 const directLightData = this.setupDirect(builder); 21818 const directRectAreaLightData = this.setupDirectRectArea(builder); 21819 if (directLightData) { 21820 builder.lightsNode.setupDirectLight(builder, this, directLightData); 21821 } 21822 if (directRectAreaLightData) { 21823 builder.lightsNode.setupDirectRectAreaLight(builder, this, directRectAreaLightData); 21824 } 21825 } 21826 /** 21827 * The update method is used to update light uniforms per frame. 21828 * Potentially overwritten in concrete light nodes to update light 21829 * specific uniforms. 21830 * 21831 * @param {NodeFrame} frame - A reference to the current node frame. 21832 */ 21833 update() { 21834 const { light } = this; 21835 this.color.copy(light.color).multiplyScalar(light.intensity); 21836 } 21837}; 21838var getDistanceAttenuation = /* @__PURE__ */ Fn(({ lightDistance, cutoffDistance, decayExponent }) => { 21839 const distanceFalloff = lightDistance.pow(decayExponent).max(0.01).reciprocal(); 21840 return cutoffDistance.greaterThan(0).select( 21841 distanceFalloff.mul(lightDistance.div(cutoffDistance).pow4().oneMinus().clamp().pow2()), 21842 distanceFalloff 21843 ); 21844}); 21845var directPointLight = ({ color: color3, lightVector, cutoffDistance, decayExponent }) => { 21846 const lightDirection = lightVector.normalize(); 21847 const lightDistance = lightVector.length(); 21848 const attenuation = getDistanceAttenuation({ 21849 lightDistance, 21850 cutoffDistance, 21851 decayExponent 21852 }); 21853 const lightColor = color3.mul(attenuation); 21854 return { lightDirection, lightColor }; 21855}; 21856var PointLightNode = class extends AnalyticLightNode { 21857 static get type() { 21858 return "PointLightNode"; 21859 } 21860 /** 21861 * Constructs a new point light node. 21862 * 21863 * @param {?PointLight} [light=null] - The point light source. 21864 */ 21865 constructor(light = null) { 21866 super(light); 21867 this.cutoffDistanceNode = uniform(0).setGroup(renderGroup); 21868 this.decayExponentNode = uniform(2).setGroup(renderGroup); 21869 } 21870 /** 21871 * Overwritten to updated point light specific uniforms. 21872 * 21873 * @param {NodeFrame} frame - A reference to the current node frame. 21874 */ 21875 update(frame) { 21876 const { light } = this; 21877 super.update(frame); 21878 this.cutoffDistanceNode.value = light.distance; 21879 this.decayExponentNode.value = light.decay; 21880 } 21881 /** 21882 * Overwritten to setup point light specific shadow. 21883 * 21884 * @return {PointShadowNode} 21885 */ 21886 setupShadowNode() { 21887 return pointShadow(this.light); 21888 } 21889 setupDirect(builder) { 21890 return directPointLight({ 21891 color: this.colorNode, 21892 lightVector: this.getLightVector(builder), 21893 cutoffDistance: this.cutoffDistanceNode, 21894 decayExponent: this.decayExponentNode 21895 }); 21896 } 21897}; 21898var checker = /* @__PURE__ */ Fn(([coord = uv$1()]) => { 21899 const uv3 = coord.mul(2); 21900 const cx = uv3.x.floor(); 21901 const cy = uv3.y.floor(); 21902 const result = cx.add(cy).mod(2); 21903 return result.sign(); 21904}); 21905var shapeCircle = Fn(([coord = uv$1()], { renderer, material }) => { 21906 const len2 = lengthSq(coord.mul(2).sub(1)); 21907 let alpha; 21908 if (material.alphaToCoverage && renderer.currentSamples > 0) { 21909 const dlen = float(len2.fwidth()).toVar(); 21910 alpha = smoothstep(dlen.oneMinus(), dlen.add(1), len2).oneMinus(); 21911 } else { 21912 alpha = select(len2.greaterThan(1), 0, 1); 21913 } 21914 return alpha; 21915}); 21916var mx_select = /* @__PURE__ */ Fn(([b_immutable, t_immutable, f_immutable]) => { 21917 const f = float(f_immutable).toVar(); 21918 const t = float(t_immutable).toVar(); 21919 const b = bool(b_immutable).toVar(); 21920 return select(b, t, f); 21921}).setLayout({ 21922 name: "mx_select", 21923 type: "float", 21924 inputs: [ 21925 { name: "b", type: "bool" }, 21926 { name: "t", type: "float" }, 21927 { name: "f", type: "float" } 21928 ] 21929}); 21930var mx_negate_if = /* @__PURE__ */ Fn(([val_immutable, b_immutable]) => { 21931 const b = bool(b_immutable).toVar(); 21932 const val = float(val_immutable).toVar(); 21933 return select(b, val.negate(), val); 21934}).setLayout({ 21935 name: "mx_negate_if", 21936 type: "float", 21937 inputs: [ 21938 { name: "val", type: "float" }, 21939 { name: "b", type: "bool" } 21940 ] 21941}); 21942var mx_floor = /* @__PURE__ */ Fn(([x_immutable]) => { 21943 const x = float(x_immutable).toVar(); 21944 return int(floor(x)); 21945}).setLayout({ 21946 name: "mx_floor", 21947 type: "int", 21948 inputs: [ 21949 { name: "x", type: "float" } 21950 ] 21951}); 21952var mx_floorfrac = /* @__PURE__ */ Fn(([x_immutable, i]) => { 21953 const x = float(x_immutable).toVar(); 21954 i.assign(mx_floor(x)); 21955 return x.sub(float(i)); 21956}); 21957var mx_bilerp_0 = /* @__PURE__ */ Fn(([v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable]) => { 21958 const t = float(t_immutable).toVar(); 21959 const s = float(s_immutable).toVar(); 21960 const v3 = float(v3_immutable).toVar(); 21961 const v2 = float(v2_immutable).toVar(); 21962 const v1 = float(v1_immutable).toVar(); 21963 const v0 = float(v0_immutable).toVar(); 21964 const s1 = float(sub(1, s)).toVar(); 21965 return sub(1, t).mul(v0.mul(s1).add(v1.mul(s))).add(t.mul(v2.mul(s1).add(v3.mul(s)))); 21966}).setLayout({ 21967 name: "mx_bilerp_0", 21968 type: "float", 21969 inputs: [ 21970 { name: "v0", type: "float" }, 21971 { name: "v1", type: "float" }, 21972 { name: "v2", type: "float" }, 21973 { name: "v3", type: "float" }, 21974 { name: "s", type: "float" }, 21975 { name: "t", type: "float" } 21976 ] 21977}); 21978var mx_bilerp_1 = /* @__PURE__ */ Fn(([v0_immutable, v1_immutable, v2_immutable, v3_immutable, s_immutable, t_immutable]) => { 21979 const t = float(t_immutable).toVar(); 21980 const s = float(s_immutable).toVar(); 21981 const v3 = vec3(v3_immutable).toVar(); 21982 const v2 = vec3(v2_immutable).toVar(); 21983 const v1 = vec3(v1_immutable).toVar(); 21984 const v0 = vec3(v0_immutable).toVar(); 21985 const s1 = float(sub(1, s)).toVar(); 21986 return sub(1, t).mul(v0.mul(s1).add(v1.mul(s))).add(t.mul(v2.mul(s1).add(v3.mul(s)))); 21987}).setLayout({ 21988 name: "mx_bilerp_1", 21989 type: "vec3", 21990 inputs: [ 21991 { name: "v0", type: "vec3" }, 21992 { name: "v1", type: "vec3" }, 21993 { name: "v2", type: "vec3" }, 21994 { name: "v3", type: "vec3" }, 21995 { name: "s", type: "float" }, 21996 { name: "t", type: "float" } 21997 ] 21998}); 21999var mx_bilerp = /* @__PURE__ */ overloadingFn([mx_bilerp_0, mx_bilerp_1]); 22000var mx_trilerp_0 = /* @__PURE__ */ Fn(([v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable]) => { 22001 const r = float(r_immutable).toVar(); 22002 const t = float(t_immutable).toVar(); 22003 const s = float(s_immutable).toVar(); 22004 const v7 = float(v7_immutable).toVar(); 22005 const v6 = float(v6_immutable).toVar(); 22006 const v5 = float(v5_immutable).toVar(); 22007 const v4 = float(v4_immutable).toVar(); 22008 const v3 = float(v3_immutable).toVar(); 22009 const v2 = float(v2_immutable).toVar(); 22010 const v1 = float(v1_immutable).toVar(); 22011 const v0 = float(v0_immutable).toVar(); 22012 const s1 = float(sub(1, s)).toVar(); 22013 const t1 = float(sub(1, t)).toVar(); 22014 const r1 = float(sub(1, r)).toVar(); 22015 return r1.mul(t1.mul(v0.mul(s1).add(v1.mul(s))).add(t.mul(v2.mul(s1).add(v3.mul(s))))).add(r.mul(t1.mul(v4.mul(s1).add(v5.mul(s))).add(t.mul(v6.mul(s1).add(v7.mul(s)))))); 22016}).setLayout({ 22017 name: "mx_trilerp_0", 22018 type: "float", 22019 inputs: [ 22020 { name: "v0", type: "float" }, 22021 { name: "v1", type: "float" }, 22022 { name: "v2", type: "float" }, 22023 { name: "v3", type: "float" }, 22024 { name: "v4", type: "float" }, 22025 { name: "v5", type: "float" }, 22026 { name: "v6", type: "float" }, 22027 { name: "v7", type: "float" }, 22028 { name: "s", type: "float" }, 22029 { name: "t", type: "float" }, 22030 { name: "r", type: "float" } 22031 ] 22032}); 22033var mx_trilerp_1 = /* @__PURE__ */ Fn(([v0_immutable, v1_immutable, v2_immutable, v3_immutable, v4_immutable, v5_immutable, v6_immutable, v7_immutable, s_immutable, t_immutable, r_immutable]) => { 22034 const r = float(r_immutable).toVar(); 22035 const t = float(t_immutable).toVar(); 22036 const s = float(s_immutable).toVar(); 22037 const v7 = vec3(v7_immutable).toVar(); 22038 const v6 = vec3(v6_immutable).toVar(); 22039 const v5 = vec3(v5_immutable).toVar(); 22040 const v4 = vec3(v4_immutable).toVar(); 22041 const v3 = vec3(v3_immutable).toVar(); 22042 const v2 = vec3(v2_immutable).toVar(); 22043 const v1 = vec3(v1_immutable).toVar(); 22044 const v0 = vec3(v0_immutable).toVar(); 22045 const s1 = float(sub(1, s)).toVar(); 22046 const t1 = float(sub(1, t)).toVar(); 22047 const r1 = float(sub(1, r)).toVar(); 22048 return r1.mul(t1.mul(v0.mul(s1).add(v1.mul(s))).add(t.mul(v2.mul(s1).add(v3.mul(s))))).add(r.mul(t1.mul(v4.mul(s1).add(v5.mul(s))).add(t.mul(v6.mul(s1).add(v7.mul(s)))))); 22049}).setLayout({ 22050 name: "mx_trilerp_1", 22051 type: "vec3", 22052 inputs: [ 22053 { name: "v0", type: "vec3" }, 22054 { name: "v1", type: "vec3" }, 22055 { name: "v2", type: "vec3" }, 22056 { name: "v3", type: "vec3" }, 22057 { name: "v4", type: "vec3" }, 22058 { name: "v5", type: "vec3" }, 22059 { name: "v6", type: "vec3" }, 22060 { name: "v7", type: "vec3" }, 22061 { name: "s", type: "float" }, 22062 { name: "t", type: "float" }, 22063 { name: "r", type: "float" } 22064 ] 22065}); 22066var mx_trilerp = /* @__PURE__ */ overloadingFn([mx_trilerp_0, mx_trilerp_1]); 22067var mx_gradient_float_0 = /* @__PURE__ */ Fn(([hash_immutable, x_immutable, y_immutable]) => { 22068 const y = float(y_immutable).toVar(); 22069 const x = float(x_immutable).toVar(); 22070 const hash3 = uint(hash_immutable).toVar(); 22071 const h = uint(hash3.bitAnd(uint(7))).toVar(); 22072 const u = float(mx_select(h.lessThan(uint(4)), x, y)).toVar(); 22073 const v = float(mul(2, mx_select(h.lessThan(uint(4)), y, x))).toVar(); 22074 return mx_negate_if(u, bool(h.bitAnd(uint(1)))).add(mx_negate_if(v, bool(h.bitAnd(uint(2))))); 22075}).setLayout({ 22076 name: "mx_gradient_float_0", 22077 type: "float", 22078 inputs: [ 22079 { name: "hash", type: "uint" }, 22080 { name: "x", type: "float" }, 22081 { name: "y", type: "float" } 22082 ] 22083}); 22084var mx_gradient_float_1 = /* @__PURE__ */ Fn(([hash_immutable, x_immutable, y_immutable, z_immutable]) => { 22085 const z = float(z_immutable).toVar(); 22086 const y = float(y_immutable).toVar(); 22087 const x = float(x_immutable).toVar(); 22088 const hash3 = uint(hash_immutable).toVar(); 22089 const h = uint(hash3.bitAnd(uint(15))).toVar(); 22090 const u = float(mx_select(h.lessThan(uint(8)), x, y)).toVar(); 22091 const v = float(mx_select(h.lessThan(uint(4)), y, mx_select(h.equal(uint(12)).or(h.equal(uint(14))), x, z))).toVar(); 22092 return mx_negate_if(u, bool(h.bitAnd(uint(1)))).add(mx_negate_if(v, bool(h.bitAnd(uint(2))))); 22093}).setLayout({ 22094 name: "mx_gradient_float_1", 22095 type: "float", 22096 inputs: [ 22097 { name: "hash", type: "uint" }, 22098 { name: "x", type: "float" }, 22099 { name: "y", type: "float" }, 22100 { name: "z", type: "float" } 22101 ] 22102}); 22103var mx_gradient_float = /* @__PURE__ */ overloadingFn([mx_gradient_float_0, mx_gradient_float_1]); 22104var mx_gradient_vec3_0 = /* @__PURE__ */ Fn(([hash_immutable, x_immutable, y_immutable]) => { 22105 const y = float(y_immutable).toVar(); 22106 const x = float(x_immutable).toVar(); 22107 const hash3 = uvec3(hash_immutable).toVar(); 22108 return vec3(mx_gradient_float(hash3.x, x, y), mx_gradient_float(hash3.y, x, y), mx_gradient_float(hash3.z, x, y)); 22109}).setLayout({ 22110 name: "mx_gradient_vec3_0", 22111 type: "vec3", 22112 inputs: [ 22113 { name: "hash", type: "uvec3" }, 22114 { name: "x", type: "float" }, 22115 { name: "y", type: "float" } 22116 ] 22117}); 22118var mx_gradient_vec3_1 = /* @__PURE__ */ Fn(([hash_immutable, x_immutable, y_immutable, z_immutable]) => { 22119 const z = float(z_immutable).toVar(); 22120 const y = float(y_immutable).toVar(); 22121 const x = float(x_immutable).toVar(); 22122 const hash3 = uvec3(hash_immutable).toVar(); 22123 return vec3(mx_gradient_float(hash3.x, x, y, z), mx_gradient_float(hash3.y, x, y, z), mx_gradient_float(hash3.z, x, y, z)); 22124}).setLayout({ 22125 name: "mx_gradient_vec3_1", 22126 type: "vec3", 22127 inputs: [ 22128 { name: "hash", type: "uvec3" }, 22129 { name: "x", type: "float" }, 22130 { name: "y", type: "float" }, 22131 { name: "z", type: "float" } 22132 ] 22133}); 22134var mx_gradient_vec3 = /* @__PURE__ */ overloadingFn([mx_gradient_vec3_0, mx_gradient_vec3_1]); 22135var mx_gradient_scale2d_0 = /* @__PURE__ */ Fn(([v_immutable]) => { 22136 const v = float(v_immutable).toVar(); 22137 return mul(0.6616, v); 22138}).setLayout({ 22139 name: "mx_gradient_scale2d_0", 22140 type: "float", 22141 inputs: [ 22142 { name: "v", type: "float" } 22143 ] 22144}); 22145var mx_gradient_scale3d_0 = /* @__PURE__ */ Fn(([v_immutable]) => { 22146 const v = float(v_immutable).toVar(); 22147 return mul(0.982, v); 22148}).setLayout({ 22149 name: "mx_gradient_scale3d_0", 22150 type: "float", 22151 inputs: [ 22152 { name: "v", type: "float" } 22153 ] 22154}); 22155var mx_gradient_scale2d_1 = /* @__PURE__ */ Fn(([v_immutable]) => { 22156 const v = vec3(v_immutable).toVar(); 22157 return mul(0.6616, v); 22158}).setLayout({ 22159 name: "mx_gradient_scale2d_1", 22160 type: "vec3", 22161 inputs: [ 22162 { name: "v", type: "vec3" } 22163 ] 22164}); 22165var mx_gradient_scale2d = /* @__PURE__ */ overloadingFn([mx_gradient_scale2d_0, mx_gradient_scale2d_1]); 22166var mx_gradient_scale3d_1 = /* @__PURE__ */ Fn(([v_immutable]) => { 22167 const v = vec3(v_immutable).toVar(); 22168 return mul(0.982, v); 22169}).setLayout({ 22170 name: "mx_gradient_scale3d_1", 22171 type: "vec3", 22172 inputs: [ 22173 { name: "v", type: "vec3" } 22174 ] 22175}); 22176var mx_gradient_scale3d = /* @__PURE__ */ overloadingFn([mx_gradient_scale3d_0, mx_gradient_scale3d_1]); 22177var mx_rotl32 = /* @__PURE__ */ Fn(([x_immutable, k_immutable]) => { 22178 const k = int(k_immutable).toVar(); 22179 const x = uint(x_immutable).toVar(); 22180 return x.shiftLeft(k).bitOr(x.shiftRight(int(32).sub(k))); 22181}).setLayout({ 22182 name: "mx_rotl32", 22183 type: "uint", 22184 inputs: [ 22185 { name: "x", type: "uint" }, 22186 { name: "k", type: "int" } 22187 ] 22188}); 22189var mx_bjmix = /* @__PURE__ */ Fn(([a, b, c]) => { 22190 a.subAssign(c); 22191 a.bitXorAssign(mx_rotl32(c, int(4))); 22192 c.addAssign(b); 22193 b.subAssign(a); 22194 b.bitXorAssign(mx_rotl32(a, int(6))); 22195 a.addAssign(c); 22196 c.subAssign(b); 22197 c.bitXorAssign(mx_rotl32(b, int(8))); 22198 b.addAssign(a); 22199 a.subAssign(c); 22200 a.bitXorAssign(mx_rotl32(c, int(16))); 22201 c.addAssign(b); 22202 b.subAssign(a); 22203 b.bitXorAssign(mx_rotl32(a, int(19))); 22204 a.addAssign(c); 22205 c.subAssign(b); 22206 c.bitXorAssign(mx_rotl32(b, int(4))); 22207 b.addAssign(a); 22208}); 22209var mx_bjfinal = /* @__PURE__ */ Fn(([a_immutable, b_immutable, c_immutable]) => { 22210 const c = uint(c_immutable).toVar(); 22211 const b = uint(b_immutable).toVar(); 22212 const a = uint(a_immutable).toVar(); 22213 c.bitXorAssign(b); 22214 c.subAssign(mx_rotl32(b, int(14))); 22215 a.bitXorAssign(c); 22216 a.subAssign(mx_rotl32(c, int(11))); 22217 b.bitXorAssign(a); 22218 b.subAssign(mx_rotl32(a, int(25))); 22219 c.bitXorAssign(b); 22220 c.subAssign(mx_rotl32(b, int(16))); 22221 a.bitXorAssign(c); 22222 a.subAssign(mx_rotl32(c, int(4))); 22223 b.bitXorAssign(a); 22224 b.subAssign(mx_rotl32(a, int(14))); 22225 c.bitXorAssign(b); 22226 c.subAssign(mx_rotl32(b, int(24))); 22227 return c; 22228}).setLayout({ 22229 name: "mx_bjfinal", 22230 type: "uint", 22231 inputs: [ 22232 { name: "a", type: "uint" }, 22233 { name: "b", type: "uint" }, 22234 { name: "c", type: "uint" } 22235 ] 22236}); 22237var mx_bits_to_01 = /* @__PURE__ */ Fn(([bits_immutable]) => { 22238 const bits = uint(bits_immutable).toVar(); 22239 return float(bits).div(float(uint(int(4294967295)))); 22240}).setLayout({ 22241 name: "mx_bits_to_01", 22242 type: "float", 22243 inputs: [ 22244 { name: "bits", type: "uint" } 22245 ] 22246}); 22247var mx_fade = /* @__PURE__ */ Fn(([t_immutable]) => { 22248 const t = float(t_immutable).toVar(); 22249 return t.mul(t).mul(t).mul(t.mul(t.mul(6).sub(15)).add(10)); 22250}).setLayout({ 22251 name: "mx_fade", 22252 type: "float", 22253 inputs: [ 22254 { name: "t", type: "float" } 22255 ] 22256}); 22257var mx_hash_int_0 = /* @__PURE__ */ Fn(([x_immutable]) => { 22258 const x = int(x_immutable).toVar(); 22259 const len = uint(uint(1)).toVar(); 22260 const seed = uint(uint(int(3735928559)).add(len.shiftLeft(uint(2))).add(uint(13))).toVar(); 22261 return mx_bjfinal(seed.add(uint(x)), seed, seed); 22262}).setLayout({ 22263 name: "mx_hash_int_0", 22264 type: "uint", 22265 inputs: [ 22266 { name: "x", type: "int" } 22267 ] 22268}); 22269var mx_hash_int_1 = /* @__PURE__ */ Fn(([x_immutable, y_immutable]) => { 22270 const y = int(y_immutable).toVar(); 22271 const x = int(x_immutable).toVar(); 22272 const len = uint(uint(2)).toVar(); 22273 const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); 22274 a.assign(b.assign(c.assign(uint(int(3735928559)).add(len.shiftLeft(uint(2))).add(uint(13))))); 22275 a.addAssign(uint(x)); 22276 b.addAssign(uint(y)); 22277 return mx_bjfinal(a, b, c); 22278}).setLayout({ 22279 name: "mx_hash_int_1", 22280 type: "uint", 22281 inputs: [ 22282 { name: "x", type: "int" }, 22283 { name: "y", type: "int" } 22284 ] 22285}); 22286var mx_hash_int_2 = /* @__PURE__ */ Fn(([x_immutable, y_immutable, z_immutable]) => { 22287 const z = int(z_immutable).toVar(); 22288 const y = int(y_immutable).toVar(); 22289 const x = int(x_immutable).toVar(); 22290 const len = uint(uint(3)).toVar(); 22291 const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); 22292 a.assign(b.assign(c.assign(uint(int(3735928559)).add(len.shiftLeft(uint(2))).add(uint(13))))); 22293 a.addAssign(uint(x)); 22294 b.addAssign(uint(y)); 22295 c.addAssign(uint(z)); 22296 return mx_bjfinal(a, b, c); 22297}).setLayout({ 22298 name: "mx_hash_int_2", 22299 type: "uint", 22300 inputs: [ 22301 { name: "x", type: "int" }, 22302 { name: "y", type: "int" }, 22303 { name: "z", type: "int" } 22304 ] 22305}); 22306var mx_hash_int_3 = /* @__PURE__ */ Fn(([x_immutable, y_immutable, z_immutable, xx_immutable]) => { 22307 const xx = int(xx_immutable).toVar(); 22308 const z = int(z_immutable).toVar(); 22309 const y = int(y_immutable).toVar(); 22310 const x = int(x_immutable).toVar(); 22311 const len = uint(uint(4)).toVar(); 22312 const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); 22313 a.assign(b.assign(c.assign(uint(int(3735928559)).add(len.shiftLeft(uint(2))).add(uint(13))))); 22314 a.addAssign(uint(x)); 22315 b.addAssign(uint(y)); 22316 c.addAssign(uint(z)); 22317 mx_bjmix(a, b, c); 22318 a.addAssign(uint(xx)); 22319 return mx_bjfinal(a, b, c); 22320}).setLayout({ 22321 name: "mx_hash_int_3", 22322 type: "uint", 22323 inputs: [ 22324 { name: "x", type: "int" }, 22325 { name: "y", type: "int" }, 22326 { name: "z", type: "int" }, 22327 { name: "xx", type: "int" } 22328 ] 22329}); 22330var mx_hash_int_4 = /* @__PURE__ */ Fn(([x_immutable, y_immutable, z_immutable, xx_immutable, yy_immutable]) => { 22331 const yy = int(yy_immutable).toVar(); 22332 const xx = int(xx_immutable).toVar(); 22333 const z = int(z_immutable).toVar(); 22334 const y = int(y_immutable).toVar(); 22335 const x = int(x_immutable).toVar(); 22336 const len = uint(uint(5)).toVar(); 22337 const a = uint().toVar(), b = uint().toVar(), c = uint().toVar(); 22338 a.assign(b.assign(c.assign(uint(int(3735928559)).add(len.shiftLeft(uint(2))).add(uint(13))))); 22339 a.addAssign(uint(x)); 22340 b.addAssign(uint(y)); 22341 c.addAssign(uint(z)); 22342 mx_bjmix(a, b, c); 22343 a.addAssign(uint(xx)); 22344 b.addAssign(uint(yy)); 22345 return mx_bjfinal(a, b, c); 22346}).setLayout({ 22347 name: "mx_hash_int_4", 22348 type: "uint", 22349 inputs: [ 22350 { name: "x", type: "int" }, 22351 { name: "y", type: "int" }, 22352 { name: "z", type: "int" }, 22353 { name: "xx", type: "int" }, 22354 { name: "yy", type: "int" } 22355 ] 22356}); 22357var mx_hash_int = /* @__PURE__ */ overloadingFn([mx_hash_int_0, mx_hash_int_1, mx_hash_int_2, mx_hash_int_3, mx_hash_int_4]); 22358var mx_hash_vec3_0 = /* @__PURE__ */ Fn(([x_immutable, y_immutable]) => { 22359 const y = int(y_immutable).toVar(); 22360 const x = int(x_immutable).toVar(); 22361 const h = uint(mx_hash_int(x, y)).toVar(); 22362 const result = uvec3().toVar(); 22363 result.x.assign(h.bitAnd(int(255))); 22364 result.y.assign(h.shiftRight(int(8)).bitAnd(int(255))); 22365 result.z.assign(h.shiftRight(int(16)).bitAnd(int(255))); 22366 return result; 22367}).setLayout({ 22368 name: "mx_hash_vec3_0", 22369 type: "uvec3", 22370 inputs: [ 22371 { name: "x", type: "int" }, 22372 { name: "y", type: "int" } 22373 ] 22374}); 22375var mx_hash_vec3_1 = /* @__PURE__ */ Fn(([x_immutable, y_immutable, z_immutable]) => { 22376 const z = int(z_immutable).toVar(); 22377 const y = int(y_immutable).toVar(); 22378 const x = int(x_immutable).toVar(); 22379 const h = uint(mx_hash_int(x, y, z)).toVar(); 22380 const result = uvec3().toVar(); 22381 result.x.assign(h.bitAnd(int(255))); 22382 result.y.assign(h.shiftRight(int(8)).bitAnd(int(255))); 22383 result.z.assign(h.shiftRight(int(16)).bitAnd(int(255))); 22384 return result; 22385}).setLayout({ 22386 name: "mx_hash_vec3_1", 22387 type: "uvec3", 22388 inputs: [ 22389 { name: "x", type: "int" }, 22390 { name: "y", type: "int" }, 22391 { name: "z", type: "int" } 22392 ] 22393}); 22394var mx_hash_vec3 = /* @__PURE__ */ overloadingFn([mx_hash_vec3_0, mx_hash_vec3_1]); 22395var mx_perlin_noise_float_0 = /* @__PURE__ */ Fn(([p_immutable]) => { 22396 const p = vec2(p_immutable).toVar(); 22397 const X = int().toVar(), Y = int().toVar(); 22398 const fx = float(mx_floorfrac(p.x, X)).toVar(); 22399 const fy = float(mx_floorfrac(p.y, Y)).toVar(); 22400 const u = float(mx_fade(fx)).toVar(); 22401 const v = float(mx_fade(fy)).toVar(); 22402 const result = float(mx_bilerp(mx_gradient_float(mx_hash_int(X, Y), fx, fy), mx_gradient_float(mx_hash_int(X.add(int(1)), Y), fx.sub(1), fy), mx_gradient_float(mx_hash_int(X, Y.add(int(1))), fx, fy.sub(1)), mx_gradient_float(mx_hash_int(X.add(int(1)), Y.add(int(1))), fx.sub(1), fy.sub(1)), u, v)).toVar(); 22403 return mx_gradient_scale2d(result); 22404}).setLayout({ 22405 name: "mx_perlin_noise_float_0", 22406 type: "float", 22407 inputs: [ 22408 { name: "p", type: "vec2" } 22409 ] 22410}); 22411var mx_perlin_noise_float_1 = /* @__PURE__ */ Fn(([p_immutable]) => { 22412 const p = vec3(p_immutable).toVar(); 22413 const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); 22414 const fx = float(mx_floorfrac(p.x, X)).toVar(); 22415 const fy = float(mx_floorfrac(p.y, Y)).toVar(); 22416 const fz = float(mx_floorfrac(p.z, Z)).toVar(); 22417 const u = float(mx_fade(fx)).toVar(); 22418 const v = float(mx_fade(fy)).toVar(); 22419 const w = float(mx_fade(fz)).toVar(); 22420 const result = float(mx_trilerp(mx_gradient_float(mx_hash_int(X, Y, Z), fx, fy, fz), mx_gradient_float(mx_hash_int(X.add(int(1)), Y, Z), fx.sub(1), fy, fz), mx_gradient_float(mx_hash_int(X, Y.add(int(1)), Z), fx, fy.sub(1), fz), mx_gradient_float(mx_hash_int(X.add(int(1)), Y.add(int(1)), Z), fx.sub(1), fy.sub(1), fz), mx_gradient_float(mx_hash_int(X, Y, Z.add(int(1))), fx, fy, fz.sub(1)), mx_gradient_float(mx_hash_int(X.add(int(1)), Y, Z.add(int(1))), fx.sub(1), fy, fz.sub(1)), mx_gradient_float(mx_hash_int(X, Y.add(int(1)), Z.add(int(1))), fx, fy.sub(1), fz.sub(1)), mx_gradient_float(mx_hash_int(X.add(int(1)), Y.add(int(1)), Z.add(int(1))), fx.sub(1), fy.sub(1), fz.sub(1)), u, v, w)).toVar(); 22421 return mx_gradient_scale3d(result); 22422}).setLayout({ 22423 name: "mx_perlin_noise_float_1", 22424 type: "float", 22425 inputs: [ 22426 { name: "p", type: "vec3" } 22427 ] 22428}); 22429var mx_perlin_noise_float = /* @__PURE__ */ overloadingFn([mx_perlin_noise_float_0, mx_perlin_noise_float_1]); 22430var mx_perlin_noise_vec3_0 = /* @__PURE__ */ Fn(([p_immutable]) => { 22431 const p = vec2(p_immutable).toVar(); 22432 const X = int().toVar(), Y = int().toVar(); 22433 const fx = float(mx_floorfrac(p.x, X)).toVar(); 22434 const fy = float(mx_floorfrac(p.y, Y)).toVar(); 22435 const u = float(mx_fade(fx)).toVar(); 22436 const v = float(mx_fade(fy)).toVar(); 22437 const result = vec3(mx_bilerp(mx_gradient_vec3(mx_hash_vec3(X, Y), fx, fy), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y), fx.sub(1), fy), mx_gradient_vec3(mx_hash_vec3(X, Y.add(int(1))), fx, fy.sub(1)), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y.add(int(1))), fx.sub(1), fy.sub(1)), u, v)).toVar(); 22438 return mx_gradient_scale2d(result); 22439}).setLayout({ 22440 name: "mx_perlin_noise_vec3_0", 22441 type: "vec3", 22442 inputs: [ 22443 { name: "p", type: "vec2" } 22444 ] 22445}); 22446var mx_perlin_noise_vec3_1 = /* @__PURE__ */ Fn(([p_immutable]) => { 22447 const p = vec3(p_immutable).toVar(); 22448 const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); 22449 const fx = float(mx_floorfrac(p.x, X)).toVar(); 22450 const fy = float(mx_floorfrac(p.y, Y)).toVar(); 22451 const fz = float(mx_floorfrac(p.z, Z)).toVar(); 22452 const u = float(mx_fade(fx)).toVar(); 22453 const v = float(mx_fade(fy)).toVar(); 22454 const w = float(mx_fade(fz)).toVar(); 22455 const result = vec3(mx_trilerp(mx_gradient_vec3(mx_hash_vec3(X, Y, Z), fx, fy, fz), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y, Z), fx.sub(1), fy, fz), mx_gradient_vec3(mx_hash_vec3(X, Y.add(int(1)), Z), fx, fy.sub(1), fz), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y.add(int(1)), Z), fx.sub(1), fy.sub(1), fz), mx_gradient_vec3(mx_hash_vec3(X, Y, Z.add(int(1))), fx, fy, fz.sub(1)), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y, Z.add(int(1))), fx.sub(1), fy, fz.sub(1)), mx_gradient_vec3(mx_hash_vec3(X, Y.add(int(1)), Z.add(int(1))), fx, fy.sub(1), fz.sub(1)), mx_gradient_vec3(mx_hash_vec3(X.add(int(1)), Y.add(int(1)), Z.add(int(1))), fx.sub(1), fy.sub(1), fz.sub(1)), u, v, w)).toVar(); 22456 return mx_gradient_scale3d(result); 22457}).setLayout({ 22458 name: "mx_perlin_noise_vec3_1", 22459 type: "vec3", 22460 inputs: [ 22461 { name: "p", type: "vec3" } 22462 ] 22463}); 22464var mx_perlin_noise_vec3 = /* @__PURE__ */ overloadingFn([mx_perlin_noise_vec3_0, mx_perlin_noise_vec3_1]); 22465var mx_cell_noise_float_0 = /* @__PURE__ */ Fn(([p_immutable]) => { 22466 const p = float(p_immutable).toVar(); 22467 const ix = int(mx_floor(p)).toVar(); 22468 return mx_bits_to_01(mx_hash_int(ix)); 22469}).setLayout({ 22470 name: "mx_cell_noise_float_0", 22471 type: "float", 22472 inputs: [ 22473 { name: "p", type: "float" } 22474 ] 22475}); 22476var mx_cell_noise_float_1 = /* @__PURE__ */ Fn(([p_immutable]) => { 22477 const p = vec2(p_immutable).toVar(); 22478 const ix = int(mx_floor(p.x)).toVar(); 22479 const iy = int(mx_floor(p.y)).toVar(); 22480 return mx_bits_to_01(mx_hash_int(ix, iy)); 22481}).setLayout({ 22482 name: "mx_cell_noise_float_1", 22483 type: "float", 22484 inputs: [ 22485 { name: "p", type: "vec2" } 22486 ] 22487}); 22488var mx_cell_noise_float_2 = /* @__PURE__ */ Fn(([p_immutable]) => { 22489 const p = vec3(p_immutable).toVar(); 22490 const ix = int(mx_floor(p.x)).toVar(); 22491 const iy = int(mx_floor(p.y)).toVar(); 22492 const iz = int(mx_floor(p.z)).toVar(); 22493 return mx_bits_to_01(mx_hash_int(ix, iy, iz)); 22494}).setLayout({ 22495 name: "mx_cell_noise_float_2", 22496 type: "float", 22497 inputs: [ 22498 { name: "p", type: "vec3" } 22499 ] 22500}); 22501var mx_cell_noise_float_3 = /* @__PURE__ */ Fn(([p_immutable]) => { 22502 const p = vec4(p_immutable).toVar(); 22503 const ix = int(mx_floor(p.x)).toVar(); 22504 const iy = int(mx_floor(p.y)).toVar(); 22505 const iz = int(mx_floor(p.z)).toVar(); 22506 const iw = int(mx_floor(p.w)).toVar(); 22507 return mx_bits_to_01(mx_hash_int(ix, iy, iz, iw)); 22508}).setLayout({ 22509 name: "mx_cell_noise_float_3", 22510 type: "float", 22511 inputs: [ 22512 { name: "p", type: "vec4" } 22513 ] 22514}); 22515var mx_cell_noise_float$1 = /* @__PURE__ */ overloadingFn([mx_cell_noise_float_0, mx_cell_noise_float_1, mx_cell_noise_float_2, mx_cell_noise_float_3]); 22516var mx_cell_noise_vec3_0 = /* @__PURE__ */ Fn(([p_immutable]) => { 22517 const p = float(p_immutable).toVar(); 22518 const ix = int(mx_floor(p)).toVar(); 22519 return vec3(mx_bits_to_01(mx_hash_int(ix, int(0))), mx_bits_to_01(mx_hash_int(ix, int(1))), mx_bits_to_01(mx_hash_int(ix, int(2)))); 22520}).setLayout({ 22521 name: "mx_cell_noise_vec3_0", 22522 type: "vec3", 22523 inputs: [ 22524 { name: "p", type: "float" } 22525 ] 22526}); 22527var mx_cell_noise_vec3_1 = /* @__PURE__ */ Fn(([p_immutable]) => { 22528 const p = vec2(p_immutable).toVar(); 22529 const ix = int(mx_floor(p.x)).toVar(); 22530 const iy = int(mx_floor(p.y)).toVar(); 22531 return vec3(mx_bits_to_01(mx_hash_int(ix, iy, int(0))), mx_bits_to_01(mx_hash_int(ix, iy, int(1))), mx_bits_to_01(mx_hash_int(ix, iy, int(2)))); 22532}).setLayout({ 22533 name: "mx_cell_noise_vec3_1", 22534 type: "vec3", 22535 inputs: [ 22536 { name: "p", type: "vec2" } 22537 ] 22538}); 22539var mx_cell_noise_vec3_2 = /* @__PURE__ */ Fn(([p_immutable]) => { 22540 const p = vec3(p_immutable).toVar(); 22541 const ix = int(mx_floor(p.x)).toVar(); 22542 const iy = int(mx_floor(p.y)).toVar(); 22543 const iz = int(mx_floor(p.z)).toVar(); 22544 return vec3(mx_bits_to_01(mx_hash_int(ix, iy, iz, int(0))), mx_bits_to_01(mx_hash_int(ix, iy, iz, int(1))), mx_bits_to_01(mx_hash_int(ix, iy, iz, int(2)))); 22545}).setLayout({ 22546 name: "mx_cell_noise_vec3_2", 22547 type: "vec3", 22548 inputs: [ 22549 { name: "p", type: "vec3" } 22550 ] 22551}); 22552var mx_cell_noise_vec3_3 = /* @__PURE__ */ Fn(([p_immutable]) => { 22553 const p = vec4(p_immutable).toVar(); 22554 const ix = int(mx_floor(p.x)).toVar(); 22555 const iy = int(mx_floor(p.y)).toVar(); 22556 const iz = int(mx_floor(p.z)).toVar(); 22557 const iw = int(mx_floor(p.w)).toVar(); 22558 return vec3(mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, int(0))), mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, int(1))), mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, int(2)))); 22559}).setLayout({ 22560 name: "mx_cell_noise_vec3_3", 22561 type: "vec3", 22562 inputs: [ 22563 { name: "p", type: "vec4" } 22564 ] 22565}); 22566var mx_cell_noise_vec3 = /* @__PURE__ */ overloadingFn([mx_cell_noise_vec3_0, mx_cell_noise_vec3_1, mx_cell_noise_vec3_2, mx_cell_noise_vec3_3]); 22567var mx_fractal_noise_float$1 = /* @__PURE__ */ Fn(([p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable]) => { 22568 const diminish = float(diminish_immutable).toVar(); 22569 const lacunarity = float(lacunarity_immutable).toVar(); 22570 const octaves = int(octaves_immutable).toVar(); 22571 const p = vec3(p_immutable).toVar(); 22572 const result = float(0).toVar(); 22573 const amplitude = float(1).toVar(); 22574 Loop(octaves, () => { 22575 result.addAssign(amplitude.mul(mx_perlin_noise_float(p))); 22576 amplitude.mulAssign(diminish); 22577 p.mulAssign(lacunarity); 22578 }); 22579 return result; 22580}).setLayout({ 22581 name: "mx_fractal_noise_float", 22582 type: "float", 22583 inputs: [ 22584 { name: "p", type: "vec3" }, 22585 { name: "octaves", type: "int" }, 22586 { name: "lacunarity", type: "float" }, 22587 { name: "diminish", type: "float" } 22588 ] 22589}); 22590var mx_fractal_noise_vec3$1 = /* @__PURE__ */ Fn(([p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable]) => { 22591 const diminish = float(diminish_immutable).toVar(); 22592 const lacunarity = float(lacunarity_immutable).toVar(); 22593 const octaves = int(octaves_immutable).toVar(); 22594 const p = vec3(p_immutable).toVar(); 22595 const result = vec3(0).toVar(); 22596 const amplitude = float(1).toVar(); 22597 Loop(octaves, () => { 22598 result.addAssign(amplitude.mul(mx_perlin_noise_vec3(p))); 22599 amplitude.mulAssign(diminish); 22600 p.mulAssign(lacunarity); 22601 }); 22602 return result; 22603}).setLayout({ 22604 name: "mx_fractal_noise_vec3", 22605 type: "vec3", 22606 inputs: [ 22607 { name: "p", type: "vec3" }, 22608 { name: "octaves", type: "int" }, 22609 { name: "lacunarity", type: "float" }, 22610 { name: "diminish", type: "float" } 22611 ] 22612}); 22613var mx_fractal_noise_vec2$1 = /* @__PURE__ */ Fn(([p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable]) => { 22614 const diminish = float(diminish_immutable).toVar(); 22615 const lacunarity = float(lacunarity_immutable).toVar(); 22616 const octaves = int(octaves_immutable).toVar(); 22617 const p = vec3(p_immutable).toVar(); 22618 return vec2(mx_fractal_noise_float$1(p, octaves, lacunarity, diminish), mx_fractal_noise_float$1(p.add(vec3(int(19), int(193), int(17))), octaves, lacunarity, diminish)); 22619}).setLayout({ 22620 name: "mx_fractal_noise_vec2", 22621 type: "vec2", 22622 inputs: [ 22623 { name: "p", type: "vec3" }, 22624 { name: "octaves", type: "int" }, 22625 { name: "lacunarity", type: "float" }, 22626 { name: "diminish", type: "float" } 22627 ] 22628}); 22629var mx_fractal_noise_vec4$1 = /* @__PURE__ */ Fn(([p_immutable, octaves_immutable, lacunarity_immutable, diminish_immutable]) => { 22630 const diminish = float(diminish_immutable).toVar(); 22631 const lacunarity = float(lacunarity_immutable).toVar(); 22632 const octaves = int(octaves_immutable).toVar(); 22633 const p = vec3(p_immutable).toVar(); 22634 const c = vec3(mx_fractal_noise_vec3$1(p, octaves, lacunarity, diminish)).toVar(); 22635 const f = float(mx_fractal_noise_float$1(p.add(vec3(int(19), int(193), int(17))), octaves, lacunarity, diminish)).toVar(); 22636 return vec4(c, f); 22637}).setLayout({ 22638 name: "mx_fractal_noise_vec4", 22639 type: "vec4", 22640 inputs: [ 22641 { name: "p", type: "vec3" }, 22642 { name: "octaves", type: "int" }, 22643 { name: "lacunarity", type: "float" }, 22644 { name: "diminish", type: "float" } 22645 ] 22646}); 22647var mx_worley_distance_0 = /* @__PURE__ */ Fn(([p_immutable, x_immutable, y_immutable, xoff_immutable, yoff_immutable, jitter_immutable, metric_immutable]) => { 22648 const metric = int(metric_immutable).toVar(); 22649 const jitter = float(jitter_immutable).toVar(); 22650 const yoff = int(yoff_immutable).toVar(); 22651 const xoff = int(xoff_immutable).toVar(); 22652 const y = int(y_immutable).toVar(); 22653 const x = int(x_immutable).toVar(); 22654 const p = vec2(p_immutable).toVar(); 22655 const tmp = vec3(mx_cell_noise_vec3(vec2(x.add(xoff), y.add(yoff)))).toVar(); 22656 const off = vec2(tmp.x, tmp.y).toVar(); 22657 off.subAssign(0.5); 22658 off.mulAssign(jitter); 22659 off.addAssign(0.5); 22660 const cellpos = vec2(vec2(float(x), float(y)).add(off)).toVar(); 22661 const diff = vec2(cellpos.sub(p)).toVar(); 22662 If(metric.equal(int(2)), () => { 22663 return abs(diff.x).add(abs(diff.y)); 22664 }); 22665 If(metric.equal(int(3)), () => { 22666 return max$1(abs(diff.x), abs(diff.y)); 22667 }); 22668 return dot(diff, diff); 22669}).setLayout({ 22670 name: "mx_worley_distance_0", 22671 type: "float", 22672 inputs: [ 22673 { name: "p", type: "vec2" }, 22674 { name: "x", type: "int" }, 22675 { name: "y", type: "int" }, 22676 { name: "xoff", type: "int" }, 22677 { name: "yoff", type: "int" }, 22678 { name: "jitter", type: "float" }, 22679 { name: "metric", type: "int" } 22680 ] 22681}); 22682var mx_worley_distance_1 = /* @__PURE__ */ Fn(([p_immutable, x_immutable, y_immutable, z_immutable, xoff_immutable, yoff_immutable, zoff_immutable, jitter_immutable, metric_immutable]) => { 22683 const metric = int(metric_immutable).toVar(); 22684 const jitter = float(jitter_immutable).toVar(); 22685 const zoff = int(zoff_immutable).toVar(); 22686 const yoff = int(yoff_immutable).toVar(); 22687 const xoff = int(xoff_immutable).toVar(); 22688 const z = int(z_immutable).toVar(); 22689 const y = int(y_immutable).toVar(); 22690 const x = int(x_immutable).toVar(); 22691 const p = vec3(p_immutable).toVar(); 22692 const off = vec3(mx_cell_noise_vec3(vec3(x.add(xoff), y.add(yoff), z.add(zoff)))).toVar(); 22693 off.subAssign(0.5); 22694 off.mulAssign(jitter); 22695 off.addAssign(0.5); 22696 const cellpos = vec3(vec3(float(x), float(y), float(z)).add(off)).toVar(); 22697 const diff = vec3(cellpos.sub(p)).toVar(); 22698 If(metric.equal(int(2)), () => { 22699 return abs(diff.x).add(abs(diff.y)).add(abs(diff.z)); 22700 }); 22701 If(metric.equal(int(3)), () => { 22702 return max$1(abs(diff.x), abs(diff.y), abs(diff.z)); 22703 }); 22704 return dot(diff, diff); 22705}).setLayout({ 22706 name: "mx_worley_distance_1", 22707 type: "float", 22708 inputs: [ 22709 { name: "p", type: "vec3" }, 22710 { name: "x", type: "int" }, 22711 { name: "y", type: "int" }, 22712 { name: "z", type: "int" }, 22713 { name: "xoff", type: "int" }, 22714 { name: "yoff", type: "int" }, 22715 { name: "zoff", type: "int" }, 22716 { name: "jitter", type: "float" }, 22717 { name: "metric", type: "int" } 22718 ] 22719}); 22720var mx_worley_distance = /* @__PURE__ */ overloadingFn([mx_worley_distance_0, mx_worley_distance_1]); 22721var mx_worley_noise_float_0 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22722 const metric = int(metric_immutable).toVar(); 22723 const jitter = float(jitter_immutable).toVar(); 22724 const p = vec2(p_immutable).toVar(); 22725 const X = int().toVar(), Y = int().toVar(); 22726 const localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)).toVar(); 22727 const sqdist = float(1e6).toVar(); 22728 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22729 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22730 const dist = float(mx_worley_distance(localpos, x, y, X, Y, jitter, metric)).toVar(); 22731 sqdist.assign(min$1(sqdist, dist)); 22732 }); 22733 }); 22734 If(metric.equal(int(0)), () => { 22735 sqdist.assign(sqrt(sqdist)); 22736 }); 22737 return sqdist; 22738}).setLayout({ 22739 name: "mx_worley_noise_float_0", 22740 type: "float", 22741 inputs: [ 22742 { name: "p", type: "vec2" }, 22743 { name: "jitter", type: "float" }, 22744 { name: "metric", type: "int" } 22745 ] 22746}); 22747var mx_worley_noise_vec2_0 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22748 const metric = int(metric_immutable).toVar(); 22749 const jitter = float(jitter_immutable).toVar(); 22750 const p = vec2(p_immutable).toVar(); 22751 const X = int().toVar(), Y = int().toVar(); 22752 const localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)).toVar(); 22753 const sqdist = vec2(1e6, 1e6).toVar(); 22754 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22755 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22756 const dist = float(mx_worley_distance(localpos, x, y, X, Y, jitter, metric)).toVar(); 22757 If(dist.lessThan(sqdist.x), () => { 22758 sqdist.y.assign(sqdist.x); 22759 sqdist.x.assign(dist); 22760 }).ElseIf(dist.lessThan(sqdist.y), () => { 22761 sqdist.y.assign(dist); 22762 }); 22763 }); 22764 }); 22765 If(metric.equal(int(0)), () => { 22766 sqdist.assign(sqrt(sqdist)); 22767 }); 22768 return sqdist; 22769}).setLayout({ 22770 name: "mx_worley_noise_vec2_0", 22771 type: "vec2", 22772 inputs: [ 22773 { name: "p", type: "vec2" }, 22774 { name: "jitter", type: "float" }, 22775 { name: "metric", type: "int" } 22776 ] 22777}); 22778var mx_worley_noise_vec3_0 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22779 const metric = int(metric_immutable).toVar(); 22780 const jitter = float(jitter_immutable).toVar(); 22781 const p = vec2(p_immutable).toVar(); 22782 const X = int().toVar(), Y = int().toVar(); 22783 const localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)).toVar(); 22784 const sqdist = vec3(1e6, 1e6, 1e6).toVar(); 22785 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22786 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22787 const dist = float(mx_worley_distance(localpos, x, y, X, Y, jitter, metric)).toVar(); 22788 If(dist.lessThan(sqdist.x), () => { 22789 sqdist.z.assign(sqdist.y); 22790 sqdist.y.assign(sqdist.x); 22791 sqdist.x.assign(dist); 22792 }).ElseIf(dist.lessThan(sqdist.y), () => { 22793 sqdist.z.assign(sqdist.y); 22794 sqdist.y.assign(dist); 22795 }).ElseIf(dist.lessThan(sqdist.z), () => { 22796 sqdist.z.assign(dist); 22797 }); 22798 }); 22799 }); 22800 If(metric.equal(int(0)), () => { 22801 sqdist.assign(sqrt(sqdist)); 22802 }); 22803 return sqdist; 22804}).setLayout({ 22805 name: "mx_worley_noise_vec3_0", 22806 type: "vec3", 22807 inputs: [ 22808 { name: "p", type: "vec2" }, 22809 { name: "jitter", type: "float" }, 22810 { name: "metric", type: "int" } 22811 ] 22812}); 22813var mx_worley_noise_float_1 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22814 const metric = int(metric_immutable).toVar(); 22815 const jitter = float(jitter_immutable).toVar(); 22816 const p = vec3(p_immutable).toVar(); 22817 const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); 22818 const localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)).toVar(); 22819 const sqdist = float(1e6).toVar(); 22820 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22821 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22822 Loop({ start: -1, end: int(1), name: "z", condition: "<=" }, ({ z }) => { 22823 const dist = float(mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric)).toVar(); 22824 sqdist.assign(min$1(sqdist, dist)); 22825 }); 22826 }); 22827 }); 22828 If(metric.equal(int(0)), () => { 22829 sqdist.assign(sqrt(sqdist)); 22830 }); 22831 return sqdist; 22832}).setLayout({ 22833 name: "mx_worley_noise_float_1", 22834 type: "float", 22835 inputs: [ 22836 { name: "p", type: "vec3" }, 22837 { name: "jitter", type: "float" }, 22838 { name: "metric", type: "int" } 22839 ] 22840}); 22841var mx_worley_noise_float$1 = /* @__PURE__ */ overloadingFn([mx_worley_noise_float_0, mx_worley_noise_float_1]); 22842var mx_worley_noise_vec2_1 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22843 const metric = int(metric_immutable).toVar(); 22844 const jitter = float(jitter_immutable).toVar(); 22845 const p = vec3(p_immutable).toVar(); 22846 const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); 22847 const localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)).toVar(); 22848 const sqdist = vec2(1e6, 1e6).toVar(); 22849 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22850 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22851 Loop({ start: -1, end: int(1), name: "z", condition: "<=" }, ({ z }) => { 22852 const dist = float(mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric)).toVar(); 22853 If(dist.lessThan(sqdist.x), () => { 22854 sqdist.y.assign(sqdist.x); 22855 sqdist.x.assign(dist); 22856 }).ElseIf(dist.lessThan(sqdist.y), () => { 22857 sqdist.y.assign(dist); 22858 }); 22859 }); 22860 }); 22861 }); 22862 If(metric.equal(int(0)), () => { 22863 sqdist.assign(sqrt(sqdist)); 22864 }); 22865 return sqdist; 22866}).setLayout({ 22867 name: "mx_worley_noise_vec2_1", 22868 type: "vec2", 22869 inputs: [ 22870 { name: "p", type: "vec3" }, 22871 { name: "jitter", type: "float" }, 22872 { name: "metric", type: "int" } 22873 ] 22874}); 22875var mx_worley_noise_vec2$1 = /* @__PURE__ */ overloadingFn([mx_worley_noise_vec2_0, mx_worley_noise_vec2_1]); 22876var mx_worley_noise_vec3_1 = /* @__PURE__ */ Fn(([p_immutable, jitter_immutable, metric_immutable]) => { 22877 const metric = int(metric_immutable).toVar(); 22878 const jitter = float(jitter_immutable).toVar(); 22879 const p = vec3(p_immutable).toVar(); 22880 const X = int().toVar(), Y = int().toVar(), Z = int().toVar(); 22881 const localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)).toVar(); 22882 const sqdist = vec3(1e6, 1e6, 1e6).toVar(); 22883 Loop({ start: -1, end: int(1), name: "x", condition: "<=" }, ({ x }) => { 22884 Loop({ start: -1, end: int(1), name: "y", condition: "<=" }, ({ y }) => { 22885 Loop({ start: -1, end: int(1), name: "z", condition: "<=" }, ({ z }) => { 22886 const dist = float(mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric)).toVar(); 22887 If(dist.lessThan(sqdist.x), () => { 22888 sqdist.z.assign(sqdist.y); 22889 sqdist.y.assign(sqdist.x); 22890 sqdist.x.assign(dist); 22891 }).ElseIf(dist.lessThan(sqdist.y), () => { 22892 sqdist.z.assign(sqdist.y); 22893 sqdist.y.assign(dist); 22894 }).ElseIf(dist.lessThan(sqdist.z), () => { 22895 sqdist.z.assign(dist); 22896 }); 22897 }); 22898 }); 22899 }); 22900 If(metric.equal(int(0)), () => { 22901 sqdist.assign(sqrt(sqdist)); 22902 }); 22903 return sqdist; 22904}).setLayout({ 22905 name: "mx_worley_noise_vec3_1", 22906 type: "vec3", 22907 inputs: [ 22908 { name: "p", type: "vec3" }, 22909 { name: "jitter", type: "float" }, 22910 { name: "metric", type: "int" } 22911 ] 22912}); 22913var mx_worley_noise_vec3$1 = /* @__PURE__ */ overloadingFn([mx_worley_noise_vec3_0, mx_worley_noise_vec3_1]); 22914var mx_unifiednoise2d$1 = /* @__PURE__ */ Fn(([ 22915 noiseType_immutable, 22916 texcoord_immutable, 22917 freq_immutable, 22918 offset_immutable, 22919 jitter_immutable, 22920 outmin_immutable, 22921 outmax_immutable, 22922 clampoutput_immutable, 22923 octaves_immutable, 22924 lacunarity_immutable, 22925 diminish_immutable 22926]) => { 22927 const noiseType = int(noiseType_immutable).toVar(); 22928 const texcoord = vec2(texcoord_immutable).toVar(); 22929 const freq = vec2(freq_immutable).toVar(); 22930 const offset3 = vec2(offset_immutable).toVar(); 22931 const jitter = float(jitter_immutable).toVar(); 22932 const outmin = float(outmin_immutable).toVar(); 22933 const outmax = float(outmax_immutable).toVar(); 22934 const clampoutput = bool(clampoutput_immutable).toVar(); 22935 const octaves = int(octaves_immutable).toVar(); 22936 const lacunarity = float(lacunarity_immutable).toVar(); 22937 const diminish = float(diminish_immutable).toVar(); 22938 const p = texcoord.mul(freq).add(offset3); 22939 const result = float(0).toVar(); 22940 If(noiseType.equal(int(0)), () => { 22941 result.assign(mx_perlin_noise_vec3(p)); 22942 }); 22943 If(noiseType.equal(int(1)), () => { 22944 result.assign(mx_cell_noise_vec3(p)); 22945 }); 22946 If(noiseType.equal(int(2)), () => { 22947 result.assign(mx_worley_noise_vec3$1(p, jitter, int(0))); 22948 }); 22949 If(noiseType.equal(int(3)), () => { 22950 result.assign(mx_fractal_noise_vec3$1(vec3(p, 0), octaves, lacunarity, diminish)); 22951 }); 22952 result.assign(result.mul(outmax.sub(outmin)).add(outmin)); 22953 If(clampoutput, () => { 22954 result.assign(clamp(result, outmin, outmax)); 22955 }); 22956 return result; 22957}).setLayout({ 22958 name: "mx_unifiednoise2d", 22959 type: "float", 22960 inputs: [ 22961 { name: "noiseType", type: "int" }, 22962 { name: "texcoord", type: "vec2" }, 22963 { name: "freq", type: "vec2" }, 22964 { name: "offset", type: "vec2" }, 22965 { name: "jitter", type: "float" }, 22966 { name: "outmin", type: "float" }, 22967 { name: "outmax", type: "float" }, 22968 { name: "clampoutput", type: "bool" }, 22969 { name: "octaves", type: "int" }, 22970 { name: "lacunarity", type: "float" }, 22971 { name: "diminish", type: "float" } 22972 ] 22973}); 22974var mx_unifiednoise3d$1 = /* @__PURE__ */ Fn(([ 22975 noiseType_immutable, 22976 position_immutable, 22977 freq_immutable, 22978 offset_immutable, 22979 jitter_immutable, 22980 outmin_immutable, 22981 outmax_immutable, 22982 clampoutput_immutable, 22983 octaves_immutable, 22984 lacunarity_immutable, 22985 diminish_immutable 22986]) => { 22987 const noiseType = int(noiseType_immutable).toVar(); 22988 const position = vec3(position_immutable).toVar(); 22989 const freq = vec3(freq_immutable).toVar(); 22990 const offset3 = vec3(offset_immutable).toVar(); 22991 const jitter = float(jitter_immutable).toVar(); 22992 const outmin = float(outmin_immutable).toVar(); 22993 const outmax = float(outmax_immutable).toVar(); 22994 const clampoutput = bool(clampoutput_immutable).toVar(); 22995 const octaves = int(octaves_immutable).toVar(); 22996 const lacunarity = float(lacunarity_immutable).toVar(); 22997 const diminish = float(diminish_immutable).toVar(); 22998 const p = position.mul(freq).add(offset3); 22999 const result = float(0).toVar(); 23000 If(noiseType.equal(int(0)), () => { 23001 result.assign(mx_perlin_noise_vec3(p)); 23002 }); 23003 If(noiseType.equal(int(1)), () => { 23004 result.assign(mx_cell_noise_vec3(p)); 23005 }); 23006 If(noiseType.equal(int(2)), () => { 23007 result.assign(mx_worley_noise_vec3$1(p, jitter, int(0))); 23008 }); 23009 If(noiseType.equal(int(3)), () => { 23010 result.assign(mx_fractal_noise_vec3$1(p, octaves, lacunarity, diminish)); 23011 }); 23012 result.assign(result.mul(outmax.sub(outmin)).add(outmin)); 23013 If(clampoutput, () => { 23014 result.assign(clamp(result, outmin, outmax)); 23015 }); 23016 return result; 23017}).setLayout({ 23018 name: "mx_unifiednoise3d", 23019 type: "float", 23020 inputs: [ 23021 { name: "noiseType", type: "int" }, 23022 { name: "position", type: "vec3" }, 23023 { name: "freq", type: "vec3" }, 23024 { name: "offset", type: "vec3" }, 23025 { name: "jitter", type: "float" }, 23026 { name: "outmin", type: "float" }, 23027 { name: "outmax", type: "float" }, 23028 { name: "clampoutput", type: "bool" }, 23029 { name: "octaves", type: "int" }, 23030 { name: "lacunarity", type: "float" }, 23031 { name: "diminish", type: "float" } 23032 ] 23033}); 23034var mx_hsvtorgb = /* @__PURE__ */ Fn(([hsv]) => { 23035 const s = hsv.y; 23036 const v = hsv.z; 23037 const result = vec3().toVar(); 23038 If(s.lessThan(1e-4), () => { 23039 result.assign(vec3(v, v, v)); 23040 }).Else(() => { 23041 let h = hsv.x; 23042 h = h.sub(floor(h)).mul(6).toVar(); 23043 const hi = int(trunc(h)); 23044 const f = h.sub(float(hi)); 23045 const p = v.mul(s.oneMinus()); 23046 const q = v.mul(s.mul(f).oneMinus()); 23047 const t = v.mul(s.mul(f.oneMinus()).oneMinus()); 23048 If(hi.equal(int(0)), () => { 23049 result.assign(vec3(v, t, p)); 23050 }).ElseIf(hi.equal(int(1)), () => { 23051 result.assign(vec3(q, v, p)); 23052 }).ElseIf(hi.equal(int(2)), () => { 23053 result.assign(vec3(p, v, t)); 23054 }).ElseIf(hi.equal(int(3)), () => { 23055 result.assign(vec3(p, q, v)); 23056 }).ElseIf(hi.equal(int(4)), () => { 23057 result.assign(vec3(t, p, v)); 23058 }).Else(() => { 23059 result.assign(vec3(v, p, q)); 23060 }); 23061 }); 23062 return result; 23063}).setLayout({ 23064 name: "mx_hsvtorgb", 23065 type: "vec3", 23066 inputs: [ 23067 { name: "hsv", type: "vec3" } 23068 ] 23069}); 23070var mx_rgbtohsv = /* @__PURE__ */ Fn(([c_immutable]) => { 23071 const c = vec3(c_immutable).toVar(); 23072 const r = float(c.x).toVar(); 23073 const g = float(c.y).toVar(); 23074 const b = float(c.z).toVar(); 23075 const mincomp = float(min$1(r, min$1(g, b))).toVar(); 23076 const maxcomp = float(max$1(r, max$1(g, b))).toVar(); 23077 const delta = float(maxcomp.sub(mincomp)).toVar(); 23078 const h = float().toVar(), s = float().toVar(), v = float().toVar(); 23079 v.assign(maxcomp); 23080 If(maxcomp.greaterThan(0), () => { 23081 s.assign(delta.div(maxcomp)); 23082 }).Else(() => { 23083 s.assign(0); 23084 }); 23085 If(s.lessThanEqual(0), () => { 23086 h.assign(0); 23087 }).Else(() => { 23088 If(r.greaterThanEqual(maxcomp), () => { 23089 h.assign(g.sub(b).div(delta)); 23090 }).ElseIf(g.greaterThanEqual(maxcomp), () => { 23091 h.assign(add(2, b.sub(r).div(delta))); 23092 }).Else(() => { 23093 h.assign(add(4, r.sub(g).div(delta))); 23094 }); 23095 h.mulAssign(1 / 6); 23096 If(h.lessThan(0), () => { 23097 h.addAssign(1); 23098 }); 23099 }); 23100 return vec3(h, s, v); 23101}).setLayout({ 23102 name: "mx_rgbtohsv", 23103 type: "vec3", 23104 inputs: [ 23105 { name: "c", type: "vec3" } 23106 ] 23107}); 23108var mx_srgb_texture_to_lin_rec709 = /* @__PURE__ */ Fn(([color_immutable]) => { 23109 const color3 = vec3(color_immutable).toVar(); 23110 const isAbove = bvec3(greaterThan(color3, vec3(0.04045))).toVar(); 23111 const linSeg = vec3(color3.div(12.92)).toVar(); 23112 const powSeg = vec3(pow(max$1(color3.add(vec3(0.055)), vec3(0)).div(1.055), vec3(2.4))).toVar(); 23113 return mix(linSeg, powSeg, isAbove); 23114}).setLayout({ 23115 name: "mx_srgb_texture_to_lin_rec709", 23116 type: "vec3", 23117 inputs: [ 23118 { name: "color", type: "vec3" } 23119 ] 23120}); 23121var mx_aastep = (threshold, value) => { 23122 threshold = float(threshold); 23123 value = float(value); 23124 const afwidth = vec2(value.dFdx(), value.dFdy()).length().mul(0.7071067811865476); 23125 return smoothstep(threshold.sub(afwidth), threshold.add(afwidth), value); 23126}; 23127var _ramp = (a, b, uv3, p) => mix(a, b, uv3[p].clamp()); 23128var mx_ramplr = (valuel, valuer, texcoord = uv$1()) => _ramp(valuel, valuer, texcoord, "x"); 23129var mx_ramptb = (valuet, valueb, texcoord = uv$1()) => _ramp(valuet, valueb, texcoord, "y"); 23130var mx_ramp4 = (valuetl, valuetr, valuebl, valuebr, texcoord = uv$1()) => { 23131 const u = texcoord.x.clamp(); 23132 const v = texcoord.y.clamp(); 23133 const top = mix(valuetl, valuetr, u); 23134 const bottom = mix(valuebl, valuebr, u); 23135 return mix(top, bottom, v); 23136}; 23137var _split = (a, b, center, uv3, p) => mix(a, b, mx_aastep(center, uv3[p])); 23138var mx_splitlr = (valuel, valuer, center, texcoord = uv$1()) => _split(valuel, valuer, center, texcoord, "x"); 23139var mx_splittb = (valuet, valueb, center, texcoord = uv$1()) => _split(valuet, valueb, center, texcoord, "y"); 23140var mx_transform_uv = (uv_scale = 1, uv_offset = 0, uv_geo = uv$1()) => uv_geo.mul(uv_scale).add(uv_offset); 23141var mx_safepower = (in1, in2 = 1) => { 23142 in1 = float(in1); 23143 return in1.abs().pow(in2).mul(in1.sign()); 23144}; 23145var mx_contrast = (input, amount = 1, pivot = 0.5) => float(input).sub(pivot).mul(amount).add(pivot); 23146var mx_noise_float = (texcoord = uv$1(), amplitude = 1, pivot = 0) => mx_perlin_noise_float(texcoord.convert("vec2|vec3")).mul(amplitude).add(pivot); 23147var mx_noise_vec3 = (texcoord = uv$1(), amplitude = 1, pivot = 0) => mx_perlin_noise_vec3(texcoord.convert("vec2|vec3")).mul(amplitude).add(pivot); 23148var mx_noise_vec4 = (texcoord = uv$1(), amplitude = 1, pivot = 0) => { 23149 texcoord = texcoord.convert("vec2|vec3"); 23150 const noise_vec4 = vec4(mx_perlin_noise_vec3(texcoord), mx_perlin_noise_float(texcoord.add(vec2(19, 73)))); 23151 return noise_vec4.mul(amplitude).add(pivot); 23152}; 23153var mx_unifiednoise2d = (noiseType, texcoord = uv$1(), freq = vec2(1, 1), offset3 = vec2(0, 0), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = 0.5) => mx_unifiednoise2d$1(noiseType, texcoord.convert("vec2|vec3"), freq, offset3, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish); 23154var mx_unifiednoise3d = (noiseType, texcoord = uv$1(), freq = vec2(1, 1), offset3 = vec2(0, 0), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = 0.5) => mx_unifiednoise3d$1(noiseType, texcoord.convert("vec2|vec3"), freq, offset3, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish); 23155var mx_worley_noise_float = (texcoord = uv$1(), jitter = 1) => mx_worley_noise_float$1(texcoord.convert("vec2|vec3"), jitter, int(1)); 23156var mx_worley_noise_vec2 = (texcoord = uv$1(), jitter = 1) => mx_worley_noise_vec2$1(texcoord.convert("vec2|vec3"), jitter, int(1)); 23157var mx_worley_noise_vec3 = (texcoord = uv$1(), jitter = 1) => mx_worley_noise_vec3$1(texcoord.convert("vec2|vec3"), jitter, int(1)); 23158var mx_cell_noise_float = (texcoord = uv$1()) => mx_cell_noise_float$1(texcoord.convert("vec2|vec3")); 23159var mx_fractal_noise_float = (position = uv$1(), octaves = 3, lacunarity = 2, diminish = 0.5, amplitude = 1) => mx_fractal_noise_float$1(position, int(octaves), lacunarity, diminish).mul(amplitude); 23160var mx_fractal_noise_vec2 = (position = uv$1(), octaves = 3, lacunarity = 2, diminish = 0.5, amplitude = 1) => mx_fractal_noise_vec2$1(position, int(octaves), lacunarity, diminish).mul(amplitude); 23161var mx_fractal_noise_vec3 = (position = uv$1(), octaves = 3, lacunarity = 2, diminish = 0.5, amplitude = 1) => mx_fractal_noise_vec3$1(position, int(octaves), lacunarity, diminish).mul(amplitude); 23162var mx_fractal_noise_vec4 = (position = uv$1(), octaves = 3, lacunarity = 2, diminish = 0.5, amplitude = 1) => mx_fractal_noise_vec4$1(position, int(octaves), lacunarity, diminish).mul(amplitude); 23163var mx_add = (in1, in2 = float(0)) => add(in1, in2); 23164var mx_subtract = (in1, in2 = float(0)) => sub(in1, in2); 23165var mx_multiply = (in1, in2 = float(1)) => mul(in1, in2); 23166var mx_divide = (in1, in2 = float(1)) => div(in1, in2); 23167var mx_modulo = (in1, in2 = float(1)) => mod(in1, in2); 23168var mx_power = (in1, in2 = float(1)) => pow(in1, in2); 23169var mx_atan2 = (in1 = float(0), in2 = float(1)) => atan(in1, in2); 23170var mx_timer = () => time; 23171var mx_frame = () => frameId; 23172var mx_invert = (in1, amount = float(1)) => sub(amount, in1); 23173var mx_ifgreater = (value1, value2, in1, in2) => value1.greaterThan(value2).mix(in1, in2); 23174var mx_ifgreatereq = (value1, value2, in1, in2) => value1.greaterThanEqual(value2).mix(in1, in2); 23175var mx_ifequal = (value1, value2, in1, in2) => value1.equal(value2).mix(in1, in2); 23176var mx_separate = (in1, channelOrOut = null) => { 23177 if (typeof channelOrOut === "string") { 23178 const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 }; 23179 const c = channelOrOut.replace(/^out/, "").toLowerCase(); 23180 if (map[c] !== void 0) return in1.element(map[c]); 23181 } 23182 if (typeof channelOrOut === "number") { 23183 return in1.element(channelOrOut); 23184 } 23185 if (typeof channelOrOut === "string" && channelOrOut.length === 1) { 23186 const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 }; 23187 if (map[channelOrOut] !== void 0) return in1.element(map[channelOrOut]); 23188 } 23189 return in1; 23190}; 23191var mx_place2d = (texcoord, pivot = vec2(0.5, 0.5), scale2 = vec2(1, 1), rotate3 = float(0), offset3 = vec2(0, 0)) => { 23192 let uv3 = texcoord; 23193 if (pivot) uv3 = uv3.sub(pivot); 23194 if (scale2) uv3 = uv3.mul(scale2); 23195 if (rotate3) { 23196 const rad = rotate3.mul(Math.PI / 180); 23197 const cosR = rad.cos(); 23198 const sinR = rad.sin(); 23199 uv3 = vec2( 23200 uv3.x.mul(cosR).sub(uv3.y.mul(sinR)), 23201 uv3.x.mul(sinR).add(uv3.y.mul(cosR)) 23202 ); 23203 } 23204 if (pivot) uv3 = uv3.add(pivot); 23205 if (offset3) uv3 = uv3.add(offset3); 23206 return uv3; 23207}; 23208var mx_rotate2d = (input, amount) => { 23209 input = vec2(input); 23210 amount = float(amount); 23211 const radians3 = amount.mul(Math.PI / 180); 23212 return rotate(input, radians3); 23213}; 23214var mx_rotate3d = (input, amount, axis) => { 23215 input = vec3(input); 23216 amount = float(amount); 23217 axis = vec3(axis); 23218 const radians3 = amount.mul(Math.PI / 180); 23219 const nAxis = axis.normalize(); 23220 const cosA = radians3.cos(); 23221 const sinA = radians3.sin(); 23222 const oneMinusCosA = float(1).sub(cosA); 23223 const rot = input.mul(cosA).add(nAxis.cross(input).mul(sinA)).add(nAxis.mul(nAxis.dot(input)).mul(oneMinusCosA)); 23224 return rot; 23225}; 23226var mx_heighttonormal = (input, scale2) => { 23227 input = vec3(input); 23228 scale2 = float(scale2); 23229 return bumpMap(input, scale2); 23230}; 23231var getParallaxCorrectNormal = /* @__PURE__ */ Fn(([normal2, cubeSize, cubePos]) => { 23232 const nDir = normalize(normal2).toVar(); 23233 const rbmax = sub(float(0.5).mul(cubeSize.sub(cubePos)), positionWorld).div(nDir).toVar(); 23234 const rbmin = sub(float(-0.5).mul(cubeSize.sub(cubePos)), positionWorld).div(nDir).toVar(); 23235 const rbminmax = vec3().toVar(); 23236 rbminmax.x = nDir.x.greaterThan(float(0)).select(rbmax.x, rbmin.x); 23237 rbminmax.y = nDir.y.greaterThan(float(0)).select(rbmax.y, rbmin.y); 23238 rbminmax.z = nDir.z.greaterThan(float(0)).select(rbmax.z, rbmin.z); 23239 const correction = min$1(rbminmax.x, rbminmax.y, rbminmax.z).toVar(); 23240 const boxIntersection = positionWorld.add(nDir.mul(correction)).toVar(); 23241 return boxIntersection.sub(cubePos); 23242}); 23243var getShIrradianceAt = /* @__PURE__ */ Fn(([normal2, shCoefficients]) => { 23244 const x = normal2.x, y = normal2.y, z = normal2.z; 23245 let result = shCoefficients.element(0).mul(0.886227); 23246 result = result.add(shCoefficients.element(1).mul(2 * 0.511664).mul(y)); 23247 result = result.add(shCoefficients.element(2).mul(2 * 0.511664).mul(z)); 23248 result = result.add(shCoefficients.element(3).mul(2 * 0.511664).mul(x)); 23249 result = result.add(shCoefficients.element(4).mul(2 * 0.429043).mul(x).mul(y)); 23250 result = result.add(shCoefficients.element(5).mul(2 * 0.429043).mul(y).mul(z)); 23251 result = result.add(shCoefficients.element(6).mul(z.mul(z).mul(0.743125).sub(0.247708))); 23252 result = result.add(shCoefficients.element(7).mul(2 * 0.429043).mul(x).mul(z)); 23253 result = result.add(shCoefficients.element(8).mul(0.429043).mul(mul(x, x).sub(mul(y, y)))); 23254 return result; 23255}); 23256var TSL = /* @__PURE__ */ Object.freeze({ 23257 __proto__: null, 23258 BRDF_GGX, 23259 BRDF_Lambert, 23260 BasicPointShadowFilter, 23261 BasicShadowFilter, 23262 Break, 23263 Const, 23264 Continue, 23265 DFGLUT, 23266 D_GGX, 23267 Discard, 23268 EPSILON, 23269 F_Schlick, 23270 Fn, 23271 HALF_PI, 23272 INFINITY, 23273 If, 23274 Loop, 23275 NodeAccess, 23276 NodeShaderStage, 23277 NodeType, 23278 NodeUpdateType, 23279 OnBeforeFrameUpdate, 23280 OnBeforeMaterialUpdate, 23281 OnBeforeObjectUpdate, 23282 OnFrameUpdate, 23283 OnMaterialUpdate, 23284 OnObjectUpdate, 23285 PCFShadowFilter, 23286 PCFSoftShadowFilter, 23287 PI, 23288 PI2, 23289 PointShadowFilter, 23290 Return, 23291 Schlick_to_F0, 23292 ShaderNode, 23293 Stack, 23294 Switch, 23295 TBNViewMatrix, 23296 TWO_PI, 23297 VSMShadowFilter, 23298 V_GGX_SmithCorrelated, 23299 Var, 23300 VarIntent, 23301 abs, 23302 acesFilmicToneMapping, 23303 acos, 23304 acosh, 23305 add, 23306 addMethodChaining, 23307 addNodeElement, 23308 agxToneMapping, 23309 all, 23310 alphaT, 23311 and, 23312 anisotropy, 23313 anisotropyB, 23314 anisotropyT, 23315 any, 23316 append, 23317 array, 23318 arrayBuffer, 23319 asin, 23320 asinh, 23321 assign, 23322 atan, 23323 atanh, 23324 atomicAdd, 23325 atomicAnd, 23326 atomicFunc, 23327 atomicLoad, 23328 atomicMax, 23329 atomicMin, 23330 atomicOr, 23331 atomicStore, 23332 atomicSub, 23333 atomicXor, 23334 attenuationColor, 23335 attenuationDistance, 23336 attribute, 23337 attributeArray, 23338 backgroundBlurriness, 23339 backgroundIntensity, 23340 backgroundRotation, 23341 batch: batch2, 23342 bentNormalView, 23343 billboarding, 23344 bitAnd, 23345 bitNot, 23346 bitOr, 23347 bitXor, 23348 bitangentGeometry, 23349 bitangentLocal, 23350 bitangentView, 23351 bitangentWorld, 23352 bitcast, 23353 blendBurn, 23354 blendColor, 23355 blendDodge, 23356 blendOverlay, 23357 blendScreen, 23358 blur, 23359 bool, 23360 buffer, 23361 bufferAttribute, 23362 builtin, 23363 builtinAOContext, 23364 builtinShadowContext, 23365 bumpMap, 23366 bvec2, 23367 bvec3, 23368 bvec4, 23369 bypass, 23370 cache, 23371 call, 23372 cameraFar, 23373 cameraIndex, 23374 cameraNear, 23375 cameraNormalMatrix, 23376 cameraPosition, 23377 cameraProjectionMatrix, 23378 cameraProjectionMatrixInverse, 23379 cameraViewMatrix, 23380 cameraViewport, 23381 cameraWorldMatrix, 23382 cbrt, 23383 cdl, 23384 ceil, 23385 checker, 23386 cineonToneMapping, 23387 clamp, 23388 clearcoat, 23389 clearcoatNormalView, 23390 clearcoatRoughness, 23391 clipSpace, 23392 code, 23393 color, 23394 colorSpaceToWorking, 23395 colorToDirection, 23396 compute, 23397 computeKernel, 23398 computeSkinning, 23399 context, 23400 convert, 23401 convertColorSpace, 23402 convertToTexture, 23403 cos, 23404 cosh, 23405 countLeadingZeros, 23406 countOneBits, 23407 countTrailingZeros, 23408 cross, 23409 cubeTexture, 23410 cubeTextureBase, 23411 dFdx, 23412 dFdy, 23413 dashSize, 23414 debug, 23415 decrement, 23416 decrementBefore, 23417 defaultBuildStages, 23418 defaultShaderStages, 23419 defined, 23420 degrees, 23421 deltaTime, 23422 densityFogFactor, 23423 depth, 23424 depthPass, 23425 determinant, 23426 difference, 23427 diffuseColor, 23428 diffuseContribution, 23429 directPointLight, 23430 directionToColor, 23431 directionToFaceDirection, 23432 dispersion, 23433 disposeShadowMaterial, 23434 distance, 23435 div, 23436 dot, 23437 drawIndex, 23438 dynamicBufferAttribute, 23439 element, 23440 emissive, 23441 equal, 23442 equirectUV, 23443 exp, 23444 exp2, 23445 exponentialHeightFogFactor, 23446 expression, 23447 faceDirection, 23448 faceForward, 23449 faceforward, 23450 float, 23451 floatBitsToInt, 23452 floatBitsToUint, 23453 floor, 23454 fog, 23455 fract, 23456 frameGroup, 23457 frameId, 23458 frontFacing, 23459 fwidth, 23460 gain, 23461 gapSize, 23462 getConstNodeType, 23463 getCurrentStack, 23464 getDirection, 23465 getDistanceAttenuation, 23466 getGeometryRoughness, 23467 getNormalFromDepth, 23468 getParallaxCorrectNormal, 23469 getRoughness, 23470 getScreenPosition, 23471 getShIrradianceAt, 23472 getShadowMaterial, 23473 getShadowRenderObjectFunction, 23474 getTextureIndex, 23475 getViewPosition, 23476 ggxConvolution, 23477 globalId, 23478 glsl, 23479 glslFn, 23480 grayscale, 23481 greaterThan, 23482 greaterThanEqual, 23483 hash, 23484 highpModelNormalViewMatrix, 23485 highpModelViewMatrix, 23486 hue, 23487 increment, 23488 incrementBefore, 23489 inspector, 23490 instance, 23491 instanceIndex, 23492 instancedArray, 23493 instancedBufferAttribute, 23494 instancedDynamicBufferAttribute, 23495 instancedMesh, 23496 int, 23497 intBitsToFloat, 23498 interleavedGradientNoise, 23499 inverse, 23500 inverseSqrt, 23501 inversesqrt, 23502 invocationLocalIndex, 23503 invocationSubgroupIndex, 23504 ior, 23505 iridescence, 23506 iridescenceIOR, 23507 iridescenceThickness, 23508 isolate, 23509 ivec2, 23510 ivec3, 23511 ivec4, 23512 js, 23513 label, 23514 length, 23515 lengthSq, 23516 lessThan, 23517 lessThanEqual, 23518 lightPosition, 23519 lightProjectionUV, 23520 lightShadowMatrix, 23521 lightTargetDirection, 23522 lightTargetPosition, 23523 lightViewPosition, 23524 lightingContext, 23525 lights, 23526 linearDepth, 23527 linearToneMapping, 23528 localId, 23529 log: log2, 23530 log2: log22, 23531 logarithmicDepthToViewZ, 23532 luminance, 23533 mat2, 23534 mat3, 23535 mat4, 23536 matcapUV, 23537 materialAO, 23538 materialAlphaTest, 23539 materialAnisotropy, 23540 materialAnisotropyVector, 23541 materialAttenuationColor, 23542 materialAttenuationDistance, 23543 materialClearcoat, 23544 materialClearcoatNormal, 23545 materialClearcoatRoughness, 23546 materialColor, 23547 materialDispersion, 23548 materialEmissive, 23549 materialEnvIntensity, 23550 materialEnvRotation, 23551 materialIOR, 23552 materialIridescence, 23553 materialIridescenceIOR, 23554 materialIridescenceThickness, 23555 materialLightMap, 23556 materialLineDashOffset, 23557 materialLineDashSize, 23558 materialLineGapSize, 23559 materialLineScale, 23560 materialLineWidth, 23561 materialMetalness, 23562 materialNormal, 23563 materialOpacity, 23564 materialPointSize, 23565 materialReference, 23566 materialReflectivity, 23567 materialRefractionRatio, 23568 materialRotation, 23569 materialRoughness, 23570 materialSheen, 23571 materialSheenRoughness, 23572 materialShininess, 23573 materialSpecular, 23574 materialSpecularColor, 23575 materialSpecularIntensity, 23576 materialSpecularStrength, 23577 materialThickness, 23578 materialTransmission, 23579 max: max$1, 23580 maxMipLevel, 23581 mediumpModelViewMatrix, 23582 metalness, 23583 min: min$1, 23584 mix, 23585 mixElement, 23586 mod, 23587 modInt, 23588 modelDirection, 23589 modelNormalMatrix, 23590 modelPosition, 23591 modelRadius, 23592 modelScale, 23593 modelViewMatrix, 23594 modelViewPosition, 23595 modelViewProjection, 23596 modelWorldMatrix, 23597 modelWorldMatrixInverse, 23598 morphReference, 23599 mrt, 23600 mul, 23601 mx_aastep, 23602 mx_add, 23603 mx_atan2, 23604 mx_cell_noise_float, 23605 mx_contrast, 23606 mx_divide, 23607 mx_fractal_noise_float, 23608 mx_fractal_noise_vec2, 23609 mx_fractal_noise_vec3, 23610 mx_fractal_noise_vec4, 23611 mx_frame, 23612 mx_heighttonormal, 23613 mx_hsvtorgb, 23614 mx_ifequal, 23615 mx_ifgreater, 23616 mx_ifgreatereq, 23617 mx_invert, 23618 mx_modulo, 23619 mx_multiply, 23620 mx_noise_float, 23621 mx_noise_vec3, 23622 mx_noise_vec4, 23623 mx_place2d, 23624 mx_power, 23625 mx_ramp4, 23626 mx_ramplr, 23627 mx_ramptb, 23628 mx_rgbtohsv, 23629 mx_rotate2d, 23630 mx_rotate3d, 23631 mx_safepower, 23632 mx_separate, 23633 mx_splitlr, 23634 mx_splittb, 23635 mx_srgb_texture_to_lin_rec709, 23636 mx_subtract, 23637 mx_timer, 23638 mx_transform_uv, 23639 mx_unifiednoise2d, 23640 mx_unifiednoise3d, 23641 mx_worley_noise_float, 23642 mx_worley_noise_vec2, 23643 mx_worley_noise_vec3, 23644 negate, 23645 neutralToneMapping, 23646 nodeArray, 23647 nodeImmutable, 23648 nodeObject, 23649 nodeObjectIntent, 23650 nodeObjects, 23651 nodeProxy, 23652 nodeProxyIntent, 23653 normalFlat, 23654 normalGeometry, 23655 normalLocal, 23656 normalMap, 23657 normalView, 23658 normalViewGeometry, 23659 normalWorld, 23660 normalWorldGeometry, 23661 normalize, 23662 not, 23663 notEqual, 23664 numWorkgroups, 23665 objectDirection, 23666 objectGroup, 23667 objectPosition, 23668 objectRadius, 23669 objectScale, 23670 objectViewPosition, 23671 objectWorldMatrix, 23672 oneMinus, 23673 or, 23674 orthographicDepthToViewZ, 23675 oscSawtooth, 23676 oscSine, 23677 oscSquare, 23678 oscTriangle, 23679 output, 23680 outputStruct, 23681 overloadingFn, 23682 packHalf2x16, 23683 packSnorm2x16, 23684 packUnorm2x16, 23685 parabola, 23686 parallaxDirection, 23687 parallaxUV, 23688 parameter, 23689 pass, 23690 passTexture, 23691 pcurve, 23692 perspectiveDepthToViewZ, 23693 pmremTexture, 23694 pointShadow, 23695 pointUV, 23696 pointWidth, 23697 positionGeometry, 23698 positionLocal, 23699 positionPrevious, 23700 positionView, 23701 positionViewDirection, 23702 positionWorld, 23703 positionWorldDirection, 23704 posterize, 23705 pow, 23706 pow2, 23707 pow3, 23708 pow4, 23709 premultiplyAlpha, 23710 property, 23711 quadBroadcast, 23712 quadSwapDiagonal, 23713 quadSwapX, 23714 quadSwapY, 23715 radians, 23716 rand, 23717 range, 23718 rangeFogFactor, 23719 reciprocal, 23720 reference, 23721 referenceBuffer, 23722 reflect, 23723 reflectVector, 23724 reflectView, 23725 reflector, 23726 refract, 23727 refractVector, 23728 refractView, 23729 reinhardToneMapping, 23730 remap, 23731 remapClamp, 23732 renderGroup, 23733 renderOutput, 23734 rendererReference, 23735 replaceDefaultUV, 23736 rotate, 23737 rotateUV, 23738 roughness, 23739 round, 23740 rtt, 23741 sRGBTransferEOTF, 23742 sRGBTransferOETF, 23743 sample, 23744 sampler, 23745 samplerComparison, 23746 saturate, 23747 saturation, 23748 screenCoordinate, 23749 screenDPR, 23750 screenSize, 23751 screenUV, 23752 select, 23753 setCurrentStack, 23754 setName, 23755 shaderStages, 23756 shadow, 23757 shadowPositionWorld, 23758 shapeCircle, 23759 sharedUniformGroup, 23760 sheen, 23761 sheenRoughness, 23762 shiftLeft, 23763 shiftRight, 23764 shininess, 23765 sign, 23766 sin, 23767 sinc, 23768 sinh, 23769 skinning, 23770 smoothstep, 23771 smoothstepElement, 23772 specularColor, 23773 specularColorBlended, 23774 specularF90, 23775 spherizeUV, 23776 split, 23777 spritesheetUV, 23778 sqrt, 23779 stack, 23780 step, 23781 stepElement, 23782 storage, 23783 storageBarrier, 23784 storageTexture, 23785 string, 23786 struct, 23787 sub, 23788 subBuild, 23789 subgroupAdd, 23790 subgroupAll, 23791 subgroupAnd, 23792 subgroupAny, 23793 subgroupBallot, 23794 subgroupBroadcast, 23795 subgroupBroadcastFirst, 23796 subgroupElect, 23797 subgroupExclusiveAdd, 23798 subgroupExclusiveMul, 23799 subgroupInclusiveAdd, 23800 subgroupInclusiveMul, 23801 subgroupIndex, 23802 subgroupMax, 23803 subgroupMin, 23804 subgroupMul, 23805 subgroupOr, 23806 subgroupShuffle, 23807 subgroupShuffleDown, 23808 subgroupShuffleUp, 23809 subgroupShuffleXor, 23810 subgroupSize, 23811 subgroupXor, 23812 tan, 23813 tangentGeometry, 23814 tangentLocal, 23815 tangentView, 23816 tangentWorld, 23817 tanh, 23818 texture, 23819 texture3D, 23820 texture3DLevel, 23821 texture3DLoad, 23822 textureBarrier, 23823 textureBicubic, 23824 textureBicubicLevel, 23825 textureCubeUV, 23826 textureLevel, 23827 textureLoad, 23828 textureSize, 23829 textureStore, 23830 thickness, 23831 time, 23832 toneMapping, 23833 toneMappingExposure, 23834 toonOutlinePass, 23835 transformDirection, 23836 transformNormal, 23837 transformNormalToView, 23838 transformedClearcoatNormalView, 23839 transformedNormalView, 23840 transformedNormalWorld, 23841 transmission, 23842 transpose, 23843 triNoise3D, 23844 triplanarTexture, 23845 triplanarTextures, 23846 trunc, 23847 uint, 23848 uintBitsToFloat, 23849 uniform, 23850 uniformArray, 23851 uniformCubeTexture, 23852 uniformFlow, 23853 uniformGroup, 23854 uniformTexture, 23855 unpackHalf2x16, 23856 unpackNormal, 23857 unpackSnorm2x16, 23858 unpackUnorm2x16, 23859 unpremultiplyAlpha, 23860 userData, 23861 uv: uv$1, 23862 uvec2, 23863 uvec3, 23864 uvec4, 23865 varying, 23866 varyingProperty, 23867 vec2, 23868 vec3, 23869 vec4, 23870 vectorComponents, 23871 velocity, 23872 vertexColor, 23873 vertexIndex, 23874 vertexStage, 23875 vibrance, 23876 viewZToLogarithmicDepth, 23877 viewZToOrthographicDepth, 23878 viewZToPerspectiveDepth, 23879 viewZToReversedOrthographicDepth, 23880 viewZToReversedPerspectiveDepth, 23881 viewport, 23882 viewportCoordinate, 23883 viewportDepthTexture, 23884 viewportLinearDepth, 23885 viewportMipTexture, 23886 viewportOpaqueMipTexture, 23887 viewportResolution, 23888 viewportSafeUV, 23889 viewportSharedTexture, 23890 viewportSize, 23891 viewportTexture, 23892 viewportUV, 23893 vogelDiskSample, 23894 wgsl, 23895 wgslFn, 23896 workgroupArray, 23897 workgroupBarrier, 23898 workgroupId, 23899 workingToColorSpace, 23900 xor 23901}); 23902var _clearColor = /* @__PURE__ */ new Color4(); 23903var Background = class extends DataMap { 23904 /** 23905 * Constructs a new background management component. 23906 * 23907 * @param {Renderer} renderer - The renderer. 23908 * @param {NodeManager} nodes - Renderer component for managing nodes related logic. 23909 */ 23910 constructor(renderer, nodes) { 23911 super(); 23912 this.renderer = renderer; 23913 this.nodes = nodes; 23914 } 23915 /** 23916 * Updates the background for the given scene. Depending on how `Scene.background` 23917 * or `Scene.backgroundNode` are configured, this method might configure a simple clear 23918 * or add a mesh to the render list for rendering the background as a textured plane 23919 * or skybox. 23920 * 23921 * @param {Scene} scene - The scene. 23922 * @param {RenderList} renderList - The current render list. 23923 * @param {RenderContext} renderContext - The current render context. 23924 */ 23925 update(scene, renderList, renderContext) { 23926 const renderer = this.renderer; 23927 const background = this.nodes.getBackgroundNode(scene) || scene.background; 23928 let forceClear = false; 23929 if (background === null) { 23930 renderer._clearColor.getRGB(_clearColor); 23931 _clearColor.a = renderer._clearColor.a; 23932 } else if (background.isColor === true) { 23933 background.getRGB(_clearColor); 23934 _clearColor.a = 1; 23935 forceClear = true; 23936 } else if (background.isNode === true) { 23937 const sceneData = this.get(scene); 23938 const backgroundNode = background; 23939 _clearColor.copy(renderer._clearColor); 23940 let backgroundMesh = sceneData.backgroundMesh; 23941 if (backgroundMesh === void 0) { 23942 let onBackgroundDispose = function() { 23943 background.removeEventListener("dispose", onBackgroundDispose); 23944 backgroundMesh.material.dispose(); 23945 backgroundMesh.geometry.dispose(); 23946 }; 23947 const backgroundMeshNode = vec4(backgroundNode).mul(backgroundIntensity).context({ 23948 // @TODO: Add Texture2D support using node context 23949 getUV: () => backgroundRotation.mul(normalWorldGeometry), 23950 getTextureLevel: () => backgroundBlurriness 23951 }); 23952 const isOrtho = cameraProjectionMatrix.element(3).element(3).equal(1); 23953 const orthoScale = div(1, cameraProjectionMatrix.element(1).element(1)).mul(3); 23954 const modifiedPosition = isOrtho.select(positionLocal.mul(orthoScale), positionLocal); 23955 const viewPosition = modelViewMatrix.mul(vec4(modifiedPosition, 0)); 23956 let viewProj = cameraProjectionMatrix.mul(vec4(viewPosition.xyz, 1)); 23957 viewProj = viewProj.setZ(viewProj.w); 23958 const nodeMaterial = new NodeMaterial(); 23959 nodeMaterial.name = "Background.material"; 23960 nodeMaterial.side = BackSide; 23961 nodeMaterial.depthTest = false; 23962 nodeMaterial.depthWrite = false; 23963 nodeMaterial.allowOverride = false; 23964 nodeMaterial.fog = false; 23965 nodeMaterial.lights = false; 23966 nodeMaterial.vertexNode = viewProj; 23967 nodeMaterial.colorNode = backgroundMeshNode; 23968 sceneData.backgroundMeshNode = backgroundMeshNode; 23969 sceneData.backgroundMesh = backgroundMesh = new Mesh(new SphereGeometry(1, 32, 32), nodeMaterial); 23970 backgroundMesh.frustumCulled = false; 23971 backgroundMesh.name = "Background.mesh"; 23972 background.addEventListener("dispose", onBackgroundDispose); 23973 } 23974 const backgroundCacheKey = backgroundNode.getCacheKey(); 23975 if (sceneData.backgroundCacheKey !== backgroundCacheKey) { 23976 sceneData.backgroundMeshNode.node = vec4(backgroundNode).mul(backgroundIntensity); 23977 sceneData.backgroundMeshNode.needsUpdate = true; 23978 backgroundMesh.material.needsUpdate = true; 23979 sceneData.backgroundCacheKey = backgroundCacheKey; 23980 } 23981 renderList.unshift(backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null); 23982 } else { 23983 error("Renderer: Unsupported background configuration.", background); 23984 } 23985 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); 23986 if (environmentBlendMode === "additive") { 23987 _clearColor.set(0, 0, 0, 1); 23988 } else if (environmentBlendMode === "alpha-blend") { 23989 _clearColor.set(0, 0, 0, 0); 23990 } 23991 if (renderer.autoClear === true || forceClear === true) { 23992 const clearColorValue = renderContext.clearColorValue; 23993 clearColorValue.r = _clearColor.r; 23994 clearColorValue.g = _clearColor.g; 23995 clearColorValue.b = _clearColor.b; 23996 clearColorValue.a = _clearColor.a; 23997 if (renderer.backend.isWebGLBackend === true || renderer.alpha === true) { 23998 clearColorValue.r *= clearColorValue.a; 23999 clearColorValue.g *= clearColorValue.a; 24000 clearColorValue.b *= clearColorValue.a; 24001 } 24002 renderContext.depthClearValue = renderer.getClearDepth(); 24003 renderContext.stencilClearValue = renderer.getClearStencil(); 24004 renderContext.clearColor = renderer.autoClearColor === true; 24005 renderContext.clearDepth = renderer.autoClearDepth === true; 24006 renderContext.clearStencil = renderer.autoClearStencil === true; 24007 } else { 24008 renderContext.clearColor = false; 24009 renderContext.clearDepth = false; 24010 renderContext.clearStencil = false; 24011 } 24012 } 24013}; 24014var _id$7 = 0; 24015var BindGroup = class { 24016 /** 24017 * Constructs a new bind group. 24018 * 24019 * @param {string} name - The bind group's name. 24020 * @param {Array<Binding>} bindings - An array of bindings. 24021 * @param {number} index - The group index. 24022 */ 24023 constructor(name = "", bindings = []) { 24024 this.name = name; 24025 this.bindings = bindings; 24026 this.id = _id$7++; 24027 } 24028}; 24029var NodeBuilderState = class { 24030 /** 24031 * Constructs a new node builder state. 24032 * 24033 * @param {string} vertexShader - The native vertex shader code. 24034 * @param {string} fragmentShader - The native fragment shader code. 24035 * @param {string} computeShader - The native compute shader code. 24036 * @param {Array<NodeAttribute>} nodeAttributes - An array of node attributes. 24037 * @param {Array<BindGroup>} bindings - An array of bind groups. 24038 * @param {Array<Node>} updateNodes - An array of nodes that implement their `update()` method. 24039 * @param {Array<Node>} updateBeforeNodes - An array of nodes that implement their `updateBefore()` method. 24040 * @param {Array<Node>} updateAfterNodes - An array of nodes that implement their `updateAfter()` method. 24041 * @param {NodeMaterialObserver} observer - A node material observer. 24042 * @param {Array<Object>} transforms - An array with transform attribute objects. Only relevant when using compute shaders with WebGL 2. 24043 */ 24044 constructor(vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, observer, transforms = []) { 24045 this.vertexShader = vertexShader; 24046 this.fragmentShader = fragmentShader; 24047 this.computeShader = computeShader; 24048 this.transforms = transforms; 24049 this.nodeAttributes = nodeAttributes; 24050 this.bindings = bindings; 24051 this.updateNodes = updateNodes; 24052 this.updateBeforeNodes = updateBeforeNodes; 24053 this.updateAfterNodes = updateAfterNodes; 24054 this.observer = observer; 24055 this.usedTimes = 0; 24056 } 24057 /** 24058 * This method is used to create a array of bind groups based 24059 * on the existing bind groups of this state. Shared groups are 24060 * not cloned. 24061 * 24062 * @return {Array<BindGroup>} A array of bind groups. 24063 */ 24064 createBindings() { 24065 const bindings = []; 24066 for (const instanceGroup of this.bindings) { 24067 const shared = instanceGroup.bindings[0].groupNode.shared; 24068 if (shared !== true) { 24069 const bindingsGroup = new BindGroup(instanceGroup.name, []); 24070 bindings.push(bindingsGroup); 24071 for (const instanceBinding of instanceGroup.bindings) { 24072 bindingsGroup.bindings.push(instanceBinding.clone()); 24073 } 24074 } else { 24075 bindings.push(instanceGroup); 24076 } 24077 } 24078 return bindings; 24079 } 24080}; 24081var NodeAttribute = class { 24082 /** 24083 * Constructs a new node attribute. 24084 * 24085 * @param {string} name - The name of the attribute. 24086 * @param {string} type - The type of the attribute. 24087 * @param {?Node} node - An optional reference to the node. 24088 */ 24089 constructor(name, type, node = null) { 24090 this.isNodeAttribute = true; 24091 this.name = name; 24092 this.type = type; 24093 this.node = node; 24094 } 24095}; 24096var NodeUniform = class { 24097 /** 24098 * Constructs a new node uniform. 24099 * 24100 * @param {string} name - The name of the uniform. 24101 * @param {string} type - The type of the uniform. 24102 * @param {UniformNode} node - An reference to the node. 24103 */ 24104 constructor(name, type, node) { 24105 this.isNodeUniform = true; 24106 this.name = name; 24107 this.type = type; 24108 this.node = node; 24109 } 24110 /** 24111 * The value of the uniform node. 24112 * 24113 * @type {any} 24114 */ 24115 get value() { 24116 return this.node.value; 24117 } 24118 set value(val) { 24119 this.node.value = val; 24120 } 24121 /** 24122 * The id of the uniform node. 24123 * 24124 * @type {number} 24125 */ 24126 get id() { 24127 return this.node.id; 24128 } 24129 /** 24130 * The uniform node's group. 24131 * 24132 * @type {UniformGroupNode} 24133 */ 24134 get groupNode() { 24135 return this.node.groupNode; 24136 } 24137}; 24138var NodeVar = class { 24139 /** 24140 * Constructs a new node variable. 24141 * 24142 * @param {string} name - The name of the variable. 24143 * @param {string} type - The type of the variable. 24144 * @param {boolean} [readOnly=false] - The read-only flag. 24145 * @param {?number} [count=null] - The size. 24146 */ 24147 constructor(name, type, readOnly = false, count = null) { 24148 this.isNodeVar = true; 24149 this.name = name; 24150 this.type = type; 24151 this.readOnly = readOnly; 24152 this.count = count; 24153 } 24154}; 24155var NodeVarying = class extends NodeVar { 24156 /** 24157 * Constructs a new node varying. 24158 * 24159 * @param {string} name - The name of the varying. 24160 * @param {string} type - The type of the varying. 24161 * @param {?string} interpolationType - The interpolation type of the varying. 24162 * @param {?string} interpolationSampling - The interpolation sampling type of the varying. 24163 */ 24164 constructor(name, type, interpolationType = null, interpolationSampling = null) { 24165 super(name, type); 24166 this.needsInterpolation = false; 24167 this.isNodeVarying = true; 24168 this.interpolationType = interpolationType; 24169 this.interpolationSampling = interpolationSampling; 24170 } 24171}; 24172var NodeCode = class { 24173 /** 24174 * Constructs a new code node. 24175 * 24176 * @param {string} name - The name of the code. 24177 * @param {string} type - The node type. 24178 * @param {string} [code=''] - The native shader code. 24179 */ 24180 constructor(name, type, code3 = "") { 24181 this.name = name; 24182 this.type = type; 24183 this.code = code3; 24184 Object.defineProperty(this, "isNodeCode", { value: true }); 24185 } 24186}; 24187var _id$6 = 0; 24188var NodeCache = class { 24189 /** 24190 * Constructs a new node cache. 24191 * 24192 * @param {?NodeCache} parent - A reference to a parent cache. 24193 */ 24194 constructor(parent = null) { 24195 this.id = _id$6++; 24196 this.nodesData = /* @__PURE__ */ new WeakMap(); 24197 this.parent = parent; 24198 } 24199 /** 24200 * Returns the data for the given node. 24201 * 24202 * @param {Node} node - The node. 24203 * @return {?Object} The data for the node. 24204 */ 24205 getData(node) { 24206 let data = this.nodesData.get(node); 24207 if (data === void 0 && this.parent !== null) { 24208 data = this.parent.getData(node); 24209 } 24210 return data; 24211 } 24212 /** 24213 * Sets the data for a given node. 24214 * 24215 * @param {Node} node - The node. 24216 * @param {Object} data - The data that should be cached. 24217 */ 24218 setData(node, data) { 24219 this.nodesData.set(node, data); 24220 } 24221}; 24222var StructType = class { 24223 constructor(name, members) { 24224 this.name = name; 24225 this.members = members; 24226 this.output = false; 24227 } 24228}; 24229var Uniform2 = class { 24230 /** 24231 * Constructs a new uniform. 24232 * 24233 * @param {string} name - The uniform's name. 24234 * @param {any} value - The uniform's value. 24235 */ 24236 constructor(name, value) { 24237 this.name = name; 24238 this.value = value; 24239 this.boundary = 0; 24240 this.itemSize = 0; 24241 this.offset = 0; 24242 this.index = -1; 24243 } 24244 /** 24245 * Sets the uniform's value. 24246 * 24247 * @param {any} value - The value to set. 24248 */ 24249 setValue(value) { 24250 this.value = value; 24251 } 24252 /** 24253 * Returns the uniform's value. 24254 * 24255 * @return {any} The value. 24256 */ 24257 getValue() { 24258 return this.value; 24259 } 24260}; 24261var NumberUniform = class extends Uniform2 { 24262 /** 24263 * Constructs a new Number uniform. 24264 * 24265 * @param {string} name - The uniform's name. 24266 * @param {number} value - The uniform's value. 24267 */ 24268 constructor(name, value = 0) { 24269 super(name, value); 24270 this.isNumberUniform = true; 24271 this.boundary = 4; 24272 this.itemSize = 1; 24273 } 24274}; 24275var Vector2Uniform = class extends Uniform2 { 24276 /** 24277 * Constructs a new Number uniform. 24278 * 24279 * @param {string} name - The uniform's name. 24280 * @param {Vector2} value - The uniform's value. 24281 */ 24282 constructor(name, value = new Vector2()) { 24283 super(name, value); 24284 this.isVector2Uniform = true; 24285 this.boundary = 8; 24286 this.itemSize = 2; 24287 } 24288}; 24289var Vector3Uniform = class extends Uniform2 { 24290 /** 24291 * Constructs a new Number uniform. 24292 * 24293 * @param {string} name - The uniform's name. 24294 * @param {Vector3} value - The uniform's value. 24295 */ 24296 constructor(name, value = new Vector3()) { 24297 super(name, value); 24298 this.isVector3Uniform = true; 24299 this.boundary = 16; 24300 this.itemSize = 3; 24301 } 24302}; 24303var Vector4Uniform = class extends Uniform2 { 24304 /** 24305 * Constructs a new Number uniform. 24306 * 24307 * @param {string} name - The uniform's name. 24308 * @param {Vector4} value - The uniform's value. 24309 */ 24310 constructor(name, value = new Vector4()) { 24311 super(name, value); 24312 this.isVector4Uniform = true; 24313 this.boundary = 16; 24314 this.itemSize = 4; 24315 } 24316}; 24317var ColorUniform = class extends Uniform2 { 24318 /** 24319 * Constructs a new Number uniform. 24320 * 24321 * @param {string} name - The uniform's name. 24322 * @param {Color} value - The uniform's value. 24323 */ 24324 constructor(name, value = new Color()) { 24325 super(name, value); 24326 this.isColorUniform = true; 24327 this.boundary = 16; 24328 this.itemSize = 3; 24329 } 24330}; 24331var Matrix2Uniform = class extends Uniform2 { 24332 /** 24333 * Constructs a new Number uniform. 24334 * 24335 * @param {string} name - The uniform's name. 24336 * @param {Matrix2} value - The uniform's value. 24337 */ 24338 constructor(name, value = new Matrix2()) { 24339 super(name, value); 24340 this.isMatrix2Uniform = true; 24341 this.boundary = 8; 24342 this.itemSize = 4; 24343 } 24344}; 24345var Matrix3Uniform = class extends Uniform2 { 24346 /** 24347 * Constructs a new Number uniform. 24348 * 24349 * @param {string} name - The uniform's name. 24350 * @param {Matrix3} value - The uniform's value. 24351 */ 24352 constructor(name, value = new Matrix3()) { 24353 super(name, value); 24354 this.isMatrix3Uniform = true; 24355 this.boundary = 48; 24356 this.itemSize = 12; 24357 } 24358}; 24359var Matrix4Uniform = class extends Uniform2 { 24360 /** 24361 * Constructs a new Number uniform. 24362 * 24363 * @param {string} name - The uniform's name. 24364 * @param {Matrix4} value - The uniform's value. 24365 */ 24366 constructor(name, value = new Matrix4()) { 24367 super(name, value); 24368 this.isMatrix4Uniform = true; 24369 this.boundary = 64; 24370 this.itemSize = 16; 24371 } 24372}; 24373var NumberNodeUniform = class extends NumberUniform { 24374 /** 24375 * Constructs a new node-based Number uniform. 24376 * 24377 * @param {NodeUniform} nodeUniform - The node uniform. 24378 */ 24379 constructor(nodeUniform) { 24380 super(nodeUniform.name, nodeUniform.value); 24381 this.nodeUniform = nodeUniform; 24382 } 24383 /** 24384 * Overwritten to return the value of the node uniform. 24385 * 24386 * @return {number} The value. 24387 */ 24388 getValue() { 24389 return this.nodeUniform.value; 24390 } 24391 /** 24392 * Returns the node uniform data type. 24393 * 24394 * @return {string} The data type. 24395 */ 24396 getType() { 24397 return this.nodeUniform.type; 24398 } 24399}; 24400var Vector2NodeUniform = class extends Vector2Uniform { 24401 /** 24402 * Constructs a new node-based Vector2 uniform. 24403 * 24404 * @param {NodeUniform} nodeUniform - The node uniform. 24405 */ 24406 constructor(nodeUniform) { 24407 super(nodeUniform.name, nodeUniform.value); 24408 this.nodeUniform = nodeUniform; 24409 } 24410 /** 24411 * Overwritten to return the value of the node uniform. 24412 * 24413 * @return {Vector2} The value. 24414 */ 24415 getValue() { 24416 return this.nodeUniform.value; 24417 } 24418 /** 24419 * Returns the node uniform data type. 24420 * 24421 * @return {string} The data type. 24422 */ 24423 getType() { 24424 return this.nodeUniform.type; 24425 } 24426}; 24427var Vector3NodeUniform = class extends Vector3Uniform { 24428 /** 24429 * Constructs a new node-based Vector3 uniform. 24430 * 24431 * @param {NodeUniform} nodeUniform - The node uniform. 24432 */ 24433 constructor(nodeUniform) { 24434 super(nodeUniform.name, nodeUniform.value); 24435 this.nodeUniform = nodeUniform; 24436 } 24437 /** 24438 * Overwritten to return the value of the node uniform. 24439 * 24440 * @return {Vector3} The value. 24441 */ 24442 getValue() { 24443 return this.nodeUniform.value; 24444 } 24445 /** 24446 * Returns the node uniform data type. 24447 * 24448 * @return {string} The data type. 24449 */ 24450 getType() { 24451 return this.nodeUniform.type; 24452 } 24453}; 24454var Vector4NodeUniform = class extends Vector4Uniform { 24455 /** 24456 * Constructs a new node-based Vector4 uniform. 24457 * 24458 * @param {NodeUniform} nodeUniform - The node uniform. 24459 */ 24460 constructor(nodeUniform) { 24461 super(nodeUniform.name, nodeUniform.value); 24462 this.nodeUniform = nodeUniform; 24463 } 24464 /** 24465 * Overwritten to return the value of the node uniform. 24466 * 24467 * @return {Vector4} The value. 24468 */ 24469 getValue() { 24470 return this.nodeUniform.value; 24471 } 24472 /** 24473 * Returns the node uniform data type. 24474 * 24475 * @return {string} The data type. 24476 */ 24477 getType() { 24478 return this.nodeUniform.type; 24479 } 24480}; 24481var ColorNodeUniform = class extends ColorUniform { 24482 /** 24483 * Constructs a new node-based Color uniform. 24484 * 24485 * @param {NodeUniform} nodeUniform - The node uniform. 24486 */ 24487 constructor(nodeUniform) { 24488 super(nodeUniform.name, nodeUniform.value); 24489 this.nodeUniform = nodeUniform; 24490 } 24491 /** 24492 * Overwritten to return the value of the node uniform. 24493 * 24494 * @return {Color} The value. 24495 */ 24496 getValue() { 24497 return this.nodeUniform.value; 24498 } 24499 /** 24500 * Returns the node uniform data type. 24501 * 24502 * @return {string} The data type. 24503 */ 24504 getType() { 24505 return this.nodeUniform.type; 24506 } 24507}; 24508var Matrix2NodeUniform = class extends Matrix2Uniform { 24509 /** 24510 * Constructs a new node-based Matrix2 uniform. 24511 * 24512 * @param {NodeUniform} nodeUniform - The node uniform. 24513 */ 24514 constructor(nodeUniform) { 24515 super(nodeUniform.name, nodeUniform.value); 24516 this.nodeUniform = nodeUniform; 24517 } 24518 /** 24519 * Overwritten to return the value of the node uniform. 24520 * 24521 * @return {Matrix2} The value. 24522 */ 24523 getValue() { 24524 return this.nodeUniform.value; 24525 } 24526 /** 24527 * Returns the node uniform data type. 24528 * 24529 * @return {string} The data type. 24530 */ 24531 getType() { 24532 return this.nodeUniform.type; 24533 } 24534}; 24535var Matrix3NodeUniform = class extends Matrix3Uniform { 24536 /** 24537 * Constructs a new node-based Matrix3 uniform. 24538 * 24539 * @param {NodeUniform} nodeUniform - The node uniform. 24540 */ 24541 constructor(nodeUniform) { 24542 super(nodeUniform.name, nodeUniform.value); 24543 this.nodeUniform = nodeUniform; 24544 } 24545 /** 24546 * Overwritten to return the value of the node uniform. 24547 * 24548 * @return {Matrix3} The value. 24549 */ 24550 getValue() { 24551 return this.nodeUniform.value; 24552 } 24553 /** 24554 * Returns the node uniform data type. 24555 * 24556 * @return {string} The data type. 24557 */ 24558 getType() { 24559 return this.nodeUniform.type; 24560 } 24561}; 24562var Matrix4NodeUniform = class extends Matrix4Uniform { 24563 /** 24564 * Constructs a new node-based Matrix4 uniform. 24565 * 24566 * @param {NodeUniform} nodeUniform - The node uniform. 24567 */ 24568 constructor(nodeUniform) { 24569 super(nodeUniform.name, nodeUniform.value); 24570 this.nodeUniform = nodeUniform; 24571 } 24572 /** 24573 * Overwritten to return the value of the node uniform. 24574 * 24575 * @return {Matrix4} The value. 24576 */ 24577 getValue() { 24578 return this.nodeUniform.value; 24579 } 24580 /** 24581 * Returns the node uniform data type. 24582 * 24583 * @return {string} The data type. 24584 */ 24585 getType() { 24586 return this.nodeUniform.type; 24587 } 24588}; 24589var _id$5 = 0; 24590var _bindingGroupsCache = /* @__PURE__ */ new WeakMap(); 24591var sharedNodeData = /* @__PURE__ */ new WeakMap(); 24592var typeFromArray = /* @__PURE__ */ new Map([ 24593 [Int8Array, "int"], 24594 [Int16Array, "int"], 24595 [Int32Array, "int"], 24596 [Uint8Array, "uint"], 24597 [Uint16Array, "uint"], 24598 [Uint32Array, "uint"], 24599 [Float32Array, "float"] 24600]); 24601var toFloat = (value) => { 24602 if (/e/g.test(value)) { 24603 return String(value).replace(/\+/g, ""); 24604 } else { 24605 value = Number(value); 24606 return value + (value % 1 ? "" : ".0"); 24607 } 24608}; 24609var NodeBuilder = class { 24610 /** 24611 * Constructs a new node builder. 24612 * 24613 * @param {Object3D} object - The 3D object. 24614 * @param {Renderer} renderer - The current renderer. 24615 * @param {NodeParser} parser - A reference to a node parser. 24616 */ 24617 constructor(object, renderer, parser) { 24618 this.object = object; 24619 this.material = object && object.material || null; 24620 this.geometry = object && object.geometry || null; 24621 this.renderer = renderer; 24622 this.parser = parser; 24623 this.scene = null; 24624 this.camera = null; 24625 this.nodes = []; 24626 this.sequentialNodes = []; 24627 this.updateNodes = []; 24628 this.updateBeforeNodes = []; 24629 this.updateAfterNodes = []; 24630 this.hashNodes = {}; 24631 this.observer = null; 24632 this.lightsNode = null; 24633 this.environmentNode = null; 24634 this.fogNode = null; 24635 this.clippingContext = null; 24636 this.vertexShader = null; 24637 this.fragmentShader = null; 24638 this.computeShader = null; 24639 this.flowNodes = { vertex: [], fragment: [], compute: [] }; 24640 this.flowCode = { vertex: "", fragment: "", compute: "" }; 24641 this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; 24642 this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; 24643 this.types = { vertex: [], fragment: [], compute: [], index: 0 }; 24644 this.bindings = { vertex: {}, fragment: {}, compute: {} }; 24645 this.bindingsIndexes = {}; 24646 this.bindGroups = null; 24647 this.attributes = []; 24648 this.bufferAttributes = []; 24649 this.varyings = []; 24650 this.codes = {}; 24651 this.vars = {}; 24652 this.declarations = {}; 24653 this.flow = { code: "" }; 24654 this.chaining = []; 24655 this.stack = stack(); 24656 this.stacks = []; 24657 this.tab = " "; 24658 this.currentFunctionNode = null; 24659 this.context = { 24660 material: this.material 24661 }; 24662 this.cache = new NodeCache(); 24663 this.globalCache = this.cache; 24664 this.flowsData = /* @__PURE__ */ new WeakMap(); 24665 this.shaderStage = null; 24666 this.buildStage = null; 24667 this.subBuildLayers = []; 24668 this.activeStacks = []; 24669 this.subBuildFn = null; 24670 this.fnCall = null; 24671 Object.defineProperty(this, "id", { value: _id$5++ }); 24672 } 24673 /** 24674 * Whether the material is using flat shading or not. 24675 * 24676 * @returns {boolean} Whether the material is using flat shading or not. 24677 */ 24678 isFlatShading() { 24679 return this.material.flatShading === true || this.geometry.hasAttribute("normal") === false; 24680 } 24681 /** 24682 * Whether the material is opaque or not. 24683 * 24684 * @return {boolean} Whether the material is opaque or not. 24685 */ 24686 isOpaque() { 24687 const material = this.material; 24688 return material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false; 24689 } 24690 /** 24691 * Factory method for creating an instance of {@link RenderTarget} with the given 24692 * dimensions and options. 24693 * 24694 * @param {number} width - The width of the render target. 24695 * @param {number} height - The height of the render target. 24696 * @param {Object} options - The options of the render target. 24697 * @return {RenderTarget} The render target. 24698 */ 24699 createRenderTarget(width, height, options) { 24700 return new RenderTarget(width, height, options); 24701 } 24702 /** 24703 * Factory method for creating an instance of {@link CubeRenderTarget} with the given 24704 * dimensions and options. 24705 * 24706 * @param {number} size - The size of the cube render target. 24707 * @param {Object} options - The options of the cube render target. 24708 * @return {CubeRenderTarget} The cube render target. 24709 */ 24710 createCubeRenderTarget(size3, options) { 24711 return new CubeRenderTarget(size3, options); 24712 } 24713 /** 24714 * Whether the given node is included in the internal array of nodes or not. 24715 * 24716 * @param {Node} node - The node to test. 24717 * @return {boolean} Whether the given node is included in the internal array of nodes or not. 24718 */ 24719 includes(node) { 24720 return this.nodes.includes(node); 24721 } 24722 /** 24723 * Returns the output struct name which is required by 24724 * {@link OutputStructNode}. 24725 * 24726 * @abstract 24727 * @return {string} The name of the output struct. 24728 */ 24729 getOutputStructName() { 24730 } 24731 /** 24732 * Returns a bind group for the given group name and binding. 24733 * 24734 * @private 24735 * @param {string} groupName - The group name. 24736 * @param {Array<NodeUniformsGroup>} bindings - List of bindings. 24737 * @return {BindGroup} The bind group 24738 */ 24739 _getBindGroup(groupName, bindings) { 24740 const groupNode = bindings[0].groupNode; 24741 let sharedGroup = groupNode.shared; 24742 if (sharedGroup) { 24743 for (let i = 1; i < bindings.length; i++) { 24744 if (groupNode !== bindings[i].groupNode) { 24745 sharedGroup = false; 24746 } 24747 } 24748 } 24749 let bindGroup; 24750 if (sharedGroup) { 24751 let cacheKeyString = ""; 24752 for (const binding of bindings) { 24753 if (binding.isNodeUniformsGroup) { 24754 binding.uniforms.sort((a, b) => a.nodeUniform.node.id - b.nodeUniform.node.id); 24755 for (const uniform3 of binding.uniforms) { 24756 cacheKeyString += uniform3.nodeUniform.node.id; 24757 } 24758 } else { 24759 cacheKeyString += binding.nodeUniform.id; 24760 } 24761 } 24762 const currentContext = this.renderer._currentRenderContext || this.renderer; 24763 let bindingGroupsCache = _bindingGroupsCache.get(currentContext); 24764 if (bindingGroupsCache === void 0) { 24765 bindingGroupsCache = /* @__PURE__ */ new Map(); 24766 _bindingGroupsCache.set(currentContext, bindingGroupsCache); 24767 } 24768 const cacheKey = hashString(cacheKeyString); 24769 bindGroup = bindingGroupsCache.get(cacheKey); 24770 if (bindGroup === void 0) { 24771 bindGroup = new BindGroup(groupName, bindings); 24772 bindingGroupsCache.set(cacheKey, bindGroup); 24773 } 24774 } else { 24775 bindGroup = new BindGroup(groupName, bindings); 24776 } 24777 return bindGroup; 24778 } 24779 /** 24780 * Returns an array of node uniform groups for the given group name and shader stage. 24781 * 24782 * @param {string} groupName - The group name. 24783 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 24784 * @return {Array<NodeUniformsGroup>} The array of node uniform groups. 24785 */ 24786 getBindGroupArray(groupName, shaderStage) { 24787 const bindings = this.bindings[shaderStage]; 24788 let bindGroup = bindings[groupName]; 24789 if (bindGroup === void 0) { 24790 if (this.bindingsIndexes[groupName] === void 0) { 24791 this.bindingsIndexes[groupName] = { binding: 0, group: Object.keys(this.bindingsIndexes).length }; 24792 } 24793 bindings[groupName] = bindGroup = []; 24794 } 24795 return bindGroup; 24796 } 24797 /** 24798 * Returns a list bindings of all shader stages separated by groups. 24799 * 24800 * @return {Array<BindGroup>} The list of bindings. 24801 */ 24802 getBindings() { 24803 let bindingsGroups = this.bindGroups; 24804 if (bindingsGroups === null) { 24805 const groups = {}; 24806 const bindings = this.bindings; 24807 for (const shaderStage of shaderStages) { 24808 for (const groupName in bindings[shaderStage]) { 24809 const uniforms = bindings[shaderStage][groupName]; 24810 const groupUniforms = groups[groupName] || (groups[groupName] = []); 24811 for (const uniform3 of uniforms) { 24812 if (groupUniforms.includes(uniform3) === false) { 24813 groupUniforms.push(uniform3); 24814 } 24815 } 24816 } 24817 } 24818 bindingsGroups = []; 24819 for (const groupName in groups) { 24820 const group = groups[groupName]; 24821 const bindingsGroup = this._getBindGroup(groupName, group); 24822 bindingsGroups.push(bindingsGroup); 24823 } 24824 this.bindGroups = bindingsGroups; 24825 } 24826 return bindingsGroups; 24827 } 24828 /** 24829 * Sorts the bind groups and updates {@link NodeBuilder#bindingsIndexes}. 24830 */ 24831 sortBindingGroups() { 24832 const bindingsGroups = this.getBindings(); 24833 bindingsGroups.sort((a, b) => a.bindings[0].groupNode.order - b.bindings[0].groupNode.order); 24834 for (let i = 0; i < bindingsGroups.length; i++) { 24835 const bindingGroup = bindingsGroups[i]; 24836 this.bindingsIndexes[bindingGroup.name].group = i; 24837 } 24838 } 24839 /** 24840 * The builder maintains each node in a hash-based dictionary. 24841 * This method sets the given node (value) with the given hash (key) into this dictionary. 24842 * 24843 * @param {Node} node - The node to add. 24844 * @param {number} hash - The hash of the node. 24845 */ 24846 setHashNode(node, hash3) { 24847 this.hashNodes[hash3] = node; 24848 } 24849 /** 24850 * Adds a node to this builder. 24851 * 24852 * @param {Node} node - The node to add. 24853 */ 24854 addNode(node) { 24855 if (this.nodes.includes(node) === false) { 24856 this.nodes.push(node); 24857 this.setHashNode(node, node.getHash(this)); 24858 } 24859 } 24860 /** 24861 * It is used to add Nodes that will be used as FRAME and RENDER events, 24862 * and need to follow a certain sequence in the calls to work correctly. 24863 * This function should be called after 'setup()' in the 'build()' process to ensure that the child nodes are processed first. 24864 * 24865 * @param {Node} node - The node to add. 24866 */ 24867 addSequentialNode(node) { 24868 const updateBeforeType = node.getUpdateBeforeType(); 24869 const updateAfterType = node.getUpdateAfterType(); 24870 if (updateBeforeType !== NodeUpdateType.NONE || updateAfterType !== NodeUpdateType.NONE) { 24871 if (this.sequentialNodes.includes(node) === false) { 24872 this.sequentialNodes.push(node); 24873 } 24874 } 24875 } 24876 /** 24877 * Checks the update types of nodes 24878 */ 24879 buildUpdateNodes() { 24880 for (const node of this.nodes) { 24881 const updateType = node.getUpdateType(); 24882 if (updateType !== NodeUpdateType.NONE) { 24883 this.updateNodes.push(node); 24884 } 24885 } 24886 for (const node of this.sequentialNodes) { 24887 const updateBeforeType = node.getUpdateBeforeType(); 24888 const updateAfterType = node.getUpdateAfterType(); 24889 if (updateBeforeType !== NodeUpdateType.NONE) { 24890 this.updateBeforeNodes.push(node); 24891 } 24892 if (updateAfterType !== NodeUpdateType.NONE) { 24893 this.updateAfterNodes.push(node); 24894 } 24895 } 24896 } 24897 /** 24898 * A reference the current node which is the 24899 * last node in the chain of nodes. 24900 * 24901 * @type {Node} 24902 */ 24903 get currentNode() { 24904 return this.chaining[this.chaining.length - 1]; 24905 } 24906 /** 24907 * Whether the given texture is filtered or not. 24908 * 24909 * @param {Texture} texture - The texture to check. 24910 * @return {boolean} Whether the given texture is filtered or not. 24911 */ 24912 isFilteredTexture(texture3) { 24913 return texture3.magFilter === LinearFilter || texture3.magFilter === LinearMipmapNearestFilter || texture3.magFilter === NearestMipmapLinearFilter || texture3.magFilter === LinearMipmapLinearFilter || texture3.minFilter === LinearFilter || texture3.minFilter === LinearMipmapNearestFilter || texture3.minFilter === NearestMipmapLinearFilter || texture3.minFilter === LinearMipmapLinearFilter; 24914 } 24915 /** 24916 * Returns the maximum number of bytes available for uniform buffers. 24917 * 24918 * @return {number} The maximum number of bytes available for uniform buffers. 24919 */ 24920 getUniformBufferLimit() { 24921 return this.renderer.backend.capabilities.getUniformBufferLimit(); 24922 } 24923 /** 24924 * Adds the given node to the internal node chain. 24925 * This is used to check recursive calls in node-graph. 24926 * 24927 * @param {Node} node - The node to add. 24928 */ 24929 addChain(node) { 24930 this.chaining.push(node); 24931 } 24932 /** 24933 * Removes the given node from the internal node chain. 24934 * 24935 * @param {Node} node - The node to remove. 24936 */ 24937 removeChain(node) { 24938 const lastChain = this.chaining.pop(); 24939 if (lastChain !== node) { 24940 throw new Error("NodeBuilder: Invalid node chaining!"); 24941 } 24942 } 24943 /** 24944 * Returns the native shader method name for a given generic name. E.g. 24945 * the method name `textureDimensions` matches the WGSL name but must be 24946 * resolved to `textureSize` in GLSL. 24947 * 24948 * @abstract 24949 * @param {string} method - The method name to resolve. 24950 * @return {string} The resolved method name. 24951 */ 24952 getMethod(method) { 24953 return method; 24954 } 24955 /** 24956 * Returns the native snippet for a ternary operation. E.g. GLSL would output 24957 * a ternary op as `cond ? x : y` whereas WGSL would output it as `select(y, x, cond)` 24958 * 24959 * @abstract 24960 * @param {string} condSnippet - The condition determining which expression gets resolved. 24961 * @param {string} ifSnippet - The expression to resolve to if the condition is true. 24962 * @param {string} elseSnippet - The expression to resolve to if the condition is false. 24963 * @return {string} The resolved method name. 24964 */ 24965 getTernary() { 24966 return null; 24967 } 24968 /** 24969 * Returns a node for the given hash, see {@link NodeBuilder#setHashNode}. 24970 * 24971 * @param {number} hash - The hash of the node. 24972 * @return {Node} The found node. 24973 */ 24974 getNodeFromHash(hash3) { 24975 return this.hashNodes[hash3]; 24976 } 24977 /** 24978 * Adds the Node to a target flow so that it can generate code in the 'generate' process. 24979 * 24980 * @param {('vertex'|'fragment'|'compute')} shaderStage - The shader stage. 24981 * @param {Node} node - The node to add. 24982 * @return {Node} The node. 24983 */ 24984 addFlow(shaderStage, node) { 24985 this.flowNodes[shaderStage].push(node); 24986 return node; 24987 } 24988 /** 24989 * Sets builder's context. 24990 * 24991 * @param {Object} context - The context to set. 24992 */ 24993 setContext(context3) { 24994 this.context = context3; 24995 } 24996 /** 24997 * Returns the builder's current context. 24998 * 24999 * @return {Object} The builder's current context. 25000 */ 25001 getContext() { 25002 return this.context; 25003 } 25004 /** 25005 * Adds context data to the builder's current context. 25006 * 25007 * @param {Object} context - The context to add. 25008 * @return {Object} The previous context. 25009 */ 25010 addContext(context3) { 25011 const previousContext = this.getContext(); 25012 this.setContext({ ...this.context, ...context3 }); 25013 return previousContext; 25014 } 25015 /** 25016 * Gets a context used in shader construction that can be shared across different materials. 25017 * This is necessary since the renderer cache can reuse shaders generated in one material and use them in another. 25018 * 25019 * @return {Object} The builder's current context without material. 25020 */ 25021 getSharedContext() { 25022 const context3 = { ...this.context }; 25023 delete context3.material; 25024 delete context3.getUV; 25025 delete context3.getOutput; 25026 delete context3.getTextureLevel; 25027 delete context3.getAO; 25028 delete context3.getShadow; 25029 return context3; 25030 } 25031 /** 25032 * Sets builder's cache. 25033 * 25034 * @param {NodeCache} cache - The cache to set. 25035 */ 25036 setCache(cache4) { 25037 this.cache = cache4; 25038 } 25039 /** 25040 * Returns the builder's current cache. 25041 * 25042 * @return {NodeCache} The builder's current cache. 25043 */ 25044 getCache() { 25045 return this.cache; 25046 } 25047 /** 25048 * Returns a cache for the given node. 25049 * 25050 * @param {Node} node - The node. 25051 * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not. 25052 * @return {NodeCache} The cache. 25053 */ 25054 getCacheFromNode(node, parent = true) { 25055 const data = this.getDataFromNode(node); 25056 if (data.cache === void 0) data.cache = new NodeCache(parent ? this.getCache() : null); 25057 return data.cache; 25058 } 25059 /** 25060 * Whether the requested feature is available or not. 25061 * 25062 * @abstract 25063 * @param {string} name - The requested feature. 25064 * @return {boolean} Whether the requested feature is supported or not. 25065 */ 25066 isAvailable() { 25067 return false; 25068 } 25069 /** 25070 * Returns the vertexIndex input variable as a native shader string. 25071 * 25072 * @abstract 25073 * @return {string} The instanceIndex shader string. 25074 */ 25075 getVertexIndex() { 25076 warn("Abstract function."); 25077 } 25078 /** 25079 * Contextually returns either the vertex stage instance index builtin 25080 * or the linearized index of an compute invocation within a grid of workgroups. 25081 * 25082 * @abstract 25083 * @return {string} The instanceIndex shader string. 25084 */ 25085 getInstanceIndex() { 25086 warn("Abstract function."); 25087 } 25088 /** 25089 * Returns the drawIndex input variable as a native shader string. 25090 * Only relevant for WebGL and its `WEBGL_multi_draw` extension. 25091 * 25092 * @abstract 25093 * @return {?string} The drawIndex shader string. 25094 */ 25095 getDrawIndex() { 25096 warn("Abstract function."); 25097 } 25098 /** 25099 * Returns the frontFacing input variable as a native shader string. 25100 * 25101 * @abstract 25102 * @return {string} The frontFacing shader string. 25103 */ 25104 getFrontFacing() { 25105 warn("Abstract function."); 25106 } 25107 /** 25108 * Returns the fragCoord input variable as a native shader string. 25109 * 25110 * @abstract 25111 * @return {string} The fragCoord shader string. 25112 */ 25113 getFragCoord() { 25114 warn("Abstract function."); 25115 } 25116 /** 25117 * Whether to flip texture data along its vertical axis or not. WebGL needs 25118 * this method evaluate to `true`, WebGPU to `false`. 25119 * 25120 * @abstract 25121 * @return {boolean} Whether to flip texture data along its vertical axis or not. 25122 */ 25123 isFlipY() { 25124 return false; 25125 } 25126 /** 25127 * Calling this method increases the usage count for the given node by one. 25128 * 25129 * @param {Node} node - The node to increase the usage count for. 25130 * @return {number} The updated usage count. 25131 */ 25132 increaseUsage(node) { 25133 const nodeData = this.getDataFromNode(node); 25134 nodeData.usageCount = nodeData.usageCount === void 0 ? 1 : nodeData.usageCount + 1; 25135 return nodeData.usageCount; 25136 } 25137 /** 25138 * Generates a texture sample shader string for the given texture data. 25139 * 25140 * @abstract 25141 * @param {Texture} texture - The texture. 25142 * @param {string} textureProperty - The texture property name. 25143 * @param {string} uvSnippet - Snippet defining the texture coordinates. 25144 * @return {string} The generated shader string. 25145 */ 25146 generateTexture() { 25147 warn("Abstract function."); 25148 } 25149 /** 25150 * Generates a texture LOD shader string for the given texture data. 25151 * 25152 * @abstract 25153 * @param {Texture} texture - The texture. 25154 * @param {string} textureProperty - The texture property name. 25155 * @param {string} uvSnippet - Snippet defining the texture coordinates. 25156 * @param {?string} depthSnippet - Snippet defining the 0-based texture array index to sample. 25157 * @param {string} levelSnippet - Snippet defining the mip level. 25158 * @return {string} The generated shader string. 25159 */ 25160 generateTextureLod() { 25161 warn("Abstract function."); 25162 } 25163 /** 25164 * Generates the array declaration string. 25165 * 25166 * @param {string} type - The type. 25167 * @param {?number} [count] - The count. 25168 * @return {string} The generated value as a shader string. 25169 */ 25170 generateArrayDeclaration(type, count) { 25171 return this.getType(type) + "[ " + count + " ]"; 25172 } 25173 /** 25174 * Generates the array shader string for the given type and value. 25175 * 25176 * @param {string} type - The type. 25177 * @param {?number} [count] - The count. 25178 * @param {?Array<Node>} [values=null] - The default values. 25179 * @return {string} The generated value as a shader string. 25180 */ 25181 generateArray(type, count, values = null) { 25182 let snippet = this.generateArrayDeclaration(type, count) + "( "; 25183 for (let i = 0; i < count; i++) { 25184 const value = values ? values[i] : null; 25185 if (value !== null) { 25186 snippet += value.build(this, type); 25187 } else { 25188 snippet += this.generateConst(type); 25189 } 25190 if (i < count - 1) snippet += ", "; 25191 } 25192 snippet += " )"; 25193 return snippet; 25194 } 25195 /** 25196 * Generates the struct shader string. 25197 * 25198 * @param {string} type - The type. 25199 * @param {Array<Object>} [membersLayout] - The count. 25200 * @param {?Array<Node>} [values=null] - The default values. 25201 * @return {string} The generated value as a shader string. 25202 */ 25203 generateStruct(type, membersLayout, values = null) { 25204 const snippets = []; 25205 for (const member of membersLayout) { 25206 const { name, type: type2 } = member; 25207 if (values && values[name] && values[name].isNode) { 25208 snippets.push(values[name].build(this, type2)); 25209 } else { 25210 snippets.push(this.generateConst(type2)); 25211 } 25212 } 25213 return type + "( " + snippets.join(", ") + " )"; 25214 } 25215 /** 25216 * Generates the shader string for the given type and value. 25217 * 25218 * @param {string} type - The type. 25219 * @param {?any} [value=null] - The value. 25220 * @return {string} The generated value as a shader string. 25221 */ 25222 generateConst(type, value = null) { 25223 if (value === null) { 25224 if (type === "float" || type === "int" || type === "uint") value = 0; 25225 else if (type === "bool") value = false; 25226 else if (type === "color") value = new Color(); 25227 else if (type === "vec2" || type === "uvec2" || type === "ivec2") value = new Vector2(); 25228 else if (type === "vec3" || type === "uvec3" || type === "ivec3") value = new Vector3(); 25229 else if (type === "vec4" || type === "uvec4" || type === "ivec4") value = new Vector4(); 25230 } 25231 if (type === "float") return toFloat(value); 25232 if (type === "int") return `${Math.round(value)}`; 25233 if (type === "uint") return value >= 0 ? `${Math.round(value)}u` : "0u"; 25234 if (type === "bool") return value ? "true" : "false"; 25235 if (type === "color") return `${this.getType("vec3")}( ${toFloat(value.r)}, ${toFloat(value.g)}, ${toFloat(value.b)} )`; 25236 const typeLength = this.getTypeLength(type); 25237 const componentType = this.getComponentType(type); 25238 const generateConst = (value2) => this.generateConst(componentType, value2); 25239 if (typeLength === 2) { 25240 return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)} )`; 25241 } else if (typeLength === 3) { 25242 return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)}, ${generateConst(value.z)} )`; 25243 } else if (typeLength === 4 && type !== "mat2") { 25244 return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)}, ${generateConst(value.z)}, ${generateConst(value.w)} )`; 25245 } else if (typeLength >= 4 && value && (value.isMatrix2 || value.isMatrix3 || value.isMatrix4)) { 25246 return `${this.getType(type)}( ${value.elements.map(generateConst).join(", ")} )`; 25247 } else if (typeLength > 4) { 25248 return `${this.getType(type)}()`; 25249 } 25250 throw new Error(`NodeBuilder: Type '${type}' not found in generate constant attempt.`); 25251 } 25252 /** 25253 * It might be necessary to convert certain data types to different ones 25254 * so this method can be used to hide the conversion. 25255 * 25256 * @param {string} type - The type. 25257 * @return {string} The updated type. 25258 */ 25259 getType(type) { 25260 if (type === "color") return "vec3"; 25261 return type; 25262 } 25263 /** 25264 * Whether the given attribute name is defined in the geometry or not. 25265 * 25266 * @param {string} name - The attribute name. 25267 * @return {boolean} Whether the given attribute name is defined in the geometry. 25268 */ 25269 hasGeometryAttribute(name) { 25270 return this.geometry && this.geometry.getAttribute(name) !== void 0; 25271 } 25272 /** 25273 * Returns a node attribute for the given name and type. 25274 * 25275 * @param {string} name - The attribute's name. 25276 * @param {string} type - The attribute's type. 25277 * @return {NodeAttribute} The node attribute. 25278 */ 25279 getAttribute(name, type) { 25280 const attributes = this.attributes; 25281 for (const attribute4 of attributes) { 25282 if (attribute4.name === name) { 25283 return attribute4; 25284 } 25285 } 25286 const attribute3 = new NodeAttribute(name, type); 25287 this.registerDeclaration(attribute3); 25288 attributes.push(attribute3); 25289 return attribute3; 25290 } 25291 /** 25292 * Returns for the given node and shader stage the property name for the shader. 25293 * 25294 * @param {Node} node - The node. 25295 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 25296 * @return {string} The property name. 25297 */ 25298 getPropertyName(node) { 25299 return node.name; 25300 } 25301 /** 25302 * Whether the given type is a vector type or not. 25303 * 25304 * @param {string} type - The type to check. 25305 * @return {boolean} Whether the given type is a vector type or not. 25306 */ 25307 isVector(type) { 25308 return /vec\d/.test(type); 25309 } 25310 /** 25311 * Whether the given type is a matrix type or not. 25312 * 25313 * @param {string} type - The type to check. 25314 * @return {boolean} Whether the given type is a matrix type or not. 25315 */ 25316 isMatrix(type) { 25317 return /mat\d/.test(type); 25318 } 25319 /** 25320 * Whether the given type is a reference type or not. 25321 * 25322 * @param {string} type - The type to check. 25323 * @return {boolean} Whether the given type is a reference type or not. 25324 */ 25325 isReference(type) { 25326 return type === "void" || type === "property" || type === "sampler" || type === "samplerComparison" || type === "texture" || type === "cubeTexture" || type === "storageTexture" || type === "depthTexture" || type === "texture3D"; 25327 } 25328 /** 25329 * Checks if the given texture requires a manual conversion to the working color space. 25330 * 25331 * @abstract 25332 * @param {Texture} texture - The texture to check. 25333 * @return {boolean} Whether the given texture requires a conversion to working color space or not. 25334 */ 25335 needsToWorkingColorSpace() { 25336 return false; 25337 } 25338 /** 25339 * Returns the component type of a given texture. 25340 * 25341 * @param {Texture} texture - The texture. 25342 * @return {string} The component type. 25343 */ 25344 getComponentTypeFromTexture(texture3) { 25345 const type = texture3.type; 25346 if (texture3.isDataTexture) { 25347 if (type === IntType) return "int"; 25348 if (type === UnsignedIntType) return "uint"; 25349 } 25350 return "float"; 25351 } 25352 /** 25353 * Returns the element type for a given type. 25354 * 25355 * @param {string} type - The type. 25356 * @return {string} The element type. 25357 */ 25358 getElementType(type) { 25359 if (type === "mat2") return "vec2"; 25360 if (type === "mat3") return "vec3"; 25361 if (type === "mat4") return "vec4"; 25362 return this.getComponentType(type); 25363 } 25364 /** 25365 * Returns the component type for a given type. 25366 * 25367 * @param {string} type - The type. 25368 * @return {string} The component type. 25369 */ 25370 getComponentType(type) { 25371 type = this.getVectorType(type); 25372 if (type === "float" || type === "bool" || type === "int" || type === "uint") return type; 25373 const componentType = /(b|i|u|)(vec|mat)([2-4])/.exec(type); 25374 if (componentType === null) return null; 25375 if (componentType[1] === "b") return "bool"; 25376 if (componentType[1] === "i") return "int"; 25377 if (componentType[1] === "u") return "uint"; 25378 return "float"; 25379 } 25380 /** 25381 * Returns the vector type for a given type. 25382 * 25383 * @param {string} type - The type. 25384 * @return {string} The vector type. 25385 */ 25386 getVectorType(type) { 25387 if (type === "color") return "vec3"; 25388 if (type === "texture" || type === "cubeTexture" || type === "storageTexture" || type === "texture3D") return "vec4"; 25389 return type; 25390 } 25391 /** 25392 * Returns the data type for the given the length and component type. 25393 * 25394 * @param {number} length - The length. 25395 * @param {string} [componentType='float'] - The component type. 25396 * @return {string} The type. 25397 */ 25398 getTypeFromLength(length3, componentType = "float") { 25399 if (length3 === 1) return componentType; 25400 let baseType = getTypeFromLength(length3); 25401 const prefix = componentType === "float" ? "" : componentType[0]; 25402 if (/mat2/.test(componentType) === true) { 25403 baseType = baseType.replace("vec", "mat"); 25404 } 25405 return prefix + baseType; 25406 } 25407 /** 25408 * Returns the type for a given typed array. 25409 * 25410 * @param {TypedArray} array - The typed array. 25411 * @return {string} The type. 25412 */ 25413 getTypeFromArray(array3) { 25414 return typeFromArray.get(array3.constructor); 25415 } 25416 /** 25417 * Returns the type is an integer type. 25418 * 25419 * @param {string} type - The type. 25420 * @return {boolean} Whether the type is an integer type or not. 25421 */ 25422 isInteger(type) { 25423 return /int|uint|(i|u)vec/.test(type); 25424 } 25425 /** 25426 * Returns the type for a given buffer attribute. 25427 * 25428 * @param {BufferAttribute} attribute - The buffer attribute. 25429 * @return {string} The type. 25430 */ 25431 getTypeFromAttribute(attribute3) { 25432 let dataAttribute = attribute3; 25433 if (attribute3.isInterleavedBufferAttribute) dataAttribute = attribute3.data; 25434 const array3 = dataAttribute.array; 25435 const itemSize = attribute3.itemSize; 25436 const normalized = attribute3.normalized; 25437 let arrayType; 25438 if (!(attribute3 instanceof Float16BufferAttribute) && normalized !== true) { 25439 arrayType = this.getTypeFromArray(array3); 25440 } 25441 return this.getTypeFromLength(itemSize, arrayType); 25442 } 25443 /** 25444 * Returns the length for the given data type. 25445 * 25446 * @param {string} type - The data type. 25447 * @return {number} The length. 25448 */ 25449 getTypeLength(type) { 25450 const vecType = this.getVectorType(type); 25451 const vecNum = /vec([2-4])/.exec(vecType); 25452 if (vecNum !== null) return Number(vecNum[1]); 25453 if (vecType === "float" || vecType === "bool" || vecType === "int" || vecType === "uint") return 1; 25454 if (/mat2/.test(type) === true) return 4; 25455 if (/mat3/.test(type) === true) return 9; 25456 if (/mat4/.test(type) === true) return 16; 25457 return 0; 25458 } 25459 /** 25460 * Returns the vector type for a given matrix type. 25461 * 25462 * @param {string} type - The matrix type. 25463 * @return {string} The vector type. 25464 */ 25465 getVectorFromMatrix(type) { 25466 return type.replace("mat", "vec"); 25467 } 25468 /** 25469 * For a given type this method changes the component type to the 25470 * given value. E.g. `vec4` should be changed to the new component type 25471 * `uint` which results in `uvec4`. 25472 * 25473 * @param {string} type - The type. 25474 * @param {string} newComponentType - The new component type. 25475 * @return {string} The new type. 25476 */ 25477 changeComponentType(type, newComponentType) { 25478 return this.getTypeFromLength(this.getTypeLength(type), newComponentType); 25479 } 25480 /** 25481 * Returns the integer type pendant for the given type. 25482 * 25483 * @param {string} type - The type. 25484 * @return {string} The integer type. 25485 */ 25486 getIntegerType(type) { 25487 const componentType = this.getComponentType(type); 25488 if (componentType === "int" || componentType === "uint") return type; 25489 return this.changeComponentType(type, "int"); 25490 } 25491 /** 25492 * Adds an active stack to the internal stack. 25493 * 25494 * @param {StackNode} stack - The stack node to add. 25495 */ 25496 setActiveStack(stack3) { 25497 this.activeStacks.push(stack3); 25498 } 25499 /** 25500 * Removes the active stack from the internal stack. 25501 * 25502 * @param {StackNode} stack - The stack node to remove. 25503 */ 25504 removeActiveStack(stack3) { 25505 if (this.activeStacks[this.activeStacks.length - 1] === stack3) { 25506 this.activeStacks.pop(); 25507 } else { 25508 throw new Error("NodeBuilder: Invalid active stack removal."); 25509 } 25510 } 25511 /** 25512 * Returns the active stack. 25513 * 25514 * @return {StackNode} The active stack. 25515 */ 25516 getActiveStack() { 25517 return this.activeStacks[this.activeStacks.length - 1]; 25518 } 25519 /** 25520 * Returns the base stack. 25521 * 25522 * @return {StackNode} The base stack. 25523 */ 25524 getBaseStack() { 25525 return this.activeStacks[0]; 25526 } 25527 /** 25528 * Adds a stack node to the internal stack. 25529 * 25530 * @return {StackNode} The added stack node. 25531 */ 25532 addStack() { 25533 this.stack = stack(this.stack); 25534 const previousStack = getCurrentStack(); 25535 this.stacks.push(previousStack); 25536 setCurrentStack(this.stack); 25537 return this.stack; 25538 } 25539 /** 25540 * Removes the last stack node from the internal stack. 25541 * 25542 * @return {StackNode} The removed stack node. 25543 */ 25544 removeStack() { 25545 const lastStack = this.stack; 25546 for (const node of lastStack.nodes) { 25547 const nodeData = this.getDataFromNode(node); 25548 nodeData.stack = lastStack; 25549 } 25550 this.stack = lastStack.parent; 25551 setCurrentStack(this.stacks.pop()); 25552 return lastStack; 25553 } 25554 /** 25555 * The builder maintains (cached) data for each node during the building process. This method 25556 * can be used to get these data for a specific shader stage and cache. 25557 * 25558 * @param {Node} node - The node to get the data for. 25559 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25560 * @param {?NodeCache} cache - An optional cache. 25561 * @return {Object} The node data. 25562 */ 25563 getDataFromNode(node, shaderStage = this.shaderStage, cache4 = null) { 25564 cache4 = cache4 === null ? node.isGlobal(this) ? this.globalCache : this.cache : cache4; 25565 let nodeData = cache4.getData(node); 25566 if (nodeData === void 0) { 25567 nodeData = {}; 25568 cache4.setData(node, nodeData); 25569 } 25570 if (nodeData[shaderStage] === void 0) nodeData[shaderStage] = {}; 25571 let data = nodeData[shaderStage]; 25572 const subBuilds = nodeData.any ? nodeData.any.subBuilds : null; 25573 const subBuild3 = this.getClosestSubBuild(subBuilds); 25574 if (subBuild3) { 25575 if (data.subBuildsCache === void 0) data.subBuildsCache = {}; 25576 data = data.subBuildsCache[subBuild3] || (data.subBuildsCache[subBuild3] = {}); 25577 data.subBuilds = subBuilds; 25578 } 25579 return data; 25580 } 25581 /** 25582 * Returns the properties for the given node and shader stage. 25583 * 25584 * Properties are typically used within a build stage to reference a node's 25585 * child node or nodes manually assigned to the properties in a separate build stage. 25586 * A typical usage pattern for defining nodes manually would be assigning dependency nodes 25587 * to the current node's properties in the setup stage and building those properties in the generate stage. 25588 * 25589 * @param {Node} node - The node to get the properties for. 25590 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage='any'] - The shader stage. 25591 * @return {Object} The node properties. 25592 */ 25593 getNodeProperties(node, shaderStage = "any") { 25594 const nodeData = this.getDataFromNode(node, shaderStage); 25595 return nodeData.properties || (nodeData.properties = { outputNode: null }); 25596 } 25597 /** 25598 * Returns an instance of {@link NodeAttribute} for the given buffer attribute node. 25599 * 25600 * @param {BufferAttributeNode} node - The buffer attribute node. 25601 * @param {string} type - The node type. 25602 * @return {NodeAttribute} The node attribute. 25603 */ 25604 getBufferAttributeFromNode(node, type) { 25605 const nodeData = this.getDataFromNode(node, "vertex"); 25606 let bufferAttribute3 = nodeData.bufferAttribute; 25607 if (bufferAttribute3 === void 0) { 25608 const index = this.uniforms.index++; 25609 bufferAttribute3 = new NodeAttribute("nodeAttribute" + index, type, node); 25610 this.bufferAttributes.push(bufferAttribute3); 25611 nodeData.bufferAttribute = bufferAttribute3; 25612 } 25613 return bufferAttribute3; 25614 } 25615 /** 25616 * Returns an instance of {@link StructType} for the given struct name and shader stage 25617 * or null if not found. 25618 * 25619 * @param {string} name - The name of the struct. 25620 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25621 * @return {?StructType} The struct type or null if not found. 25622 */ 25623 getStructTypeNode(name, shaderStage = this.shaderStage) { 25624 return this.types[shaderStage][name] || null; 25625 } 25626 /** 25627 * Returns an instance of {@link StructType} for the given output struct node. 25628 * 25629 * @param {OutputStructNode} node - The output struct node. 25630 * @param {Array<Object>} membersLayout - The output struct types. 25631 * @param {?string} [name=null] - The name of the struct. 25632 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25633 * @return {StructType} The struct type attribute. 25634 */ 25635 getStructTypeFromNode(node, membersLayout, name = null, shaderStage = this.shaderStage) { 25636 const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); 25637 let structType = nodeData.structType; 25638 if (structType === void 0) { 25639 const index = this.structs.index++; 25640 if (name === null) name = "StructType" + index; 25641 structType = new StructType(name, membersLayout); 25642 this.structs[shaderStage].push(structType); 25643 this.types[shaderStage][name] = node; 25644 nodeData.structType = structType; 25645 } 25646 return structType; 25647 } 25648 /** 25649 * Returns an instance of {@link StructType} for the given output struct node. 25650 * 25651 * @param {OutputStructNode} node - The output struct node. 25652 * @param {Array<Object>} membersLayout - The output struct types. 25653 * @return {StructType} The struct type attribute. 25654 */ 25655 getOutputStructTypeFromNode(node, membersLayout) { 25656 const structType = this.getStructTypeFromNode(node, membersLayout, "OutputType", "fragment"); 25657 structType.output = true; 25658 return structType; 25659 } 25660 /** 25661 * Returns an instance of {@link NodeUniform} for the given uniform node. 25662 * 25663 * @param {UniformNode} node - The uniform node. 25664 * @param {string} type - The uniform type. 25665 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25666 * @param {?string} name - The name of the uniform. 25667 * @return {NodeUniform} The node uniform. 25668 */ 25669 getUniformFromNode(node, type, shaderStage = this.shaderStage, name = null) { 25670 const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); 25671 let nodeUniform = nodeData.uniform; 25672 if (nodeUniform === void 0) { 25673 const index = this.uniforms.index++; 25674 nodeUniform = new NodeUniform(name || "nodeUniform" + index, type, node); 25675 this.uniforms[shaderStage].push(nodeUniform); 25676 this.registerDeclaration(nodeUniform); 25677 nodeData.uniform = nodeUniform; 25678 } 25679 return nodeUniform; 25680 } 25681 /** 25682 * Returns an instance of {@link NodeVar} for the given variable node. 25683 * 25684 * @param {VarNode} node - The variable node. 25685 * @param {?string} name - The variable's name. 25686 * @param {string} [type=node.getNodeType( this )] - The variable's type. 25687 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25688 * @param {boolean} [readOnly=false] - Whether the variable is read-only or not. 25689 * 25690 * @return {NodeVar} The node variable. 25691 */ 25692 getVarFromNode(node, name = null, type = node.getNodeType(this), shaderStage = this.shaderStage, readOnly = false) { 25693 const nodeData = this.getDataFromNode(node, shaderStage); 25694 const subBuildVariable = this.getSubBuildProperty("variable", nodeData.subBuilds); 25695 let nodeVar = nodeData[subBuildVariable]; 25696 if (nodeVar === void 0) { 25697 const idNS = readOnly ? "_const" : "_var"; 25698 const vars = this.vars[shaderStage] || (this.vars[shaderStage] = []); 25699 const id = this.vars[idNS] || (this.vars[idNS] = 0); 25700 if (name === null) { 25701 name = (readOnly ? "nodeConst" : "nodeVar") + id; 25702 this.vars[idNS]++; 25703 } 25704 if (subBuildVariable !== "variable") { 25705 name = this.getSubBuildProperty(name, nodeData.subBuilds); 25706 } 25707 const count = node.getArrayCount(this); 25708 nodeVar = new NodeVar(name, type, readOnly, count); 25709 if (!readOnly) { 25710 vars.push(nodeVar); 25711 } 25712 this.registerDeclaration(nodeVar); 25713 nodeData[subBuildVariable] = nodeVar; 25714 } 25715 return nodeVar; 25716 } 25717 /** 25718 * Returns whether a Node or its flow is deterministic, useful for use in `const`. 25719 * 25720 * @param {Node} node - The varying node. 25721 * @return {boolean} Returns true if deterministic. 25722 */ 25723 isDeterministic(node) { 25724 if (node.isMathNode) { 25725 return this.isDeterministic(node.aNode) && (node.bNode ? this.isDeterministic(node.bNode) : true) && (node.cNode ? this.isDeterministic(node.cNode) : true); 25726 } else if (node.isOperatorNode) { 25727 return this.isDeterministic(node.aNode) && (node.bNode ? this.isDeterministic(node.bNode) : true); 25728 } else if (node.isArrayNode) { 25729 if (node.values !== null) { 25730 for (const n of node.values) { 25731 if (!this.isDeterministic(n)) { 25732 return false; 25733 } 25734 } 25735 } 25736 return true; 25737 } else if (node.isConstNode) { 25738 return true; 25739 } 25740 return false; 25741 } 25742 /** 25743 * Returns an instance of {@link NodeVarying} for the given varying node. 25744 * 25745 * @param {(VaryingNode|PropertyNode)} node - The varying node. 25746 * @param {?string} name - The varying's name. 25747 * @param {string} [type=node.getNodeType( this )] - The varying's type. 25748 * @param {?string} interpolationType - The interpolation type of the varying. 25749 * @param {?string} interpolationSampling - The interpolation sampling type of the varying. 25750 * @return {NodeVar} The node varying. 25751 */ 25752 getVaryingFromNode(node, name = null, type = node.getNodeType(this), interpolationType = null, interpolationSampling = null) { 25753 const nodeData = this.getDataFromNode(node, "any"); 25754 const subBuildVarying = this.getSubBuildProperty("varying", nodeData.subBuilds); 25755 let nodeVarying = nodeData[subBuildVarying]; 25756 if (nodeVarying === void 0) { 25757 const varyings = this.varyings; 25758 const index = varyings.length; 25759 if (name === null) name = "nodeVarying" + index; 25760 if (subBuildVarying !== "varying") { 25761 name = this.getSubBuildProperty(name, nodeData.subBuilds); 25762 } 25763 nodeVarying = new NodeVarying(name, type, interpolationType, interpolationSampling); 25764 varyings.push(nodeVarying); 25765 this.registerDeclaration(nodeVarying); 25766 nodeData[subBuildVarying] = nodeVarying; 25767 } 25768 return nodeVarying; 25769 } 25770 /** 25771 * Registers a node declaration in the current shader stage. 25772 * 25773 * @param {Object} node - The node to be registered. 25774 */ 25775 registerDeclaration(node) { 25776 const shaderStage = this.shaderStage; 25777 const declarations = this.declarations[shaderStage] || (this.declarations[shaderStage] = {}); 25778 const property3 = this.getPropertyName(node); 25779 let index = 1; 25780 let name = property3; 25781 while (declarations[name] !== void 0) { 25782 name = property3 + "_" + index++; 25783 } 25784 if (index > 1) { 25785 node.name = name; 25786 warn(`TSL: Declaration name '${property3}' of '${node.type}' already in use. Renamed to '${name}'.`); 25787 } 25788 declarations[name] = node; 25789 } 25790 /** 25791 * Returns an instance of {@link NodeCode} for the given code node. 25792 * 25793 * @param {CodeNode} node - The code node. 25794 * @param {string} type - The node type. 25795 * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. 25796 * @return {NodeCode} The node code. 25797 */ 25798 getCodeFromNode(node, type, shaderStage = this.shaderStage) { 25799 const nodeData = this.getDataFromNode(node); 25800 let nodeCode = nodeData.code; 25801 if (nodeCode === void 0) { 25802 const codes = this.codes[shaderStage] || (this.codes[shaderStage] = []); 25803 const index = codes.length; 25804 nodeCode = new NodeCode("nodeCode" + index, type); 25805 codes.push(nodeCode); 25806 nodeData.code = nodeCode; 25807 } 25808 return nodeCode; 25809 } 25810 /** 25811 * Adds a code flow based on the code-block hierarchy. 25812 25813 * This is used so that code-blocks like If,Else create their variables locally if the Node 25814 * is only used inside one of these conditionals in the current shader stage. 25815 * 25816 * @param {Node} node - The node to add. 25817 * @param {Node} nodeBlock - Node-based code-block. Usually 'ConditionalNode'. 25818 */ 25819 addFlowCodeHierarchy(node, nodeBlock) { 25820 const { flowCodes, flowCodeBlock } = this.getDataFromNode(node); 25821 let needsFlowCode = true; 25822 let nodeBlockHierarchy = nodeBlock; 25823 while (nodeBlockHierarchy) { 25824 if (flowCodeBlock.get(nodeBlockHierarchy) === true) { 25825 needsFlowCode = false; 25826 break; 25827 } 25828 nodeBlockHierarchy = this.getDataFromNode(nodeBlockHierarchy).parentNodeBlock; 25829 } 25830 if (needsFlowCode) { 25831 for (const flowCode of flowCodes) { 25832 this.addLineFlowCode(flowCode); 25833 } 25834 } 25835 } 25836 /** 25837 * Add a inline-code to the current flow code-block. 25838 * 25839 * @param {Node} node - The node to add. 25840 * @param {string} code - The code to add. 25841 * @param {Node} nodeBlock - Current ConditionalNode 25842 */ 25843 addLineFlowCodeBlock(node, code3, nodeBlock) { 25844 const nodeData = this.getDataFromNode(node); 25845 const flowCodes = nodeData.flowCodes || (nodeData.flowCodes = []); 25846 const codeBlock = nodeData.flowCodeBlock || (nodeData.flowCodeBlock = /* @__PURE__ */ new WeakMap()); 25847 flowCodes.push(code3); 25848 codeBlock.set(nodeBlock, true); 25849 } 25850 /** 25851 * Add a inline-code to the current flow. 25852 * 25853 * @param {string} code - The code to add. 25854 * @param {?Node} [node= null] - Optional Node, can help the system understand if the Node is part of a code-block. 25855 * @return {NodeBuilder} A reference to this node builder. 25856 */ 25857 addLineFlowCode(code3, node = null) { 25858 if (code3 === "") return this; 25859 if (node !== null && this.context.nodeBlock) { 25860 this.addLineFlowCodeBlock(node, code3, this.context.nodeBlock); 25861 } 25862 code3 = this.tab + code3; 25863 if (!/;\s*$/.test(code3)) { 25864 code3 = code3 + ";\n"; 25865 } 25866 this.flow.code += code3; 25867 return this; 25868 } 25869 /** 25870 * Adds a code to the current code flow. 25871 * 25872 * @param {string} code - Shader code. 25873 * @return {NodeBuilder} A reference to this node builder. 25874 */ 25875 addFlowCode(code3) { 25876 this.flow.code += code3; 25877 return this; 25878 } 25879 /** 25880 * Add tab in the code that will be generated so that other snippets respect the current tabulation. 25881 * Typically used in codes with If,Else. 25882 * 25883 * @return {NodeBuilder} A reference to this node builder. 25884 */ 25885 addFlowTab() { 25886 this.tab += " "; 25887 return this; 25888 } 25889 /** 25890 * Removes a tab. 25891 * 25892 * @return {NodeBuilder} A reference to this node builder. 25893 */ 25894 removeFlowTab() { 25895 this.tab = this.tab.slice(0, -1); 25896 return this; 25897 } 25898 /** 25899 * Gets the current flow data based on a Node. 25900 * 25901 * @param {Node} node - Node that the flow was started. 25902 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 25903 * @return {Object} The flow data. 25904 */ 25905 getFlowData(node) { 25906 return this.flowsData.get(node); 25907 } 25908 /** 25909 * Executes the node flow based on a root node to generate the final shader code. 25910 * 25911 * @param {Node} node - The node to execute. 25912 * @return {Object} The code flow. 25913 */ 25914 flowNode(node) { 25915 const output3 = node.getNodeType(this); 25916 const flowData = this.flowChildNode(node, output3); 25917 this.flowsData.set(node, flowData); 25918 return flowData; 25919 } 25920 /** 25921 * Includes a node in the current function node. 25922 * 25923 * @param {Node} node - The node to include. 25924 * @returns {void} 25925 */ 25926 addInclude(node) { 25927 if (this.currentFunctionNode !== null) { 25928 this.currentFunctionNode.includes.push(node); 25929 } 25930 } 25931 /** 25932 * Returns the native shader operator name for a given generic name. 25933 * It is a similar type of method like {@link NodeBuilder#getMethod}. 25934 * 25935 * @param {ShaderNodeInternal} shaderNode - The shader node to build the function node with. 25936 * @return {FunctionNode} The build function node. 25937 */ 25938 buildFunctionNode(shaderNode) { 25939 const fn = new FunctionNode(); 25940 const previous = this.currentFunctionNode; 25941 this.currentFunctionNode = fn; 25942 fn.code = this.buildFunctionCode(shaderNode); 25943 this.currentFunctionNode = previous; 25944 return fn; 25945 } 25946 /** 25947 * Generates a code flow based on a TSL function: Fn(). 25948 * 25949 * @param {ShaderNodeInternal} shaderNode - A function code will be generated based on the input. 25950 * @return {Object} 25951 */ 25952 flowShaderNode(shaderNode) { 25953 const layout = shaderNode.layout; 25954 const inputs = { 25955 [Symbol.iterator]() { 25956 let index = 0; 25957 const values = Object.values(this); 25958 return { 25959 next: () => ({ 25960 value: values[index], 25961 done: index++ >= values.length 25962 }) 25963 }; 25964 } 25965 }; 25966 for (const input of layout.inputs) { 25967 inputs[input.name] = new ParameterNode(input.type, input.name); 25968 } 25969 shaderNode.layout = null; 25970 const callNode = shaderNode.call(inputs); 25971 const flowData = this.flowStagesNode(callNode, layout.type); 25972 shaderNode.layout = layout; 25973 return flowData; 25974 } 25975 /** 25976 * Executes the node in a specific build stage. 25977 * 25978 * This function can be used to arbitrarily execute the specified build stage 25979 * outside of the standard build process. For instance, if a node's type depends 25980 * on properties created by the 'setup' stage, then flowBuildStage(node, 'setup') 25981 * can be used to execute the setup build stage and access its generated nodes 25982 * before the standard build process begins. 25983 * 25984 * @param {Node} node - The node to execute. 25985 * @param {string} buildStage - The build stage to execute the node in. 25986 * @param {?(Node|string)} [output=null] - Expected output type. For example 'vec3'. 25987 * @return {?(Node|string)} The result of the node build. 25988 */ 25989 flowBuildStage(node, buildStage, output3 = null) { 25990 const previousBuildStage = this.getBuildStage(); 25991 this.setBuildStage(buildStage); 25992 const result = node.build(this, output3); 25993 this.setBuildStage(previousBuildStage); 25994 return result; 25995 } 25996 /** 25997 * Runs the node flow through all the steps of creation, 'setup', 'analyze', 'generate'. 25998 * 25999 * @param {Node} node - The node to execute. 26000 * @param {?string} output - Expected output type. For example 'vec3'. 26001 * @return {Object} 26002 */ 26003 flowStagesNode(node, output3 = null) { 26004 const previousFlow = this.flow; 26005 const previousVars = this.vars; 26006 const previousDeclarations = this.declarations; 26007 const previousCache = this.cache; 26008 const previousBuildStage = this.buildStage; 26009 const previousStack = this.stack; 26010 const flow = { 26011 code: "" 26012 }; 26013 this.flow = flow; 26014 this.vars = {}; 26015 this.declarations = {}; 26016 this.cache = new NodeCache(); 26017 this.stack = stack(); 26018 for (const buildStage of defaultBuildStages) { 26019 this.setBuildStage(buildStage); 26020 flow.result = node.build(this, output3); 26021 } 26022 flow.vars = this.getVars(this.shaderStage); 26023 this.flow = previousFlow; 26024 this.vars = previousVars; 26025 this.declarations = previousDeclarations; 26026 this.cache = previousCache; 26027 this.stack = previousStack; 26028 this.setBuildStage(previousBuildStage); 26029 return flow; 26030 } 26031 /** 26032 * Returns the native shader operator name for a given generic name. 26033 * It is a similar type of method like {@link NodeBuilder#getMethod}. 26034 * 26035 * @abstract 26036 * @param {string} op - The operator name to resolve. 26037 * @return {?string} The resolved operator name. 26038 */ 26039 getFunctionOperator() { 26040 return null; 26041 } 26042 /** 26043 * Builds the given shader node. 26044 * 26045 * @abstract 26046 * @param {ShaderNodeInternal} shaderNode - The shader node. 26047 * @return {string} The function code. 26048 */ 26049 buildFunctionCode() { 26050 warn("Abstract function."); 26051 } 26052 /** 26053 * Generates a code flow based on a child Node. 26054 * 26055 * @param {Node} node - The node to execute. 26056 * @param {?string} output - Expected output type. For example 'vec3'. 26057 * @return {Object} The code flow. 26058 */ 26059 flowChildNode(node, output3 = null) { 26060 const previousFlow = this.flow; 26061 const flow = { 26062 code: "" 26063 }; 26064 this.flow = flow; 26065 flow.result = node.build(this, output3); 26066 this.flow = previousFlow; 26067 return flow; 26068 } 26069 /** 26070 * Executes a flow of code in a different stage. 26071 * 26072 * Some nodes like `varying()` have the ability to compute code in vertex-stage and 26073 * return the value in fragment-stage even if it is being executed in an input fragment. 26074 * 26075 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26076 * @param {Node} node - The node to execute. 26077 * @param {?string} output - Expected output type. For example 'vec3'. 26078 * @param {?string} propertyName - The property name to assign the result. 26079 * @return {?(Object|Node)} The code flow or node.build() result. 26080 */ 26081 flowNodeFromShaderStage(shaderStage, node, output3 = null, propertyName = null) { 26082 const previousTab = this.tab; 26083 const previousCache = this.cache; 26084 const previousShaderStage = this.shaderStage; 26085 const previousContext = this.context; 26086 this.setShaderStage(shaderStage); 26087 const context3 = { ...this.context }; 26088 delete context3.nodeBlock; 26089 this.cache = this.globalCache; 26090 this.tab = " "; 26091 this.context = context3; 26092 let result = null; 26093 if (this.buildStage === "generate") { 26094 const flowData = this.flowChildNode(node, output3); 26095 if (propertyName !== null) { 26096 flowData.code += `${this.tab + propertyName} = ${flowData.result}; 26097`; 26098 } 26099 this.flowCode[shaderStage] = this.flowCode[shaderStage] + flowData.code; 26100 result = flowData; 26101 } else { 26102 result = node.build(this); 26103 } 26104 this.setShaderStage(previousShaderStage); 26105 this.cache = previousCache; 26106 this.tab = previousTab; 26107 this.context = previousContext; 26108 return result; 26109 } 26110 /** 26111 * Returns an array holding all node attributes of this node builder. 26112 * 26113 * @return {Array<NodeAttribute>} The node attributes of this builder. 26114 */ 26115 getAttributesArray() { 26116 return this.attributes.concat(this.bufferAttributes); 26117 } 26118 /** 26119 * Returns the attribute definitions as a shader string for the given shader stage. 26120 * 26121 * @abstract 26122 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26123 * @return {string} The attribute code section. 26124 */ 26125 getAttributes() { 26126 warn("Abstract function."); 26127 } 26128 /** 26129 * Returns the varying definitions as a shader string for the given shader stage. 26130 * 26131 * @abstract 26132 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26133 * @return {string} The varying code section. 26134 */ 26135 getVaryings() { 26136 warn("Abstract function."); 26137 } 26138 /** 26139 * Returns a single variable definition as a shader string for the given variable type and name. 26140 * 26141 * @param {string} type - The variable's type. 26142 * @param {string} name - The variable's name. 26143 * @param {?number} [count=null] - The array length. 26144 * @return {string} The shader string. 26145 */ 26146 getVar(type, name, count = null) { 26147 return `${count !== null ? this.generateArrayDeclaration(type, count) : this.getType(type)} ${name}`; 26148 } 26149 /** 26150 * Returns the variable definitions as a shader string for the given shader stage. 26151 * 26152 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26153 * @param {boolean} [global=false] - Whether the variables are global. 26154 * @return {string} The variable code section. 26155 */ 26156 getVars(shaderStage, global = false) { 26157 const snippets = []; 26158 const vars = this.vars[shaderStage]; 26159 if (vars !== void 0) { 26160 for (const variable of vars) { 26161 snippets.push(`${this.getVar(variable.type, variable.name, variable.count)};`); 26162 } 26163 } 26164 return snippets.join(global ? "\n" : "\n "); 26165 } 26166 /** 26167 * Returns the uniform definitions as a shader string for the given shader stage. 26168 * 26169 * @abstract 26170 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26171 * @return {string} The uniform code section. 26172 */ 26173 getUniforms() { 26174 warn("Abstract function."); 26175 } 26176 /** 26177 * Returns the native code definitions as a shader string for the given shader stage. 26178 * 26179 * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage. 26180 * @return {string} The native code section. 26181 */ 26182 getCodes(shaderStage) { 26183 const codes = this.codes[shaderStage]; 26184 let code3 = ""; 26185 if (codes !== void 0) { 26186 for (const nodeCode of codes) { 26187 code3 += nodeCode.code + "\n"; 26188 } 26189 } 26190 return code3; 26191 } 26192 /** 26193 * Returns the hash of this node builder. 26194 * 26195 * @return {string} The hash. 26196 */ 26197 getHash() { 26198 return this.vertexShader + this.fragmentShader + this.computeShader; 26199 } 26200 /** 26201 * Sets the current shader stage. 26202 * 26203 * @param {?('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage to set. 26204 */ 26205 setShaderStage(shaderStage) { 26206 this.shaderStage = shaderStage; 26207 } 26208 /** 26209 * Returns the current shader stage. 26210 * 26211 * @return {?('vertex'|'fragment'|'compute'|'any')} The current shader stage. 26212 */ 26213 getShaderStage() { 26214 return this.shaderStage; 26215 } 26216 /** 26217 * Sets the current build stage. 26218 * 26219 * @param {?('setup'|'analyze'|'generate')} buildStage - The build stage to set. 26220 */ 26221 setBuildStage(buildStage) { 26222 this.buildStage = buildStage; 26223 } 26224 /** 26225 * Returns the current build stage. 26226 * 26227 * @return {?('setup'|'analyze'|'generate')} The current build stage. 26228 */ 26229 getBuildStage() { 26230 return this.buildStage; 26231 } 26232 /** 26233 * Controls the code build of the shader stages. 26234 * 26235 * @abstract 26236 */ 26237 buildCode() { 26238 warn("Abstract function."); 26239 } 26240 /** 26241 * Returns the current sub-build layer. 26242 * 26243 * @return {SubBuildNode} The current sub-build layers. 26244 */ 26245 get subBuild() { 26246 return this.subBuildLayers[this.subBuildLayers.length - 1] || null; 26247 } 26248 /** 26249 * Adds a sub-build layer to the node builder. 26250 * 26251 * @param {SubBuildNode} subBuild - The sub-build layer to add. 26252 */ 26253 addSubBuild(subBuild3) { 26254 this.subBuildLayers.push(subBuild3); 26255 } 26256 /** 26257 * Removes the last sub-build layer from the node builder. 26258 * 26259 * @return {SubBuildNode} The removed sub-build layer. 26260 */ 26261 removeSubBuild() { 26262 return this.subBuildLayers.pop(); 26263 } 26264 /** 26265 * Returns the closest sub-build layer for the given data. 26266 * 26267 * @param {Node|Set<string>|Array<string>} data - The data to get the closest sub-build layer from. 26268 * @return {?string} The closest sub-build name or null if none found. 26269 */ 26270 getClosestSubBuild(data) { 26271 let subBuilds; 26272 if (data && data.isNode) { 26273 if (data.isShaderCallNodeInternal) { 26274 subBuilds = data.shaderNode.subBuilds; 26275 } else if (data.isStackNode) { 26276 subBuilds = [data.subBuild]; 26277 } else { 26278 subBuilds = this.getDataFromNode(data, "any").subBuilds; 26279 } 26280 } else if (data instanceof Set) { 26281 subBuilds = [...data]; 26282 } else { 26283 subBuilds = data; 26284 } 26285 if (!subBuilds) return null; 26286 const subBuildLayers = this.subBuildLayers; 26287 for (let i = subBuilds.length - 1; i >= 0; i--) { 26288 const subBuild3 = subBuilds[i]; 26289 if (subBuildLayers.includes(subBuild3)) { 26290 return subBuild3; 26291 } 26292 } 26293 return null; 26294 } 26295 /** 26296 * Returns the output node of a sub-build layer. 26297 * 26298 * @param {Node} node - The node to get the output from. 26299 * @return {string} The output node name. 26300 */ 26301 getSubBuildOutput(node) { 26302 return this.getSubBuildProperty("outputNode", node); 26303 } 26304 /** 26305 * Returns the sub-build property name for the given property and node. 26306 * 26307 * @param {string} [property=''] - The property name. 26308 * @param {?Node} [node=null] - The node to get the sub-build from. 26309 * @return {string} The sub-build property name. 26310 */ 26311 getSubBuildProperty(property3 = "", node = null) { 26312 let subBuild3; 26313 if (node !== null) { 26314 subBuild3 = this.getClosestSubBuild(node); 26315 } else { 26316 subBuild3 = this.subBuildFn; 26317 } 26318 let result; 26319 if (subBuild3) { 26320 result = property3 ? subBuild3 + "_" + property3 : subBuild3; 26321 } else { 26322 result = property3; 26323 } 26324 return result; 26325 } 26326 /** 26327 * Prebuild the node builder. 26328 */ 26329 prebuild() { 26330 const { object, renderer, material } = this; 26331 if (renderer.contextNode.isContextNode === true) { 26332 this.context = { ...this.context, ...renderer.contextNode.getFlowContextData() }; 26333 } else { 26334 error('NodeBuilder: "renderer.contextNode" must be an instance of `context()`.'); 26335 } 26336 if (material && material.contextNode) { 26337 if (material.contextNode.isContextNode === true) { 26338 this.context = { ...this.context, ...material.contextNode.getFlowContextData() }; 26339 } else { 26340 error('NodeBuilder: "material.contextNode" must be an instance of `context()`.'); 26341 } 26342 } 26343 if (material !== null) { 26344 let nodeMaterial = renderer.library.fromMaterial(material); 26345 if (nodeMaterial === null) { 26346 error(`NodeBuilder: Material "${material.type}" is not compatible.`); 26347 nodeMaterial = new NodeMaterial(); 26348 } 26349 nodeMaterial.build(this); 26350 } else { 26351 this.addFlow("compute", object); 26352 } 26353 } 26354 /** 26355 * Central build method which controls the build for the given object. 26356 * 26357 * @return {NodeBuilder} A reference to this node builder. 26358 */ 26359 build() { 26360 this.prebuild(); 26361 for (const buildStage of defaultBuildStages) { 26362 this.setBuildStage(buildStage); 26363 if (this.context.position && this.context.position.isNode) { 26364 this.flowNodeFromShaderStage("vertex", this.context.position); 26365 } 26366 for (const shaderStage of shaderStages) { 26367 this.setShaderStage(shaderStage); 26368 const flowNodes = this.flowNodes[shaderStage]; 26369 for (const node of flowNodes) { 26370 if (buildStage === "generate") { 26371 this.flowNode(node); 26372 } else { 26373 node.build(this); 26374 } 26375 } 26376 } 26377 } 26378 this.setBuildStage(null); 26379 this.setShaderStage(null); 26380 this.buildCode(); 26381 this.buildUpdateNodes(); 26382 return this; 26383 } 26384 /** 26385 * Async version of build() that yields to main thread between shader stages. 26386 * Use this in compileAsync() to prevent blocking the main thread. 26387 * 26388 * @return {Promise<NodeBuilder>} A promise that resolves to this node builder. 26389 */ 26390 async buildAsync() { 26391 this.prebuild(); 26392 for (const buildStage of defaultBuildStages) { 26393 this.setBuildStage(buildStage); 26394 if (this.context.position && this.context.position.isNode) { 26395 this.flowNodeFromShaderStage("vertex", this.context.position); 26396 } 26397 for (const shaderStage of shaderStages) { 26398 this.setShaderStage(shaderStage); 26399 const flowNodes = this.flowNodes[shaderStage]; 26400 for (const node of flowNodes) { 26401 if (buildStage === "generate") { 26402 this.flowNode(node); 26403 } else { 26404 node.build(this); 26405 } 26406 } 26407 await yieldToMain(); 26408 } 26409 } 26410 this.setBuildStage(null); 26411 this.setShaderStage(null); 26412 this.buildCode(); 26413 this.buildUpdateNodes(); 26414 return this; 26415 } 26416 /** 26417 * Returns shared data object for the given node. 26418 * 26419 * @param {Node} node - The node to get shared data from. 26420 * @return {Object} The shared data. 26421 */ 26422 getSharedDataFromNode(node) { 26423 let data = sharedNodeData.get(node); 26424 if (data === void 0) { 26425 data = {}; 26426 } 26427 return data; 26428 } 26429 /** 26430 * Returns a uniform representation which is later used for UBO generation and rendering. 26431 * 26432 * @param {NodeUniform} uniformNode - The uniform node. 26433 * @param {string} type - The requested type. 26434 * @return {Uniform} The uniform. 26435 */ 26436 getNodeUniform(uniformNode, type) { 26437 const nodeData = this.getSharedDataFromNode(uniformNode); 26438 let node = nodeData.cache; 26439 if (node === void 0) { 26440 if (type === "float" || type === "int" || type === "uint") node = new NumberNodeUniform(uniformNode); 26441 else if (type === "vec2" || type === "ivec2" || type === "uvec2") node = new Vector2NodeUniform(uniformNode); 26442 else if (type === "vec3" || type === "ivec3" || type === "uvec3") node = new Vector3NodeUniform(uniformNode); 26443 else if (type === "vec4" || type === "ivec4" || type === "uvec4") node = new Vector4NodeUniform(uniformNode); 26444 else if (type === "color") node = new ColorNodeUniform(uniformNode); 26445 else if (type === "mat2") node = new Matrix2NodeUniform(uniformNode); 26446 else if (type === "mat3") node = new Matrix3NodeUniform(uniformNode); 26447 else if (type === "mat4") node = new Matrix4NodeUniform(uniformNode); 26448 else { 26449 throw new Error(`Uniform "${type}" not implemented.`); 26450 } 26451 nodeData.cache = node; 26452 } 26453 return node; 26454 } 26455 /** 26456 * Formats the given shader snippet from a given type into another one. E.g. 26457 * this method might be used to convert a simple float string `"1.0"` into a 26458 * `vec3` representation: `"vec3<f32>( 1.0 )"`. 26459 * 26460 * @param {string} snippet - The shader snippet. 26461 * @param {string} fromType - The source type. 26462 * @param {string} toType - The target type. 26463 * @return {string} The updated shader string. 26464 */ 26465 format(snippet, fromType, toType) { 26466 fromType = this.getVectorType(fromType); 26467 toType = this.getVectorType(toType); 26468 if (fromType === toType || toType === null || this.isReference(toType)) { 26469 return snippet; 26470 } 26471 const fromTypeLength = this.getTypeLength(fromType); 26472 const toTypeLength = this.getTypeLength(toType); 26473 if (fromTypeLength === 16 && toTypeLength === 9) { 26474 return `${this.getType(toType)}( ${snippet}[ 0 ].xyz, ${snippet}[ 1 ].xyz, ${snippet}[ 2 ].xyz )`; 26475 } 26476 if (fromTypeLength === 9 && toTypeLength === 4) { 26477 return `${this.getType(toType)}( ${snippet}[ 0 ].xy, ${snippet}[ 1 ].xy )`; 26478 } 26479 if (fromTypeLength > 4) { 26480 return snippet; 26481 } 26482 if (toTypeLength > 4 || toTypeLength === 0) { 26483 return snippet; 26484 } 26485 if (fromTypeLength === toTypeLength) { 26486 return `${this.getType(toType)}( ${snippet} )`; 26487 } 26488 if (fromTypeLength > toTypeLength) { 26489 snippet = toType === "bool" ? `all( ${snippet} )` : `${snippet}.${"xyz".slice(0, toTypeLength)}`; 26490 return this.format(snippet, this.getTypeFromLength(toTypeLength, this.getComponentType(fromType)), toType); 26491 } 26492 if (toTypeLength === 4 && fromTypeLength > 1) { 26493 return `${this.getType(toType)}( ${this.format(snippet, fromType, "vec3")}, 1.0 )`; 26494 } 26495 if (fromTypeLength === 2) { 26496 return `${this.getType(toType)}( ${this.format(snippet, fromType, "vec2")}, 0.0 )`; 26497 } 26498 if (fromTypeLength === 1 && toTypeLength > 1 && fromType !== this.getComponentType(toType)) { 26499 snippet = `${this.getType(this.getComponentType(toType))}( ${snippet} )`; 26500 } 26501 return `${this.getType(toType)}( ${snippet} )`; 26502 } 26503 /** 26504 * Returns a signature with the engine's current revision. 26505 * 26506 * @return {string} The signature. 26507 */ 26508 getSignature() { 26509 return `// Three.js r${REVISION} - Node System 26510`; 26511 } 26512 /** 26513 * Returns `true` if data from the previous frame are required. Relevant 26514 * when computing motion vectors with {@link VelocityNode}. 26515 * 26516 * @return {boolean} Whether data from the previous frame are required or not. 26517 */ 26518 needsPreviousData() { 26519 const mrt3 = this.renderer.getMRT(); 26520 return mrt3 && mrt3.has("velocity") || getDataFromObject(this.object).useVelocity === true; 26521 } 26522}; 26523var NodeFrame = class { 26524 /** 26525 * Constructs a new node fame. 26526 */ 26527 constructor() { 26528 this.time = 0; 26529 this.deltaTime = 0; 26530 this.frameId = 0; 26531 this.renderId = 0; 26532 this.updateMap = /* @__PURE__ */ new WeakMap(); 26533 this.updateBeforeMap = /* @__PURE__ */ new WeakMap(); 26534 this.updateAfterMap = /* @__PURE__ */ new WeakMap(); 26535 this.renderer = null; 26536 this.material = null; 26537 this.camera = null; 26538 this.object = null; 26539 this.scene = null; 26540 } 26541 /** 26542 * Returns a dictionary for a given node and update map which 26543 * is used to correctly call node update methods per frame or render. 26544 * 26545 * @private 26546 * @param {WeakMap<Node, Object>} referenceMap - The reference weak map. 26547 * @param {Node} nodeRef - The reference to the current node. 26548 * @return {Object<string,WeakMap<Object, number>>} The dictionary. 26549 */ 26550 _getMaps(referenceMap, nodeRef) { 26551 let maps = referenceMap.get(nodeRef); 26552 if (maps === void 0) { 26553 maps = { 26554 renderId: 0, 26555 frameId: 0 26556 }; 26557 referenceMap.set(nodeRef, maps); 26558 } 26559 return maps; 26560 } 26561 /** 26562 * This method executes the {@link Node#updateBefore} for the given node. 26563 * It makes sure {@link Node#updateBeforeType} is honored meaning the update 26564 * is only executed once per frame, render or object depending on the update 26565 * type. 26566 * 26567 * @param {Node} node - The node that should be updated. 26568 */ 26569 updateBeforeNode(node) { 26570 const updateType = node.getUpdateBeforeType(); 26571 const reference3 = node.updateReference(this); 26572 if (updateType === NodeUpdateType.FRAME) { 26573 const nodeUpdateBeforeMap = this._getMaps(this.updateBeforeMap, reference3); 26574 if (nodeUpdateBeforeMap.frameId !== this.frameId) { 26575 const previousFrameId = nodeUpdateBeforeMap.frameId; 26576 nodeUpdateBeforeMap.frameId = this.frameId; 26577 if (node.updateBefore(this) === false) { 26578 nodeUpdateBeforeMap.frameId = previousFrameId; 26579 } 26580 } 26581 } else if (updateType === NodeUpdateType.RENDER) { 26582 const nodeUpdateBeforeMap = this._getMaps(this.updateBeforeMap, reference3); 26583 if (nodeUpdateBeforeMap.renderId !== this.renderId) { 26584 const previousRenderId = nodeUpdateBeforeMap.renderId; 26585 nodeUpdateBeforeMap.renderId = this.renderId; 26586 if (node.updateBefore(this) === false) { 26587 nodeUpdateBeforeMap.renderId = previousRenderId; 26588 } 26589 } 26590 } else if (updateType === NodeUpdateType.OBJECT) { 26591 node.updateBefore(this); 26592 } 26593 } 26594 /** 26595 * This method executes the {@link Node#updateAfter} for the given node. 26596 * It makes sure {@link Node#updateAfterType} is honored meaning the update 26597 * is only executed once per frame, render or object depending on the update 26598 * type. 26599 * 26600 * @param {Node} node - The node that should be updated. 26601 */ 26602 updateAfterNode(node) { 26603 const updateType = node.getUpdateAfterType(); 26604 const reference3 = node.updateReference(this); 26605 if (updateType === NodeUpdateType.FRAME) { 26606 const nodeUpdateAfterMap = this._getMaps(this.updateAfterMap, reference3); 26607 if (nodeUpdateAfterMap.frameId !== this.frameId) { 26608 if (node.updateAfter(this) !== false) { 26609 nodeUpdateAfterMap.frameId = this.frameId; 26610 } 26611 } 26612 } else if (updateType === NodeUpdateType.RENDER) { 26613 const nodeUpdateAfterMap = this._getMaps(this.updateAfterMap, reference3); 26614 if (nodeUpdateAfterMap.renderId !== this.renderId) { 26615 if (node.updateAfter(this) !== false) { 26616 nodeUpdateAfterMap.renderId = this.renderId; 26617 } 26618 } 26619 } else if (updateType === NodeUpdateType.OBJECT) { 26620 node.updateAfter(this); 26621 } 26622 } 26623 /** 26624 * This method executes the {@link Node#update} for the given node. 26625 * It makes sure {@link Node#updateType} is honored meaning the update 26626 * is only executed once per frame, render or object depending on the update 26627 * type. 26628 * 26629 * @param {Node} node - The node that should be updated. 26630 */ 26631 updateNode(node) { 26632 const updateType = node.getUpdateType(); 26633 const reference3 = node.updateReference(this); 26634 if (updateType === NodeUpdateType.FRAME) { 26635 const nodeUpdateMap = this._getMaps(this.updateMap, reference3); 26636 if (nodeUpdateMap.frameId !== this.frameId) { 26637 if (node.update(this) !== false) { 26638 nodeUpdateMap.frameId = this.frameId; 26639 } 26640 } 26641 } else if (updateType === NodeUpdateType.RENDER) { 26642 const nodeUpdateMap = this._getMaps(this.updateMap, reference3); 26643 if (nodeUpdateMap.renderId !== this.renderId) { 26644 if (node.update(this) !== false) { 26645 nodeUpdateMap.renderId = this.renderId; 26646 } 26647 } 26648 } else if (updateType === NodeUpdateType.OBJECT) { 26649 node.update(this); 26650 } 26651 } 26652 /** 26653 * Updates the internal state of the node frame. This method is 26654 * called by the renderer in its internal animation loop. 26655 */ 26656 update() { 26657 this.frameId++; 26658 if (this.lastTime === void 0) this.lastTime = performance.now(); 26659 this.deltaTime = (performance.now() - this.lastTime) / 1e3; 26660 this.lastTime = performance.now(); 26661 this.time += this.deltaTime; 26662 } 26663}; 26664var NodeFunctionInput = class { 26665 /** 26666 * Constructs a new node function input. 26667 * 26668 * @param {string} type - The input type. 26669 * @param {string} name - The input name. 26670 * @param {?number} [count=null] - If the input is an Array, count will be the length. 26671 * @param {('in'|'out'|'inout')} [qualifier=''] - The parameter qualifier (only relevant for GLSL). 26672 * @param {boolean} [isConst=false] - Whether the input uses a const qualifier or not (only relevant for GLSL). 26673 */ 26674 constructor(type, name, count = null, qualifier = "", isConst = false) { 26675 this.type = type; 26676 this.name = name; 26677 this.count = count; 26678 this.qualifier = qualifier; 26679 this.isConst = isConst; 26680 } 26681}; 26682NodeFunctionInput.isNodeFunctionInput = true; 26683var AmbientLightNode = class extends AnalyticLightNode { 26684 static get type() { 26685 return "AmbientLightNode"; 26686 } 26687 /** 26688 * Constructs a new ambient light node. 26689 * 26690 * @param {?AmbientLight} [light=null] - The ambient light source. 26691 */ 26692 constructor(light = null) { 26693 super(light); 26694 } 26695 setup({ context: context3 }) { 26696 context3.irradiance.addAssign(this.colorNode); 26697 } 26698}; 26699var DirectionalLightNode = class extends AnalyticLightNode { 26700 static get type() { 26701 return "DirectionalLightNode"; 26702 } 26703 /** 26704 * Constructs a new directional light node. 26705 * 26706 * @param {?DirectionalLight} [light=null] - The directional light source. 26707 */ 26708 constructor(light = null) { 26709 super(light); 26710 } 26711 setupDirect() { 26712 const lightColor = this.colorNode; 26713 const lightDirection = lightTargetDirection(this.light); 26714 return { lightDirection, lightColor }; 26715 } 26716}; 26717var HemisphereLightNode = class extends AnalyticLightNode { 26718 static get type() { 26719 return "HemisphereLightNode"; 26720 } 26721 /** 26722 * Constructs a new hemisphere light node. 26723 * 26724 * @param {?HemisphereLight} [light=null] - The hemisphere light source. 26725 */ 26726 constructor(light = null) { 26727 super(light); 26728 this.lightPositionNode = lightPosition(light); 26729 this.lightDirectionNode = this.lightPositionNode.normalize(); 26730 this.groundColorNode = uniform(new Color()).setGroup(renderGroup); 26731 } 26732 /** 26733 * Overwritten to updated hemisphere light specific uniforms. 26734 * 26735 * @param {NodeFrame} frame - A reference to the current node frame. 26736 */ 26737 update(frame) { 26738 const { light } = this; 26739 super.update(frame); 26740 this.lightPositionNode.object3d = light; 26741 this.groundColorNode.value.copy(light.groundColor).multiplyScalar(light.intensity); 26742 } 26743 setup(builder) { 26744 const { colorNode, groundColorNode, lightDirectionNode } = this; 26745 const dotNL = normalWorld.dot(lightDirectionNode); 26746 const hemiDiffuseWeight = dotNL.mul(0.5).add(0.5); 26747 const irradiance = mix(groundColorNode, colorNode, hemiDiffuseWeight); 26748 builder.context.irradiance.addAssign(irradiance); 26749 } 26750}; 26751var SpotLightNode = class extends AnalyticLightNode { 26752 static get type() { 26753 return "SpotLightNode"; 26754 } 26755 /** 26756 * Constructs a new spot light node. 26757 * 26758 * @param {?SpotLight} [light=null] - The spot light source. 26759 */ 26760 constructor(light = null) { 26761 super(light); 26762 this.coneCosNode = uniform(0).setGroup(renderGroup); 26763 this.penumbraCosNode = uniform(0).setGroup(renderGroup); 26764 this.cutoffDistanceNode = uniform(0).setGroup(renderGroup); 26765 this.decayExponentNode = uniform(0).setGroup(renderGroup); 26766 this.colorNode = uniform(this.color).setGroup(renderGroup); 26767 } 26768 /** 26769 * Overwritten to updated spot light specific uniforms. 26770 * 26771 * @param {NodeFrame} frame - A reference to the current node frame. 26772 */ 26773 update(frame) { 26774 super.update(frame); 26775 const { light } = this; 26776 this.coneCosNode.value = Math.cos(light.angle); 26777 this.penumbraCosNode.value = Math.cos(light.angle * (1 - light.penumbra)); 26778 this.cutoffDistanceNode.value = light.distance; 26779 this.decayExponentNode.value = light.decay; 26780 } 26781 /** 26782 * Computes the spot attenuation for the given angle. 26783 * 26784 * @param {NodeBuilder} builder - The node builder. 26785 * @param {Node<float>} angleCosine - The angle to compute the spot attenuation for. 26786 * @return {Node<float>} The spot attenuation. 26787 */ 26788 getSpotAttenuation(builder, angleCosine) { 26789 const { coneCosNode, penumbraCosNode } = this; 26790 return smoothstep(coneCosNode, penumbraCosNode, angleCosine); 26791 } 26792 getLightCoord(builder) { 26793 const properties = builder.getNodeProperties(this); 26794 let projectionUV = properties.projectionUV; 26795 if (projectionUV === void 0) { 26796 projectionUV = lightProjectionUV(this.light, builder.context.positionWorld); 26797 properties.projectionUV = projectionUV; 26798 } 26799 return projectionUV; 26800 } 26801 setupDirect(builder) { 26802 const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this; 26803 const lightVector = this.getLightVector(builder); 26804 const lightDirection = lightVector.normalize(); 26805 const angleCos = lightDirection.dot(lightTargetDirection(light)); 26806 const spotAttenuation = this.getSpotAttenuation(builder, angleCos); 26807 const lightDistance = lightVector.length(); 26808 const lightAttenuation = getDistanceAttenuation({ 26809 lightDistance, 26810 cutoffDistance: cutoffDistanceNode, 26811 decayExponent: decayExponentNode 26812 }); 26813 let lightColor = colorNode.mul(spotAttenuation).mul(lightAttenuation); 26814 let projected, lightCoord; 26815 if (light.colorNode) { 26816 lightCoord = this.getLightCoord(builder); 26817 projected = light.colorNode(lightCoord); 26818 } else if (light.map) { 26819 lightCoord = this.getLightCoord(builder); 26820 projected = texture(light.map, lightCoord.xy).onRenderUpdate(() => light.map); 26821 } 26822 if (projected) { 26823 const inSpotLightMap = lightCoord.mul(2).sub(1).abs().lessThan(1).all(); 26824 lightColor = inSpotLightMap.select(lightColor.mul(projected), lightColor); 26825 } 26826 return { lightColor, lightDirection }; 26827 } 26828}; 26829var IESSpotLightNode = class extends SpotLightNode { 26830 static get type() { 26831 return "IESSpotLightNode"; 26832 } 26833 /** 26834 * Overwrites the default implementation to compute an IES conform spot attenuation. 26835 * 26836 * @param {NodeBuilder} builder - The node builder. 26837 * @param {Node<float>} angleCosine - The angle to compute the spot attenuation for. 26838 * @return {Node<float>} The spot attenuation. 26839 */ 26840 getSpotAttenuation(builder, angleCosine) { 26841 const iesMap = this.light.iesMap; 26842 let spotAttenuation = null; 26843 if (iesMap && iesMap.isTexture === true) { 26844 const angle = angleCosine.acos().mul(1 / Math.PI); 26845 spotAttenuation = texture(iesMap, vec2(angle, 0), 0).r; 26846 } else { 26847 spotAttenuation = super.getSpotAttenuation(angleCosine); 26848 } 26849 return spotAttenuation; 26850 } 26851}; 26852var LightProbeNode = class extends AnalyticLightNode { 26853 static get type() { 26854 return "LightProbeNode"; 26855 } 26856 /** 26857 * Constructs a new light probe node. 26858 * 26859 * @param {?LightProbe} [light=null] - The light probe. 26860 */ 26861 constructor(light = null) { 26862 super(light); 26863 const array3 = []; 26864 for (let i = 0; i < 9; i++) array3.push(new Vector3()); 26865 this.lightProbe = uniformArray(array3); 26866 } 26867 /** 26868 * Overwritten to updated light probe specific uniforms. 26869 * 26870 * @param {NodeFrame} frame - A reference to the current node frame. 26871 */ 26872 update(frame) { 26873 const { light } = this; 26874 super.update(frame); 26875 for (let i = 0; i < 9; i++) { 26876 this.lightProbe.array[i].copy(light.sh.coefficients[i]).multiplyScalar(light.intensity); 26877 } 26878 } 26879 setup(builder) { 26880 const irradiance = getShIrradianceAt(normalWorld, this.lightProbe); 26881 builder.context.irradiance.addAssign(irradiance); 26882 } 26883}; 26884var sdBox = /* @__PURE__ */ Fn(([p, b]) => { 26885 const d = p.abs().sub(b); 26886 return length(max$1(d, 0)).add(min$1(max$1(d.x, d.y), 0)); 26887}); 26888var ProjectorLightNode = class extends SpotLightNode { 26889 static get type() { 26890 return "ProjectorLightNode"; 26891 } 26892 update(frame) { 26893 super.update(frame); 26894 const light = this.light; 26895 this.penumbraCosNode.value = Math.min(Math.cos(light.angle * (1 - light.penumbra)), 0.99999); 26896 if (light.aspect === null) { 26897 let aspect = 1; 26898 if (light.map !== null) { 26899 aspect = light.map.width / light.map.height; 26900 } 26901 light.shadow.aspect = aspect; 26902 } else { 26903 light.shadow.aspect = light.aspect; 26904 } 26905 } 26906 /** 26907 * Overwrites the default implementation to compute projection attenuation. 26908 * 26909 * @param {NodeBuilder} builder - The node builder. 26910 * @return {Node<float>} The spot attenuation. 26911 */ 26912 getSpotAttenuation(builder) { 26913 const attenuation = float(0); 26914 const penumbraCos = this.penumbraCosNode; 26915 const spotLightCoord = lightShadowMatrix(this.light).mul(builder.context.positionWorld || positionWorld); 26916 If(spotLightCoord.w.greaterThan(0), () => { 26917 const projectionUV = spotLightCoord.xyz.div(spotLightCoord.w); 26918 const boxDist = sdBox(projectionUV.xy.sub(vec2(0.5)), vec2(0.5)); 26919 const angleFactor = div(-1, sub(1, acos(penumbraCos)).sub(1)); 26920 attenuation.assign(saturate(boxDist.mul(-2).mul(angleFactor))); 26921 }); 26922 return attenuation; 26923 } 26924}; 26925var _matrix41 = /* @__PURE__ */ new Matrix4(); 26926var _matrix42 = /* @__PURE__ */ new Matrix4(); 26927var _ltcLib = null; 26928var RectAreaLightNode = class extends AnalyticLightNode { 26929 static get type() { 26930 return "RectAreaLightNode"; 26931 } 26932 /** 26933 * Constructs a new rect area light node. 26934 * 26935 * @param {?RectAreaLight} [light=null] - The rect area light source. 26936 */ 26937 constructor(light = null) { 26938 super(light); 26939 this.halfHeight = uniform(new Vector3()).setGroup(renderGroup); 26940 this.halfWidth = uniform(new Vector3()).setGroup(renderGroup); 26941 this.updateType = NodeUpdateType.RENDER; 26942 } 26943 /** 26944 * Overwritten to updated rect area light specific uniforms. 26945 * 26946 * @param {NodeFrame} frame - A reference to the current node frame. 26947 */ 26948 update(frame) { 26949 super.update(frame); 26950 const { light } = this; 26951 const viewMatrix = frame.camera.matrixWorldInverse; 26952 _matrix42.identity(); 26953 _matrix41.copy(light.matrixWorld); 26954 _matrix41.premultiply(viewMatrix); 26955 _matrix42.extractRotation(_matrix41); 26956 this.halfWidth.value.set(light.width * 0.5, 0, 0); 26957 this.halfHeight.value.set(0, light.height * 0.5, 0); 26958 this.halfWidth.value.applyMatrix4(_matrix42); 26959 this.halfHeight.value.applyMatrix4(_matrix42); 26960 } 26961 setupDirectRectArea(builder) { 26962 let ltc_1, ltc_2; 26963 if (builder.isAvailable("float32Filterable")) { 26964 ltc_1 = texture(_ltcLib.LTC_FLOAT_1); 26965 ltc_2 = texture(_ltcLib.LTC_FLOAT_2); 26966 } else { 26967 ltc_1 = texture(_ltcLib.LTC_HALF_1); 26968 ltc_2 = texture(_ltcLib.LTC_HALF_2); 26969 } 26970 const { colorNode, light } = this; 26971 const lightPosition3 = lightViewPosition(light); 26972 return { 26973 lightColor: colorNode, 26974 lightPosition: lightPosition3, 26975 halfWidth: this.halfWidth, 26976 halfHeight: this.halfHeight, 26977 ltc_1, 26978 ltc_2 26979 }; 26980 } 26981 /** 26982 * Used to configure the internal BRDF approximation texture data. 26983 * 26984 * @param {RectAreaLightTexturesLib} ltc - The BRDF approximation texture data. 26985 */ 26986 static setLTC(ltc) { 26987 _ltcLib = ltc; 26988 } 26989}; 26990var NodeParser = class { 26991 /** 26992 * The method parses the given native code an returns a node function. 26993 * 26994 * @abstract 26995 * @param {string} source - The native shader code. 26996 * @return {NodeFunction} A node function. 26997 */ 26998 parseFunction() { 26999 warn("Abstract function."); 27000 } 27001}; 27002var NodeFunction = class { 27003 /** 27004 * Constructs a new node function. 27005 * 27006 * @param {string} type - The node type. This type is the return type of the node function. 27007 * @param {Array<NodeFunctionInput>} inputs - The function's inputs. 27008 * @param {string} [name=''] - The function's name. 27009 * @param {string} [precision=''] - The precision qualifier. 27010 */ 27011 constructor(type, inputs, name = "", precision = "") { 27012 this.type = type; 27013 this.inputs = inputs; 27014 this.name = name; 27015 this.precision = precision; 27016 } 27017 /** 27018 * This method returns the native code of the node function. 27019 * 27020 * @abstract 27021 * @param {string} name - The function's name. 27022 * @return {string} A shader code. 27023 */ 27024 getCode() { 27025 warn("Abstract function."); 27026 } 27027}; 27028NodeFunction.isNodeFunction = true; 27029var declarationRegexp$1 = /^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i; 27030var propertiesRegexp$1 = /[a-z_0-9]+/ig; 27031var pragmaMain = "#pragma main"; 27032var parse$1 = (source) => { 27033 source = source.trim(); 27034 const pragmaMainIndex = source.indexOf(pragmaMain); 27035 const mainCode = pragmaMainIndex !== -1 ? source.slice(pragmaMainIndex + pragmaMain.length) : source; 27036 const declaration = mainCode.match(declarationRegexp$1); 27037 if (declaration !== null && declaration.length === 5) { 27038 const inputsCode = declaration[4]; 27039 const propsMatches = []; 27040 let nameMatch = null; 27041 while ((nameMatch = propertiesRegexp$1.exec(inputsCode)) !== null) { 27042 propsMatches.push(nameMatch); 27043 } 27044 const inputs = []; 27045 let i = 0; 27046 while (i < propsMatches.length) { 27047 const isConst = propsMatches[i][0] === "const"; 27048 if (isConst === true) { 27049 i++; 27050 } 27051 let qualifier = propsMatches[i][0]; 27052 if (qualifier === "in" || qualifier === "out" || qualifier === "inout") { 27053 i++; 27054 } else { 27055 qualifier = ""; 27056 } 27057 const type2 = propsMatches[i++][0]; 27058 let count = Number.parseInt(propsMatches[i][0]); 27059 if (Number.isNaN(count) === false) i++; 27060 else count = null; 27061 const name2 = propsMatches[i++][0]; 27062 inputs.push(new NodeFunctionInput(type2, name2, count, qualifier, isConst)); 27063 } 27064 const blockCode = mainCode.substring(declaration[0].length); 27065 const name = declaration[3] !== void 0 ? declaration[3] : ""; 27066 const type = declaration[2]; 27067 const precision = declaration[1] !== void 0 ? declaration[1] : ""; 27068 const headerCode = pragmaMainIndex !== -1 ? source.slice(0, pragmaMainIndex) : ""; 27069 return { 27070 type, 27071 inputs, 27072 name, 27073 precision, 27074 inputsCode, 27075 blockCode, 27076 headerCode 27077 }; 27078 } else { 27079 throw new Error("FunctionNode: Function is not a GLSL code."); 27080 } 27081}; 27082var GLSLNodeFunction = class extends NodeFunction { 27083 /** 27084 * Constructs a new GLSL node function. 27085 * 27086 * @param {string} source - The GLSL source. 27087 */ 27088 constructor(source) { 27089 const { type, inputs, name, precision, inputsCode, blockCode, headerCode } = parse$1(source); 27090 super(type, inputs, name, precision); 27091 this.inputsCode = inputsCode; 27092 this.blockCode = blockCode; 27093 this.headerCode = headerCode; 27094 } 27095 /** 27096 * This method returns the GLSL code of the node function. 27097 * 27098 * @param {string} [name=this.name] - The function's name. 27099 * @return {string} The shader code. 27100 */ 27101 getCode(name = this.name) { 27102 let code3; 27103 const blockCode = this.blockCode; 27104 if (blockCode !== "") { 27105 const { type, inputsCode, headerCode, precision } = this; 27106 let declarationCode = `${type} ${name} ( ${inputsCode.trim()} )`; 27107 if (precision !== "") { 27108 declarationCode = `${precision} ${declarationCode}`; 27109 } 27110 code3 = headerCode + declarationCode + blockCode; 27111 } else { 27112 code3 = ""; 27113 } 27114 return code3; 27115 } 27116}; 27117var GLSLNodeParser = class extends NodeParser { 27118 /** 27119 * The method parses the given GLSL code an returns a node function. 27120 * 27121 * @param {string} source - The GLSL code. 27122 * @return {GLSLNodeFunction} A node function. 27123 */ 27124 parseFunction(source) { 27125 return new GLSLNodeFunction(source); 27126 } 27127}; 27128var _chainKeys$1 = []; 27129var _cacheKeyValues = []; 27130var NodeManager = class extends DataMap { 27131 /** 27132 * Constructs a new nodes management component. 27133 * 27134 * @param {Renderer} renderer - The renderer. 27135 * @param {Backend} backend - The renderer's backend. 27136 */ 27137 constructor(renderer, backend) { 27138 super(); 27139 this.renderer = renderer; 27140 this.backend = backend; 27141 this.nodeFrame = new NodeFrame(); 27142 this.nodeBuilderCache = /* @__PURE__ */ new Map(); 27143 this.callHashCache = new ChainMap(); 27144 this.groupsData = new ChainMap(); 27145 this._buildQueue = []; 27146 this._buildInProgress = false; 27147 this.cacheLib = {}; 27148 } 27149 /** 27150 * Returns `true` if the given node uniforms group must be updated or not. 27151 * 27152 * @param {NodeUniformsGroup} nodeUniformsGroup - The node uniforms group. 27153 * @return {boolean} Whether the node uniforms group requires an update or not. 27154 */ 27155 updateGroup(nodeUniformsGroup) { 27156 const groupNode = nodeUniformsGroup.groupNode; 27157 _chainKeys$1[0] = groupNode; 27158 _chainKeys$1[1] = nodeUniformsGroup; 27159 let groupData = this.groupsData.get(_chainKeys$1); 27160 if (groupData === void 0) this.groupsData.set(_chainKeys$1, groupData = {}); 27161 _chainKeys$1[0] = null; 27162 _chainKeys$1[1] = null; 27163 if (groupData.version !== groupNode.version) { 27164 groupData.version = groupNode.version; 27165 return true; 27166 } 27167 return false; 27168 } 27169 /** 27170 * Returns the cache key for the given render object. 27171 * 27172 * @param {RenderObject} renderObject - The render object. 27173 * @return {number} The cache key. 27174 */ 27175 getForRenderCacheKey(renderObject) { 27176 return renderObject.initialCacheKey; 27177 } 27178 /** 27179 * Creates a node builder configured for the given render object and material. 27180 * 27181 * @private 27182 * @param {RenderObject} renderObject - The render object. 27183 * @param {Material} material - The material to use. 27184 * @return {NodeBuilder} The configured node builder. 27185 */ 27186 _createNodeBuilder(renderObject, material) { 27187 const nodeBuilder = this.backend.createNodeBuilder(renderObject.object, this.renderer); 27188 nodeBuilder.scene = renderObject.scene; 27189 nodeBuilder.material = material; 27190 nodeBuilder.camera = renderObject.camera; 27191 nodeBuilder.context.material = material; 27192 nodeBuilder.lightsNode = renderObject.lightsNode; 27193 nodeBuilder.environmentNode = this.getEnvironmentNode(renderObject.scene); 27194 nodeBuilder.fogNode = this.getFogNode(renderObject.scene); 27195 nodeBuilder.clippingContext = renderObject.clippingContext; 27196 if (this.renderer.getOutputRenderTarget() ? this.renderer.getOutputRenderTarget().multiview : false) { 27197 nodeBuilder.enableMultiview(); 27198 } 27199 return nodeBuilder; 27200 } 27201 /** 27202 * Returns a node builder state for the given render object. 27203 * 27204 * @param {RenderObject} renderObject - The render object. 27205 * @param {boolean} [useAsync=false] - Whether to use async build with yielding. 27206 * @return {NodeBuilderState|Promise<NodeBuilderState>} The node builder state (or Promise if async). 27207 */ 27208 getForRender(renderObject, useAsync = false) { 27209 const renderObjectData = this.get(renderObject); 27210 let nodeBuilderState = renderObjectData.nodeBuilderState; 27211 if (nodeBuilderState === void 0) { 27212 const { nodeBuilderCache } = this; 27213 const cacheKey = this.getForRenderCacheKey(renderObject); 27214 nodeBuilderState = nodeBuilderCache.get(cacheKey); 27215 if (nodeBuilderState === void 0) { 27216 const buildNodeBuilder = async () => { 27217 let nodeBuilder = this._createNodeBuilder(renderObject, renderObject.material); 27218 try { 27219 if (useAsync) { 27220 await nodeBuilder.buildAsync(); 27221 } else { 27222 nodeBuilder.build(); 27223 } 27224 } catch (e) { 27225 nodeBuilder = this._createNodeBuilder(renderObject, new NodeMaterial()); 27226 if (useAsync) { 27227 await nodeBuilder.buildAsync(); 27228 } else { 27229 nodeBuilder.build(); 27230 } 27231 error("TSL: " + e); 27232 } 27233 return nodeBuilder; 27234 }; 27235 if (useAsync) { 27236 return buildNodeBuilder().then((nodeBuilder) => { 27237 nodeBuilderState = this._createNodeBuilderState(nodeBuilder); 27238 nodeBuilderCache.set(cacheKey, nodeBuilderState); 27239 nodeBuilderState.usedTimes++; 27240 renderObjectData.nodeBuilderState = nodeBuilderState; 27241 return nodeBuilderState; 27242 }); 27243 } else { 27244 let nodeBuilder = this._createNodeBuilder(renderObject, renderObject.material); 27245 try { 27246 nodeBuilder.build(); 27247 } catch (e) { 27248 nodeBuilder = this._createNodeBuilder(renderObject, new NodeMaterial()); 27249 nodeBuilder.build(); 27250 let stackTrace = e.stackTrace; 27251 if (!stackTrace && e.stack) { 27252 stackTrace = new StackTrace(e.stack); 27253 } 27254 error("TSL: " + e, stackTrace); 27255 } 27256 nodeBuilderState = this._createNodeBuilderState(nodeBuilder); 27257 nodeBuilderCache.set(cacheKey, nodeBuilderState); 27258 } 27259 } 27260 nodeBuilderState.usedTimes++; 27261 renderObjectData.nodeBuilderState = nodeBuilderState; 27262 } 27263 return nodeBuilderState; 27264 } 27265 /** 27266 * Async version of getForRender() that yields to main thread during build. 27267 * Use this in compileAsync() to prevent blocking the main thread. 27268 * 27269 * @param {RenderObject} renderObject - The render object. 27270 * @return {Promise<NodeBuilderState>} A promise that resolves to the node builder state. 27271 */ 27272 getForRenderAsync(renderObject) { 27273 const result = this.getForRender(renderObject, true); 27274 if (result.then) { 27275 return result; 27276 } 27277 return Promise.resolve(result); 27278 } 27279 /** 27280 * Returns nodeBuilderState if ready, null if pending async build. 27281 * Queues async build on first call for cache miss. 27282 * Use this in render() path to enable non-blocking compilation. 27283 * 27284 * @param {RenderObject} renderObject - The render object. 27285 * @return {?NodeBuilderState} The node builder state, or null if still building. 27286 */ 27287 getForRenderDeferred(renderObject) { 27288 const renderObjectData = this.get(renderObject); 27289 if (renderObjectData.nodeBuilderState !== void 0) { 27290 return renderObjectData.nodeBuilderState; 27291 } 27292 const cacheKey = this.getForRenderCacheKey(renderObject); 27293 const nodeBuilderState = this.nodeBuilderCache.get(cacheKey); 27294 if (nodeBuilderState !== void 0) { 27295 nodeBuilderState.usedTimes++; 27296 renderObjectData.nodeBuilderState = nodeBuilderState; 27297 return nodeBuilderState; 27298 } 27299 if (renderObjectData.pendingBuild !== true) { 27300 renderObjectData.pendingBuild = true; 27301 this._buildQueue.push(() => { 27302 return this.getForRenderAsync(renderObject).then(() => { 27303 renderObjectData.pendingBuild = false; 27304 }); 27305 }); 27306 this._processBuildQueue(); 27307 } 27308 return null; 27309 } 27310 /** 27311 * Processes the build queue one item at a time. 27312 * This ensures builds don't all run simultaneously and freeze the main thread. 27313 * 27314 * @private 27315 */ 27316 _processBuildQueue() { 27317 if (this._buildInProgress || this._buildQueue.length === 0) { 27318 return; 27319 } 27320 this._buildInProgress = true; 27321 const buildFn = this._buildQueue.shift(); 27322 buildFn().then(() => { 27323 this._buildInProgress = false; 27324 this._processBuildQueue(); 27325 }); 27326 } 27327 /** 27328 * Deletes the given object from the internal data map 27329 * 27330 * @param {any} object - The object to delete. 27331 * @return {?Object} The deleted dictionary. 27332 */ 27333 delete(object) { 27334 if (object.isRenderObject) { 27335 const nodeBuilderState = this.get(object).nodeBuilderState; 27336 if (nodeBuilderState !== void 0) { 27337 nodeBuilderState.usedTimes--; 27338 if (nodeBuilderState.usedTimes === 0) { 27339 this.nodeBuilderCache.delete(this.getForRenderCacheKey(object)); 27340 } 27341 } 27342 } 27343 return super.delete(object); 27344 } 27345 /** 27346 * Returns a node builder state for the given compute node. 27347 * 27348 * @param {Node} computeNode - The compute node. 27349 * @return {NodeBuilderState} The node builder state. 27350 */ 27351 getForCompute(computeNode) { 27352 const computeData = this.get(computeNode); 27353 let nodeBuilderState = computeData.nodeBuilderState; 27354 if (nodeBuilderState === void 0) { 27355 const nodeBuilder = this.backend.createNodeBuilder(computeNode, this.renderer); 27356 nodeBuilder.build(); 27357 nodeBuilderState = this._createNodeBuilderState(nodeBuilder); 27358 computeData.nodeBuilderState = nodeBuilderState; 27359 } 27360 return nodeBuilderState; 27361 } 27362 /** 27363 * Creates a node builder state for the given node builder. 27364 * 27365 * @private 27366 * @param {NodeBuilder} nodeBuilder - The node builder. 27367 * @return {NodeBuilderState} The node builder state. 27368 */ 27369 _createNodeBuilderState(nodeBuilder) { 27370 return new NodeBuilderState( 27371 nodeBuilder.vertexShader, 27372 nodeBuilder.fragmentShader, 27373 nodeBuilder.computeShader, 27374 nodeBuilder.getAttributesArray(), 27375 nodeBuilder.getBindings(), 27376 nodeBuilder.updateNodes, 27377 nodeBuilder.updateBeforeNodes, 27378 nodeBuilder.updateAfterNodes, 27379 nodeBuilder.observer, 27380 nodeBuilder.transforms 27381 ); 27382 } 27383 /** 27384 * Returns an environment node for the current configured 27385 * scene environment. 27386 * 27387 * @param {Scene} scene - The scene. 27388 * @return {Node} A node representing the current scene environment. 27389 */ 27390 getEnvironmentNode(scene) { 27391 this.updateEnvironment(scene); 27392 let environmentNode = null; 27393 if (scene.environmentNode && scene.environmentNode.isNode) { 27394 environmentNode = scene.environmentNode; 27395 } else { 27396 const sceneData = this.get(scene); 27397 if (sceneData.environmentNode) { 27398 environmentNode = sceneData.environmentNode; 27399 } 27400 } 27401 return environmentNode; 27402 } 27403 /** 27404 * Returns a background node for the current configured 27405 * scene background. 27406 * 27407 * @param {Scene} scene - The scene. 27408 * @return {Node} A node representing the current scene background. 27409 */ 27410 getBackgroundNode(scene) { 27411 this.updateBackground(scene); 27412 let backgroundNode = null; 27413 if (scene.backgroundNode && scene.backgroundNode.isNode) { 27414 backgroundNode = scene.backgroundNode; 27415 } else { 27416 const sceneData = this.get(scene); 27417 if (sceneData.backgroundNode) { 27418 backgroundNode = sceneData.backgroundNode; 27419 } 27420 } 27421 return backgroundNode; 27422 } 27423 /** 27424 * Returns a fog node for the current configured scene fog. 27425 * 27426 * @param {Scene} scene - The scene. 27427 * @return {Node} A node representing the current scene fog. 27428 */ 27429 getFogNode(scene) { 27430 this.updateFog(scene); 27431 return scene.fogNode || this.get(scene).fogNode || null; 27432 } 27433 /** 27434 * Returns a cache key for the given scene and lights node. 27435 * This key is used by `RenderObject` as a part of the dynamic 27436 * cache key (a key that must be checked every time the render 27437 * objects is drawn). 27438 * 27439 * @param {Scene} scene - The scene. 27440 * @param {LightsNode} lightsNode - The lights node. 27441 * @return {number} The cache key. 27442 */ 27443 getCacheKey(scene, lightsNode) { 27444 _chainKeys$1[0] = scene; 27445 _chainKeys$1[1] = lightsNode; 27446 const callId = this.renderer.info.calls; 27447 const cacheKeyData = this.callHashCache.get(_chainKeys$1) || {}; 27448 if (cacheKeyData.callId !== callId) { 27449 const environmentNode = this.getEnvironmentNode(scene); 27450 const fogNode = this.getFogNode(scene); 27451 if (lightsNode) _cacheKeyValues.push(lightsNode.getCacheKey(true)); 27452 if (environmentNode) _cacheKeyValues.push(environmentNode.getCacheKey()); 27453 if (fogNode) _cacheKeyValues.push(fogNode.getCacheKey()); 27454 _cacheKeyValues.push(this.renderer.getOutputRenderTarget() && this.renderer.getOutputRenderTarget().multiview ? 1 : 0); 27455 _cacheKeyValues.push(this.renderer.shadowMap.enabled ? 1 : 0); 27456 _cacheKeyValues.push(this.renderer.shadowMap.type); 27457 cacheKeyData.callId = callId; 27458 cacheKeyData.cacheKey = hashArray(_cacheKeyValues); 27459 this.callHashCache.set(_chainKeys$1, cacheKeyData); 27460 _cacheKeyValues.length = 0; 27461 } 27462 _chainKeys$1[0] = null; 27463 _chainKeys$1[1] = null; 27464 return cacheKeyData.cacheKey; 27465 } 27466 /** 27467 * A boolean that indicates whether tone mapping should be enabled 27468 * or not. 27469 * 27470 * @type {boolean} 27471 */ 27472 get isToneMappingState() { 27473 return this.renderer.getRenderTarget() ? false : true; 27474 } 27475 /** 27476 * If a scene background is configured, this method makes sure to 27477 * represent the background with a corresponding node-based implementation. 27478 * 27479 * @param {Scene} scene - The scene. 27480 */ 27481 updateBackground(scene) { 27482 const sceneData = this.get(scene); 27483 const background = scene.background; 27484 if (background) { 27485 const forceUpdate = scene.backgroundBlurriness === 0 && sceneData.backgroundBlurriness > 0 || scene.backgroundBlurriness > 0 && sceneData.backgroundBlurriness === 0; 27486 if (sceneData.background !== background || forceUpdate) { 27487 const backgroundNode = this.getCacheNode("background", background, () => { 27488 if (background.isCubeTexture === true || (background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping)) { 27489 if (scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping) { 27490 return pmremTexture(background); 27491 } else { 27492 let envMap; 27493 if (background.isCubeTexture === true) { 27494 envMap = cubeTexture(background); 27495 } else { 27496 envMap = texture(background); 27497 } 27498 return cubeMapNode(envMap); 27499 } 27500 } else if (background.isTexture === true) { 27501 return texture(background, screenUV.flipY()).setUpdateMatrix(true); 27502 } else if (background.isColor !== true) { 27503 error("WebGPUNodes: Unsupported background configuration.", background); 27504 } 27505 }, forceUpdate); 27506 sceneData.backgroundNode = backgroundNode; 27507 sceneData.background = background; 27508 sceneData.backgroundBlurriness = scene.backgroundBlurriness; 27509 } 27510 } else if (sceneData.backgroundNode) { 27511 delete sceneData.backgroundNode; 27512 delete sceneData.background; 27513 } 27514 } 27515 /** 27516 * This method is part of the caching of nodes which are used to represents the 27517 * scene's background, fog or environment. 27518 * 27519 * @param {string} type - The type of object to cache. 27520 * @param {Object} object - The object. 27521 * @param {Function} callback - A callback that produces a node representation for the given object. 27522 * @param {boolean} [forceUpdate=false] - Whether an update should be enforced or not. 27523 * @return {Node} The node representation. 27524 */ 27525 getCacheNode(type, object, callback, forceUpdate = false) { 27526 const nodeCache = this.cacheLib[type] || (this.cacheLib[type] = /* @__PURE__ */ new WeakMap()); 27527 let node = nodeCache.get(object); 27528 if (node === void 0 || forceUpdate) { 27529 node = callback(); 27530 nodeCache.set(object, node); 27531 } 27532 return node; 27533 } 27534 /** 27535 * If a scene fog is configured, this method makes sure to 27536 * represent the fog with a corresponding node-based implementation. 27537 * 27538 * @param {Scene} scene - The scene. 27539 */ 27540 updateFog(scene) { 27541 const sceneData = this.get(scene); 27542 const sceneFog = scene.fog; 27543 if (sceneFog) { 27544 if (sceneData.fog !== sceneFog) { 27545 const fogNode = this.getCacheNode("fog", sceneFog, () => { 27546 if (sceneFog.isFogExp2) { 27547 const color3 = reference("color", "color", sceneFog).setGroup(renderGroup); 27548 const density = reference("density", "float", sceneFog).setGroup(renderGroup); 27549 return fog(color3, densityFogFactor(density)); 27550 } else if (sceneFog.isFog) { 27551 const color3 = reference("color", "color", sceneFog).setGroup(renderGroup); 27552 const near = reference("near", "float", sceneFog).setGroup(renderGroup); 27553 const far = reference("far", "float", sceneFog).setGroup(renderGroup); 27554 return fog(color3, rangeFogFactor(near, far)); 27555 } else { 27556 error("Renderer: Unsupported fog configuration.", sceneFog); 27557 } 27558 }); 27559 sceneData.fogNode = fogNode; 27560 sceneData.fog = sceneFog; 27561 } 27562 } else { 27563 delete sceneData.fogNode; 27564 delete sceneData.fog; 27565 } 27566 } 27567 /** 27568 * If a scene environment is configured, this method makes sure to 27569 * represent the environment with a corresponding node-based implementation. 27570 * 27571 * @param {Scene} scene - The scene. 27572 */ 27573 updateEnvironment(scene) { 27574 const sceneData = this.get(scene); 27575 const environment = scene.environment; 27576 if (environment) { 27577 if (sceneData.environment !== environment) { 27578 const environmentNode = this.getCacheNode("environment", environment, () => { 27579 if (environment.isCubeTexture === true) { 27580 return cubeTexture(environment); 27581 } else if (environment.isTexture === true) { 27582 return texture(environment); 27583 } else { 27584 error("Nodes: Unsupported environment configuration.", environment); 27585 } 27586 }); 27587 sceneData.environmentNode = environmentNode; 27588 sceneData.environment = environment; 27589 } 27590 } else if (sceneData.environmentNode) { 27591 delete sceneData.environmentNode; 27592 delete sceneData.environment; 27593 } 27594 } 27595 getNodeFrame(renderer = this.renderer, scene = null, object = null, camera = null, material = null) { 27596 const nodeFrame = this.nodeFrame; 27597 nodeFrame.renderer = renderer; 27598 nodeFrame.scene = scene; 27599 nodeFrame.object = object; 27600 nodeFrame.camera = camera; 27601 nodeFrame.material = material; 27602 return nodeFrame; 27603 } 27604 getNodeFrameForRender(renderObject) { 27605 return this.getNodeFrame(renderObject.renderer, renderObject.scene, renderObject.object, renderObject.camera, renderObject.material); 27606 } 27607 /** 27608 * Returns the current output cache key. 27609 * 27610 * @return {string} The output cache key. 27611 */ 27612 getOutputCacheKey() { 27613 const renderer = this.renderer; 27614 return renderer.toneMapping + "," + renderer.currentColorSpace + "," + renderer.xr.isPresenting; 27615 } 27616 /** 27617 * Returns a node that represents the output configuration (tone mapping and 27618 * color space) for the current target. 27619 * 27620 * @param {Texture} outputTarget - The output target. 27621 * @return {Node} The output node. 27622 */ 27623 getOutputNode(outputTarget) { 27624 const renderer = this.renderer; 27625 const output3 = outputTarget.isArrayTexture ? texture(outputTarget, screenUV).depth(builtin("gl_ViewID_OVR")).renderOutput(renderer.toneMapping, renderer.currentColorSpace) : texture(outputTarget, screenUV).renderOutput(renderer.toneMapping, renderer.currentColorSpace); 27626 return output3; 27627 } 27628 /** 27629 * Triggers the call of `updateBefore()` methods 27630 * for all nodes of the given render object. 27631 * 27632 * @param {RenderObject} renderObject - The render object. 27633 */ 27634 updateBefore(renderObject) { 27635 const nodeBuilder = renderObject.getNodeBuilderState(); 27636 for (const node of nodeBuilder.updateBeforeNodes) { 27637 this.getNodeFrameForRender(renderObject).updateBeforeNode(node); 27638 } 27639 } 27640 /** 27641 * Triggers the call of `updateAfter()` methods 27642 * for all nodes of the given render object. 27643 * 27644 * @param {RenderObject} renderObject - The render object. 27645 */ 27646 updateAfter(renderObject) { 27647 const nodeBuilder = renderObject.getNodeBuilderState(); 27648 for (const node of nodeBuilder.updateAfterNodes) { 27649 this.getNodeFrameForRender(renderObject).updateAfterNode(node); 27650 } 27651 } 27652 /** 27653 * Triggers the call of `update()` methods 27654 * for all nodes of the given compute node. 27655 * 27656 * @param {Node} computeNode - The compute node. 27657 */ 27658 updateForCompute(computeNode) { 27659 const nodeFrame = this.getNodeFrame(); 27660 const nodeBuilder = this.getForCompute(computeNode); 27661 for (const node of nodeBuilder.updateNodes) { 27662 nodeFrame.updateNode(node); 27663 } 27664 } 27665 /** 27666 * Triggers the call of `update()` methods 27667 * for all nodes of the given render object. 27668 * 27669 * @param {RenderObject} renderObject - The render object. 27670 */ 27671 updateForRender(renderObject) { 27672 const nodeFrame = this.getNodeFrameForRender(renderObject); 27673 const nodeBuilder = renderObject.getNodeBuilderState(); 27674 for (const node of nodeBuilder.updateNodes) { 27675 nodeFrame.updateNode(node); 27676 } 27677 } 27678 /** 27679 * Returns `true` if the given render object requires a refresh. 27680 * 27681 * @param {RenderObject} renderObject - The render object. 27682 * @return {boolean} Whether the given render object requires a refresh or not. 27683 */ 27684 needsRefresh(renderObject) { 27685 const nodeFrame = this.getNodeFrameForRender(renderObject); 27686 const monitor = renderObject.getMonitor(); 27687 return monitor.needsRefresh(renderObject, nodeFrame); 27688 } 27689 /** 27690 * Frees the internal resources. 27691 */ 27692 dispose() { 27693 super.dispose(); 27694 this.nodeFrame = new NodeFrame(); 27695 this.nodeBuilderCache = /* @__PURE__ */ new Map(); 27696 this.cacheLib = {}; 27697 } 27698}; 27699var _plane = /* @__PURE__ */ new Plane(); 27700var ClippingContext = class _ClippingContext { 27701 /** 27702 * Constructs a new clipping context. 27703 * 27704 * @param {?ClippingContext} [parentContext=null] - A reference to the parent clipping context. 27705 */ 27706 constructor(parentContext = null) { 27707 this.version = 0; 27708 this.clipIntersection = null; 27709 this.cacheKey = ""; 27710 this.shadowPass = false; 27711 this.viewNormalMatrix = new Matrix3(); 27712 this.clippingGroupContexts = /* @__PURE__ */ new WeakMap(); 27713 this.intersectionPlanes = []; 27714 this.unionPlanes = []; 27715 this.parentVersion = null; 27716 if (parentContext !== null) { 27717 this.viewNormalMatrix = parentContext.viewNormalMatrix; 27718 this.clippingGroupContexts = parentContext.clippingGroupContexts; 27719 this.shadowPass = parentContext.shadowPass; 27720 this.viewMatrix = parentContext.viewMatrix; 27721 } 27722 } 27723 /** 27724 * Projects the given source clipping planes and writes the result into the 27725 * destination array. 27726 * 27727 * @param {Array<Plane>} source - The source clipping planes. 27728 * @param {Array<Vector4>} destination - The destination. 27729 * @param {number} offset - The offset. 27730 */ 27731 projectPlanes(source, destination, offset3) { 27732 const l = source.length; 27733 for (let i = 0; i < l; i++) { 27734 _plane.copy(source[i]).applyMatrix4(this.viewMatrix, this.viewNormalMatrix); 27735 const v = destination[offset3 + i]; 27736 const normal2 = _plane.normal; 27737 v.x = -normal2.x; 27738 v.y = -normal2.y; 27739 v.z = -normal2.z; 27740 v.w = _plane.constant; 27741 } 27742 } 27743 /** 27744 * Updates the root clipping context of a scene. 27745 * 27746 * @param {Scene} scene - The scene. 27747 * @param {Camera} camera - The camera that is used to render the scene. 27748 */ 27749 updateGlobal(scene, camera) { 27750 this.shadowPass = scene.overrideMaterial !== null && scene.overrideMaterial.isShadowPassMaterial; 27751 this.viewMatrix = camera.matrixWorldInverse; 27752 this.viewNormalMatrix.getNormalMatrix(this.viewMatrix); 27753 } 27754 /** 27755 * Updates the clipping context. 27756 * 27757 * @param {ClippingContext} parentContext - The parent context. 27758 * @param {ClippingGroup} clippingGroup - The clipping group this context belongs to. 27759 */ 27760 update(parentContext, clippingGroup) { 27761 let update = false; 27762 if (parentContext.version !== this.parentVersion) { 27763 this.intersectionPlanes = Array.from(parentContext.intersectionPlanes); 27764 this.unionPlanes = Array.from(parentContext.unionPlanes); 27765 this.parentVersion = parentContext.version; 27766 } 27767 if (this.clipIntersection !== clippingGroup.clipIntersection) { 27768 this.clipIntersection = clippingGroup.clipIntersection; 27769 if (this.clipIntersection) { 27770 this.unionPlanes.length = parentContext.unionPlanes.length; 27771 } else { 27772 this.intersectionPlanes.length = parentContext.intersectionPlanes.length; 27773 } 27774 } 27775 const srcClippingPlanes = clippingGroup.clippingPlanes; 27776 const l = srcClippingPlanes.length; 27777 let dstClippingPlanes; 27778 let offset3; 27779 if (this.clipIntersection) { 27780 dstClippingPlanes = this.intersectionPlanes; 27781 offset3 = parentContext.intersectionPlanes.length; 27782 } else { 27783 dstClippingPlanes = this.unionPlanes; 27784 offset3 = parentContext.unionPlanes.length; 27785 } 27786 if (dstClippingPlanes.length !== offset3 + l) { 27787 dstClippingPlanes.length = offset3 + l; 27788 for (let i = 0; i < l; i++) { 27789 dstClippingPlanes[offset3 + i] = new Vector4(); 27790 } 27791 update = true; 27792 } 27793 this.projectPlanes(srcClippingPlanes, dstClippingPlanes, offset3); 27794 if (update) { 27795 this.version++; 27796 this.cacheKey = `${this.intersectionPlanes.length}:${this.unionPlanes.length}`; 27797 } 27798 } 27799 /** 27800 * Returns a clipping context for the given clipping group. 27801 * 27802 * @param {ClippingGroup} clippingGroup - The clipping group. 27803 * @return {ClippingContext} The clipping context. 27804 */ 27805 getGroupContext(clippingGroup) { 27806 if (this.shadowPass && !clippingGroup.clipShadows) return this; 27807 let context3 = this.clippingGroupContexts.get(clippingGroup); 27808 if (context3 === void 0) { 27809 context3 = new _ClippingContext(this); 27810 this.clippingGroupContexts.set(clippingGroup, context3); 27811 } 27812 context3.update(this, clippingGroup); 27813 return context3; 27814 } 27815 /** 27816 * The count of union clipping planes. 27817 * 27818 * @type {number} 27819 * @readonly 27820 */ 27821 get unionClippingCount() { 27822 return this.unionPlanes.length; 27823 } 27824}; 27825var RenderBundle = class { 27826 /** 27827 * Constructs a new bundle group. 27828 * 27829 * @param {BundleGroup} bundleGroup - The bundle group. 27830 * @param {Camera} camera - The camera the bundle group is rendered with. 27831 * @param {RenderContext} renderContext - The render context the bundle is rendered with. 27832 */ 27833 constructor(bundleGroup, camera, renderContext) { 27834 this.bundleGroup = bundleGroup; 27835 this.camera = camera; 27836 this.renderContext = renderContext; 27837 } 27838}; 27839var _chainKeys = []; 27840var RenderBundles = class { 27841 /** 27842 * Constructs a new render bundle management component. 27843 */ 27844 constructor() { 27845 this.bundles = new ChainMap(); 27846 } 27847 /** 27848 * Returns a render bundle for the given bundle group and camera. 27849 * 27850 * @param {BundleGroup} bundleGroup - The bundle group. 27851 * @param {Camera} camera - The camera the bundle group is rendered with. 27852 * @param {RenderContext} renderContext - The render context the bundle is rendered with. 27853 * @return {RenderBundle} The render bundle. 27854 */ 27855 get(bundleGroup, camera, renderContext) { 27856 const bundles = this.bundles; 27857 _chainKeys[0] = bundleGroup; 27858 _chainKeys[1] = camera; 27859 _chainKeys[2] = renderContext; 27860 let bundle = bundles.get(_chainKeys); 27861 if (bundle === void 0) { 27862 bundle = new RenderBundle(bundleGroup, camera, renderContext); 27863 bundles.set(_chainKeys, bundle); 27864 } 27865 _chainKeys[0] = null; 27866 _chainKeys[1] = null; 27867 _chainKeys[2] = null; 27868 return bundle; 27869 } 27870 /** 27871 * Frees all internal resources. 27872 */ 27873 dispose() { 27874 this.bundles = new ChainMap(); 27875 } 27876}; 27877var NodeLibrary = class { 27878 /** 27879 * Constructs a new node library. 27880 */ 27881 constructor() { 27882 this.lightNodes = /* @__PURE__ */ new WeakMap(); 27883 this.materialNodes = /* @__PURE__ */ new Map(); 27884 this.toneMappingNodes = /* @__PURE__ */ new Map(); 27885 } 27886 /** 27887 * Returns a matching node material instance for the given material object. 27888 * 27889 * This method also assigns/copies the properties of the given material object 27890 * to the node material. This is done to make sure the current material 27891 * configuration carries over to the node version. 27892 * 27893 * @param {Material} material - A material. 27894 * @return {NodeMaterial} The corresponding node material. 27895 */ 27896 fromMaterial(material) { 27897 if (material.isNodeMaterial) return material; 27898 let nodeMaterial = null; 27899 const nodeMaterialClass = this.getMaterialNodeClass(material.type); 27900 if (nodeMaterialClass !== null) { 27901 nodeMaterial = new nodeMaterialClass(); 27902 for (const key in material) { 27903 nodeMaterial[key] = material[key]; 27904 } 27905 } 27906 return nodeMaterial; 27907 } 27908 /** 27909 * Adds a tone mapping node function for a tone mapping technique (constant). 27910 * 27911 * @param {Function} toneMappingNode - The tone mapping node function. 27912 * @param {number} toneMapping - The tone mapping. 27913 */ 27914 addToneMapping(toneMappingNode, toneMapping3) { 27915 this.addType(toneMappingNode, toneMapping3, this.toneMappingNodes); 27916 } 27917 /** 27918 * Returns a tone mapping node function for a tone mapping technique (constant). 27919 * 27920 * @param {number} toneMapping - The tone mapping. 27921 * @return {?Function} The tone mapping node function. Returns `null` if no node function is found. 27922 */ 27923 getToneMappingFunction(toneMapping3) { 27924 return this.toneMappingNodes.get(toneMapping3) || null; 27925 } 27926 /** 27927 * Returns a node material class definition for a material type. 27928 * 27929 * @param {string} materialType - The material type. 27930 * @return {?NodeMaterial.constructor} The node material class definition. Returns `null` if no node material is found. 27931 */ 27932 getMaterialNodeClass(materialType) { 27933 return this.materialNodes.get(materialType) || null; 27934 } 27935 /** 27936 * Adds a node material class definition for a given material type. 27937 * 27938 * @param {NodeMaterial.constructor} materialNodeClass - The node material class definition. 27939 * @param {string} materialClassType - The material type. 27940 */ 27941 addMaterial(materialNodeClass, materialClassType) { 27942 this.addType(materialNodeClass, materialClassType, this.materialNodes); 27943 } 27944 /** 27945 * Returns a light node class definition for a light class definition. 27946 * 27947 * @param {Light.constructor} light - The light class definition. 27948 * @return {?AnalyticLightNode.constructor} The light node class definition. Returns `null` if no light node is found. 27949 */ 27950 getLightNodeClass(light) { 27951 return this.lightNodes.get(light) || null; 27952 } 27953 /** 27954 * Adds a light node class definition for a given light class definition. 27955 * 27956 * @param {AnalyticLightNode.constructor} lightNodeClass - The light node class definition. 27957 * @param {Light.constructor} lightClass - The light class definition. 27958 */ 27959 addLight(lightNodeClass, lightClass) { 27960 this.addClass(lightNodeClass, lightClass, this.lightNodes); 27961 } 27962 /** 27963 * Adds a node class definition for the given type to the provided type library. 27964 * 27965 * @param {Node.constructor} nodeClass - The node class definition. 27966 * @param {number|string} type - The object type. 27967 * @param {Map<number|string,Node.constructor>} library - The type library. 27968 */ 27969 addType(nodeClass, type, library) { 27970 if (library.has(type)) { 27971 warn(`Redefinition of node ${type}`); 27972 return; 27973 } 27974 if (typeof nodeClass !== "function") throw new Error(`Node class ${nodeClass.name} is not a class.`); 27975 if (typeof type === "function" || typeof type === "object") throw new Error(`Base class ${type} is not a class.`); 27976 library.set(type, nodeClass); 27977 } 27978 /** 27979 * Adds a node class definition for the given class definition to the provided type library. 27980 * 27981 * @param {Node.constructor} nodeClass - The node class definition. 27982 * @param {Node.constructor} baseClass - The class definition. 27983 * @param {WeakMap<Node.constructor, Node.constructor>} library - The type library. 27984 */ 27985 addClass(nodeClass, baseClass, library) { 27986 if (library.has(baseClass)) { 27987 warn(`Redefinition of node ${baseClass.name}`); 27988 return; 27989 } 27990 if (typeof nodeClass !== "function") throw new Error(`Node class ${nodeClass.name} is not a class.`); 27991 if (typeof baseClass !== "function") throw new Error(`Base class ${baseClass.name} is not a class.`); 27992 library.set(baseClass, nodeClass); 27993 } 27994}; 27995var _defaultLights = /* @__PURE__ */ new LightsNode(); 27996var _weakMap = /* @__PURE__ */ new WeakMap(); 27997var Lighting = class { 27998 /** 27999 * Creates a new lights node for the given array of lights. 28000 * 28001 * @param {Array<Light>} lights - The render object. 28002 * @return {LightsNode} The lights node. 28003 */ 28004 createNode(lights3 = []) { 28005 return new LightsNode().setLights(lights3); 28006 } 28007 /** 28008 * Returns a lights node for the given scene and camera. 28009 * 28010 * @param {Scene} scene - The scene. 28011 * @param {Camera} camera - The camera. 28012 * @return {LightsNode} The lights node. 28013 */ 28014 getNode(scene) { 28015 if (scene.isQuadMesh) return _defaultLights; 28016 let node = _weakMap.get(scene); 28017 if (node === void 0) { 28018 node = this.createNode(); 28019 _weakMap.set(scene, node); 28020 } 28021 return node; 28022 } 28023}; 28024var XRRenderTarget = class extends RenderTarget { 28025 /** 28026 * Constructs a new XR render target. 28027 * 28028 * @param {number} [width=1] - The width of the render target. 28029 * @param {number} [height=1] - The height of the render target. 28030 * @param {Object} [options={}] - The configuration options. 28031 */ 28032 constructor(width = 1, height = 1, options = {}) { 28033 super(width, height, options); 28034 this.isXRRenderTarget = true; 28035 this._hasExternalTextures = false; 28036 this._autoAllocateDepthBuffer = true; 28037 this._isOpaqueFramebuffer = false; 28038 } 28039 copy(source) { 28040 super.copy(source); 28041 this._hasExternalTextures = source._hasExternalTextures; 28042 this._autoAllocateDepthBuffer = source._autoAllocateDepthBuffer; 28043 this._isOpaqueFramebuffer = source._isOpaqueFramebuffer; 28044 return this; 28045 } 28046}; 28047var _cameraLPos = /* @__PURE__ */ new Vector3(); 28048var _cameraRPos = /* @__PURE__ */ new Vector3(); 28049var _contextNodeLib = /* @__PURE__ */ new WeakMap(); 28050var XRManager = class extends EventDispatcher { 28051 /** 28052 * Constructs a new XR manager. 28053 * 28054 * @param {Renderer} renderer - The renderer. 28055 * @param {boolean} [multiview=false] - Enables multiview if the device supports it. 28056 */ 28057 constructor(renderer, multiview = false) { 28058 super(); 28059 this.enabled = false; 28060 this.isPresenting = false; 28061 this.cameraAutoUpdate = true; 28062 this._renderer = renderer; 28063 this._cameraL = new PerspectiveCamera(); 28064 this._cameraL.viewport = new Vector4(); 28065 this._cameraR = new PerspectiveCamera(); 28066 this._cameraR.viewport = new Vector4(); 28067 this._cameras = [this._cameraL, this._cameraR]; 28068 this._cameraXR = new ArrayCamera(); 28069 this._currentDepthNear = null; 28070 this._currentDepthFar = null; 28071 this._controllers = []; 28072 this._controllerInputSources = []; 28073 this._xrRenderTarget = null; 28074 this._layers = []; 28075 this._sessionUsesLayers = false; 28076 this._supportsGlBinding = typeof XRWebGLBinding !== "undefined"; 28077 this._createXRLayer = createXRLayer.bind(this); 28078 this._gl = null; 28079 this._currentAnimationContext = null; 28080 this._currentAnimationLoop = null; 28081 this._currentPixelRatio = null; 28082 this._currentSize = new Vector2(); 28083 this._onSessionEvent = onSessionEvent.bind(this); 28084 this._onSessionEnd = onSessionEnd.bind(this); 28085 this._onInputSourcesChange = onInputSourcesChange.bind(this); 28086 this._onAnimationFrame = onAnimationFrame.bind(this); 28087 this._referenceSpace = null; 28088 this._referenceSpaceType = "local-floor"; 28089 this._customReferenceSpace = null; 28090 this._framebufferScaleFactor = 1; 28091 this._foveation = 1; 28092 this._session = null; 28093 this._glBaseLayer = null; 28094 this._glBinding = null; 28095 this._glProjLayer = null; 28096 this._xrFrame = null; 28097 this._supportsLayers = this._supportsGlBinding && "createProjectionLayer" in XRWebGLBinding.prototype; 28098 this._useMultiviewIfPossible = multiview; 28099 this._useMultiview = false; 28100 } 28101 /** 28102 * Returns an instance of `THREE.Group` that represents the transformation 28103 * of a XR controller in target ray space. The requested controller is defined 28104 * by the given index. 28105 * 28106 * @param {number} index - The index of the XR controller. 28107 * @return {Group} A group that represents the controller's transformation. 28108 */ 28109 getController(index) { 28110 const controller = this._getController(index); 28111 return controller.getTargetRaySpace(); 28112 } 28113 /** 28114 * Returns an instance of `THREE.Group` that represents the transformation 28115 * of a XR controller in grip space. The requested controller is defined 28116 * by the given index. 28117 * 28118 * @param {number} index - The index of the XR controller. 28119 * @return {Group} A group that represents the controller's transformation. 28120 */ 28121 getControllerGrip(index) { 28122 const controller = this._getController(index); 28123 return controller.getGripSpace(); 28124 } 28125 /** 28126 * Returns an instance of `THREE.Group` that represents the transformation 28127 * of a XR controller in hand space. The requested controller is defined 28128 * by the given index. 28129 * 28130 * @param {number} index - The index of the XR controller. 28131 * @return {Group} A group that represents the controller's transformation. 28132 */ 28133 getHand(index) { 28134 const controller = this._getController(index); 28135 return controller.getHandSpace(); 28136 } 28137 /** 28138 * Returns the foveation value. 28139 * 28140 * @return {number|undefined} The foveation value. Returns `undefined` if no base or projection layer is defined. 28141 */ 28142 getFoveation() { 28143 if (this._glProjLayer === null && this._glBaseLayer === null) { 28144 return void 0; 28145 } 28146 return this._foveation; 28147 } 28148 /** 28149 * Sets the foveation value. 28150 * 28151 * @param {number} foveation - A number in the range `[0,1]` where `0` means no foveation (full resolution) 28152 * and `1` means maximum foveation (the edges render at lower resolution). 28153 */ 28154 setFoveation(foveation) { 28155 this._foveation = foveation; 28156 if (this._glProjLayer !== null) { 28157 this._glProjLayer.fixedFoveation = foveation; 28158 } 28159 if (this._glBaseLayer !== null && this._glBaseLayer.fixedFoveation !== void 0) { 28160 this._glBaseLayer.fixedFoveation = foveation; 28161 } 28162 } 28163 /** 28164 * Returns the framebuffer scale factor. 28165 * 28166 * @return {number} The framebuffer scale factor. 28167 */ 28168 getFramebufferScaleFactor() { 28169 return this._framebufferScaleFactor; 28170 } 28171 /** 28172 * Sets the framebuffer scale factor. 28173 * 28174 * This method can not be used during a XR session. 28175 * 28176 * @param {number} factor - The framebuffer scale factor. 28177 */ 28178 setFramebufferScaleFactor(factor) { 28179 this._framebufferScaleFactor = factor; 28180 if (this.isPresenting === true) { 28181 warn("XRManager: Cannot change framebuffer scale while presenting."); 28182 } 28183 } 28184 /** 28185 * Returns the reference space type. 28186 * 28187 * @return {XRReferenceSpaceType} The reference space type. 28188 */ 28189 getReferenceSpaceType() { 28190 return this._referenceSpaceType; 28191 } 28192 /** 28193 * Sets the reference space type. 28194 * 28195 * This method can not be used during a XR session. 28196 * 28197 * @param {XRReferenceSpaceType} type - The reference space type. 28198 */ 28199 setReferenceSpaceType(type) { 28200 this._referenceSpaceType = type; 28201 if (this.isPresenting === true) { 28202 warn("XRManager: Cannot change reference space type while presenting."); 28203 } 28204 } 28205 /** 28206 * Returns the XR reference space. 28207 * 28208 * @return {XRReferenceSpace} The XR reference space. 28209 */ 28210 getReferenceSpace() { 28211 return this._customReferenceSpace || this._referenceSpace; 28212 } 28213 /** 28214 * Sets a custom XR reference space. 28215 * 28216 * @param {XRReferenceSpace} space - The XR reference space. 28217 */ 28218 setReferenceSpace(space) { 28219 this._customReferenceSpace = space; 28220 } 28221 /** 28222 * Returns the XR camera. 28223 * 28224 * @return {ArrayCamera} The XR camera. 28225 */ 28226 getCamera() { 28227 return this._cameraXR; 28228 } 28229 /** 28230 * Returns the environment blend mode from the current XR session. 28231 * 28232 * @return {'opaque'|'additive'|'alpha-blend'|undefined} The environment blend mode. Returns `undefined` when used outside of a XR session. 28233 */ 28234 getEnvironmentBlendMode() { 28235 if (this._session !== null) { 28236 return this._session.environmentBlendMode; 28237 } 28238 } 28239 /** 28240 * Returns the current XR binding. 28241 * 28242 * Creates a new binding if needed and the browser is 28243 * capable of doing so. 28244 * 28245 * @return {?XRWebGLBinding} The XR binding. Returns `null` if one cannot be created. 28246 */ 28247 getBinding() { 28248 if (this._glBinding === null && this._supportsGlBinding) { 28249 this._glBinding = new XRWebGLBinding(this._session, this._gl); 28250 } 28251 return this._glBinding; 28252 } 28253 /** 28254 * Returns the current XR frame. 28255 * 28256 * @return {?XRFrame} The XR frame. Returns `null` when used outside a XR session. 28257 */ 28258 getFrame() { 28259 return this._xrFrame; 28260 } 28261 /** 28262 * Returns `true` if the engine renders to a multiview target. 28263 * 28264 * @return {boolean} Whether the engine renders to a multiview render target or not. 28265 */ 28266 useMultiview() { 28267 return this._useMultiview; 28268 } 28269 /** 28270 * This method can be used in XR applications to create a quadratic layer that presents a separate 28271 * rendered scene. 28272 * 28273 * @param {number} width - The width of the layer plane in world units. 28274 * @param {number} height - The height of the layer plane in world units. 28275 * @param {Vector3} translation - The position/translation of the layer plane in world units. 28276 * @param {Quaternion} quaternion - The orientation of the layer plane expressed as a quaternion. 28277 * @param {number} pixelwidth - The width of the layer's render target in pixels. 28278 * @param {number} pixelheight - The height of the layer's render target in pixels. 28279 * @param {Function} rendercall - A callback function that renders the layer. Similar to code in 28280 * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. 28281 * @param {Object} [attributes={}] - Allows to configure the layer's render target. 28282 * @return {Mesh} A mesh representing the quadratic XR layer. This mesh should be added to the XR scene. 28283 */ 28284 createQuadLayer(width, height, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {}) { 28285 const geometry = new PlaneGeometry(width, height); 28286 const renderTarget = new XRRenderTarget( 28287 pixelwidth, 28288 pixelheight, 28289 { 28290 format: RGBAFormat, 28291 type: UnsignedByteType, 28292 depthTexture: new DepthTexture( 28293 pixelwidth, 28294 pixelheight, 28295 attributes.stencil ? UnsignedInt248Type : UnsignedIntType, 28296 void 0, 28297 void 0, 28298 void 0, 28299 void 0, 28300 void 0, 28301 void 0, 28302 attributes.stencil ? DepthStencilFormat : DepthFormat 28303 ), 28304 stencilBuffer: attributes.stencil, 28305 resolveDepthBuffer: false, 28306 resolveStencilBuffer: false 28307 } 28308 ); 28309 renderTarget._autoAllocateDepthBuffer = true; 28310 const material = new MeshBasicMaterial({ color: 16777215, side: FrontSide }); 28311 material.map = renderTarget.texture; 28312 material.map.offset.y = 1; 28313 material.map.repeat.y = -1; 28314 const plane = new Mesh(geometry, material); 28315 plane.position.copy(translation); 28316 plane.quaternion.copy(quaternion); 28317 const layer = { 28318 type: "quad", 28319 width, 28320 height, 28321 translation, 28322 quaternion, 28323 pixelwidth, 28324 pixelheight, 28325 plane, 28326 material, 28327 rendercall, 28328 renderTarget 28329 }; 28330 this._layers.push(layer); 28331 if (this._session !== null) { 28332 layer.plane.material = new MeshBasicMaterial({ color: 16777215, side: FrontSide }); 28333 layer.plane.material.blending = CustomBlending; 28334 layer.plane.material.blendEquation = AddEquation; 28335 layer.plane.material.blendSrc = ZeroFactor; 28336 layer.plane.material.blendDst = ZeroFactor; 28337 layer.xrlayer = this._createXRLayer(layer); 28338 const xrlayers = this._session.renderState.layers; 28339 xrlayers.unshift(layer.xrlayer); 28340 this._session.updateRenderState({ layers: xrlayers }); 28341 } else { 28342 renderTarget.isXRRenderTarget = false; 28343 } 28344 return plane; 28345 } 28346 /** 28347 * This method can be used in XR applications to create a cylindrical layer that presents a separate 28348 * rendered scene. 28349 * 28350 * @param {number} radius - The radius of the cylinder in world units. 28351 * @param {number} centralAngle - The central angle of the cylinder in radians. 28352 * @param {number} aspectratio - The aspect ratio. 28353 * @param {Vector3} translation - The position/translation of the layer plane in world units. 28354 * @param {Quaternion} quaternion - The orientation of the layer plane expressed as a quaternion. 28355 * @param {number} pixelwidth - The width of the layer's render target in pixels. 28356 * @param {number} pixelheight - The height of the layer's render target in pixels. 28357 * @param {Function} rendercall - A callback function that renders the layer. Similar to code in 28358 * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. 28359 * @param {Object} [attributes={}] - Allows to configure the layer's render target. 28360 * @return {Mesh} A mesh representing the cylindrical XR layer. This mesh should be added to the XR scene. 28361 */ 28362 createCylinderLayer(radius, centralAngle, aspectratio, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {}) { 28363 const geometry = new CylinderGeometry(radius, radius, radius * centralAngle / aspectratio, 64, 64, true, Math.PI - centralAngle / 2, centralAngle); 28364 const renderTarget = new XRRenderTarget( 28365 pixelwidth, 28366 pixelheight, 28367 { 28368 format: RGBAFormat, 28369 type: UnsignedByteType, 28370 depthTexture: new DepthTexture( 28371 pixelwidth, 28372 pixelheight, 28373 attributes.stencil ? UnsignedInt248Type : UnsignedIntType, 28374 void 0, 28375 void 0, 28376 void 0, 28377 void 0, 28378 void 0, 28379 void 0, 28380 attributes.stencil ? DepthStencilFormat : DepthFormat 28381 ), 28382 stencilBuffer: attributes.stencil, 28383 resolveDepthBuffer: false, 28384 resolveStencilBuffer: false 28385 } 28386 ); 28387 renderTarget._autoAllocateDepthBuffer = true; 28388 const material = new MeshBasicMaterial({ color: 16777215, side: BackSide }); 28389 material.map = renderTarget.texture; 28390 material.map.offset.y = 1; 28391 material.map.repeat.y = -1; 28392 const plane = new Mesh(geometry, material); 28393 plane.position.copy(translation); 28394 plane.quaternion.copy(quaternion); 28395 const layer = { 28396 type: "cylinder", 28397 radius, 28398 centralAngle, 28399 aspectratio, 28400 translation, 28401 quaternion, 28402 pixelwidth, 28403 pixelheight, 28404 plane, 28405 material, 28406 rendercall, 28407 renderTarget 28408 }; 28409 this._layers.push(layer); 28410 if (this._session !== null) { 28411 layer.plane.material = new MeshBasicMaterial({ color: 16777215, side: BackSide }); 28412 layer.plane.material.blending = CustomBlending; 28413 layer.plane.material.blendEquation = AddEquation; 28414 layer.plane.material.blendSrc = ZeroFactor; 28415 layer.plane.material.blendDst = ZeroFactor; 28416 layer.xrlayer = this._createXRLayer(layer); 28417 const xrlayers = this._session.renderState.layers; 28418 xrlayers.unshift(layer.xrlayer); 28419 this._session.updateRenderState({ layers: xrlayers }); 28420 } else { 28421 renderTarget.isXRRenderTarget = false; 28422 } 28423 return plane; 28424 } 28425 /** 28426 * Renders the XR layers that have been previously added to the scene. 28427 * 28428 * This method is usually called in your animation loop before rendering 28429 * the actual scene via `renderer.render( scene, camera );`. 28430 */ 28431 renderLayers() { 28432 const translationObject = new Vector3(); 28433 const quaternionObject = new Quaternion(); 28434 const renderer = this._renderer; 28435 const wasPresenting = this.isPresenting; 28436 this.isPresenting = false; 28437 const rendererSize = new Vector2(); 28438 renderer.getSize(rendererSize); 28439 const currentRenderTarget = renderer.getRenderTarget(); 28440 for (const layer of this._layers) { 28441 layer.renderTarget.isXRRenderTarget = this._session !== null; 28442 layer.renderTarget._hasExternalTextures = layer.renderTarget.isXRRenderTarget; 28443 const currentContextNode = renderer.contextNode; 28444 let contextNode; 28445 if (layer.renderTarget.isXRRenderTarget && this._sessionUsesLayers) { 28446 layer.xrlayer.transform = new XRRigidTransform(layer.plane.getWorldPosition(translationObject), layer.plane.getWorldQuaternion(quaternionObject)); 28447 const glSubImage = this._glBinding.getSubImage(layer.xrlayer, this._xrFrame); 28448 renderer.backend.setXRRenderTargetTextures( 28449 layer.renderTarget, 28450 glSubImage.colorTexture, 28451 void 0 28452 ); 28453 renderer._setXRLayerSize(layer.renderTarget.width, layer.renderTarget.height); 28454 contextNode = _contextNodeLib.get(currentContextNode); 28455 if (contextNode === void 0) { 28456 contextNode = currentContextNode.context({ 28457 getOutput: (outputNode) => { 28458 return renderOutput(outputNode, renderer.toneMapping, renderer.outputColorSpace); 28459 } 28460 }); 28461 _contextNodeLib.set(currentContextNode, contextNode); 28462 } 28463 } else { 28464 contextNode = currentContextNode; 28465 } 28466 renderer.contextNode = contextNode; 28467 renderer.setRenderTarget(layer.renderTarget); 28468 layer.rendercall(); 28469 renderer.contextNode = currentContextNode; 28470 } 28471 renderer.setRenderTarget(currentRenderTarget); 28472 renderer._setXRLayerSize(rendererSize.x, rendererSize.y); 28473 this.isPresenting = wasPresenting; 28474 } 28475 /** 28476 * Returns the current XR session. 28477 * 28478 * @return {?XRSession} The XR session. Returns `null` when used outside a XR session. 28479 */ 28480 getSession() { 28481 return this._session; 28482 } 28483 /** 28484 * After a XR session has been requested usually with one of the `*Button` modules, it 28485 * is injected into the renderer with this method. This method triggers the start of 28486 * the actual XR rendering. 28487 * 28488 * @async 28489 * @param {XRSession} session - The XR session to set. 28490 * @return {Promise} A Promise that resolves when the session has been set. 28491 */ 28492 async setSession(session) { 28493 const renderer = this._renderer; 28494 const backend = renderer.backend; 28495 this._gl = renderer.getContext(); 28496 const gl = this._gl; 28497 const attributes = gl.getContextAttributes(); 28498 this._session = session; 28499 if (session !== null) { 28500 if (backend.isWebGPUBackend === true) throw new Error('THREE.XRManager: XR is currently not supported with a WebGPU backend. Use WebGL by passing "{ forceWebGL: true }" to the constructor of the renderer.'); 28501 session.addEventListener("select", this._onSessionEvent); 28502 session.addEventListener("selectstart", this._onSessionEvent); 28503 session.addEventListener("selectend", this._onSessionEvent); 28504 session.addEventListener("squeeze", this._onSessionEvent); 28505 session.addEventListener("squeezestart", this._onSessionEvent); 28506 session.addEventListener("squeezeend", this._onSessionEvent); 28507 session.addEventListener("end", this._onSessionEnd); 28508 session.addEventListener("inputsourceschange", this._onInputSourcesChange); 28509 await backend.makeXRCompatible(); 28510 this._currentPixelRatio = renderer.getPixelRatio(); 28511 renderer.getSize(this._currentSize); 28512 this._currentAnimationContext = renderer._animation.getContext(); 28513 this._currentAnimationLoop = renderer._animation.getAnimationLoop(); 28514 renderer._animation.stop(); 28515 if (this._supportsLayers === true) { 28516 let depthFormat = null; 28517 let depthType = null; 28518 let glDepthFormat = null; 28519 if (renderer.depth) { 28520 glDepthFormat = renderer.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 28521 depthFormat = renderer.stencil ? DepthStencilFormat : DepthFormat; 28522 depthType = renderer.stencil ? UnsignedInt248Type : UnsignedIntType; 28523 } 28524 const projectionlayerInit = { 28525 colorFormat: gl.RGBA8, 28526 depthFormat: glDepthFormat, 28527 scaleFactor: this._framebufferScaleFactor, 28528 clearOnAccess: false 28529 }; 28530 if (this._useMultiviewIfPossible && renderer.hasFeature("OVR_multiview2")) { 28531 projectionlayerInit.textureType = "texture-array"; 28532 this._useMultiview = true; 28533 } 28534 this._glBinding = this.getBinding(); 28535 const glProjLayer = this._glBinding.createProjectionLayer(projectionlayerInit); 28536 const layersArray = [glProjLayer]; 28537 this._glProjLayer = glProjLayer; 28538 renderer.setPixelRatio(1); 28539 renderer._setXRLayerSize(glProjLayer.textureWidth, glProjLayer.textureHeight); 28540 const depth3 = this._useMultiview ? 2 : 1; 28541 const depthTexture = new DepthTexture(glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, void 0, void 0, void 0, void 0, void 0, void 0, depthFormat, depth3); 28542 this._xrRenderTarget = new XRRenderTarget( 28543 glProjLayer.textureWidth, 28544 glProjLayer.textureHeight, 28545 { 28546 format: RGBAFormat, 28547 type: UnsignedByteType, 28548 colorSpace: renderer.outputColorSpace, 28549 depthTexture, 28550 stencilBuffer: renderer.stencil, 28551 samples: attributes.antialias ? 4 : 0, 28552 resolveDepthBuffer: glProjLayer.ignoreDepthValues === false, 28553 resolveStencilBuffer: glProjLayer.ignoreDepthValues === false, 28554 depth: this._useMultiview ? 2 : 1, 28555 multiview: this._useMultiview 28556 } 28557 ); 28558 this._xrRenderTarget._hasExternalTextures = true; 28559 this._xrRenderTarget.depth = this._useMultiview ? 2 : 1; 28560 this._sessionUsesLayers = session.enabledFeatures.includes("layers"); 28561 this._referenceSpace = await session.requestReferenceSpace(this.getReferenceSpaceType()); 28562 if (this._sessionUsesLayers) { 28563 for (const layer of this._layers) { 28564 layer.plane.material = new MeshBasicMaterial({ color: 16777215, side: layer.type === "cylinder" ? BackSide : FrontSide }); 28565 layer.plane.material.blending = CustomBlending; 28566 layer.plane.material.blendEquation = AddEquation; 28567 layer.plane.material.blendSrc = ZeroFactor; 28568 layer.plane.material.blendDst = ZeroFactor; 28569 layer.xrlayer = this._createXRLayer(layer); 28570 layersArray.unshift(layer.xrlayer); 28571 } 28572 } 28573 session.updateRenderState({ layers: layersArray }); 28574 } else { 28575 const layerInit = { 28576 antialias: renderer.currentSamples > 0, 28577 alpha: true, 28578 depth: renderer.depth, 28579 stencil: renderer.stencil, 28580 framebufferScaleFactor: this.getFramebufferScaleFactor() 28581 }; 28582 const glBaseLayer = new XRWebGLLayer(session, gl, layerInit); 28583 this._glBaseLayer = glBaseLayer; 28584 session.updateRenderState({ baseLayer: glBaseLayer }); 28585 renderer.setPixelRatio(1); 28586 renderer._setXRLayerSize(glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight); 28587 this._xrRenderTarget = new XRRenderTarget( 28588 glBaseLayer.framebufferWidth, 28589 glBaseLayer.framebufferHeight, 28590 { 28591 format: RGBAFormat, 28592 type: UnsignedByteType, 28593 colorSpace: renderer.outputColorSpace, 28594 stencilBuffer: renderer.stencil, 28595 resolveDepthBuffer: glBaseLayer.ignoreDepthValues === false, 28596 resolveStencilBuffer: glBaseLayer.ignoreDepthValues === false 28597 } 28598 ); 28599 this._xrRenderTarget._isOpaqueFramebuffer = true; 28600 this._referenceSpace = await session.requestReferenceSpace(this.getReferenceSpaceType()); 28601 } 28602 this.setFoveation(this.getFoveation()); 28603 renderer._animation.setAnimationLoop(this._onAnimationFrame); 28604 renderer._animation.setContext(session); 28605 renderer._animation.start(); 28606 this.isPresenting = true; 28607 this.dispatchEvent({ type: "sessionstart" }); 28608 } 28609 } 28610 /** 28611 * This method is called by the renderer per frame and updates the XR camera 28612 * and it sub cameras based on the given camera. The given camera is the "user" 28613 * camera created on application level and used for non-XR rendering. 28614 * 28615 * @param {PerspectiveCamera} camera - The camera. 28616 */ 28617 updateCamera(camera) { 28618 const session = this._session; 28619 if (session === null) return; 28620 const depthNear = camera.near; 28621 const depthFar = camera.far; 28622 const cameraXR = this._cameraXR; 28623 const cameraL = this._cameraL; 28624 const cameraR = this._cameraR; 28625 cameraXR.near = cameraR.near = cameraL.near = depthNear; 28626 cameraXR.far = cameraR.far = cameraL.far = depthFar; 28627 cameraXR.isMultiViewCamera = this._useMultiview; 28628 if (this._currentDepthNear !== cameraXR.near || this._currentDepthFar !== cameraXR.far) { 28629 session.updateRenderState({ 28630 depthNear: cameraXR.near, 28631 depthFar: cameraXR.far 28632 }); 28633 this._currentDepthNear = cameraXR.near; 28634 this._currentDepthFar = cameraXR.far; 28635 } 28636 cameraXR.layers.mask = camera.layers.mask | 6; 28637 cameraL.layers.mask = cameraXR.layers.mask & -5; 28638 cameraR.layers.mask = cameraXR.layers.mask & -3; 28639 const parent = camera.parent; 28640 const cameras = cameraXR.cameras; 28641 updateCamera(cameraXR, parent); 28642 for (let i = 0; i < cameras.length; i++) { 28643 updateCamera(cameras[i], parent); 28644 } 28645 if (cameras.length === 2) { 28646 setProjectionFromUnion(cameraXR, cameraL, cameraR); 28647 } else { 28648 cameraXR.projectionMatrix.copy(cameraL.projectionMatrix); 28649 } 28650 updateUserCamera(camera, cameraXR, parent); 28651 } 28652 /** 28653 * Returns a WebXR controller for the given controller index. 28654 * 28655 * @private 28656 * @param {number} index - The controller index. 28657 * @return {WebXRController} The XR controller. 28658 */ 28659 _getController(index) { 28660 let controller = this._controllers[index]; 28661 if (controller === void 0) { 28662 controller = new WebXRController(); 28663 this._controllers[index] = controller; 28664 } 28665 return controller; 28666 } 28667}; 28668function setProjectionFromUnion(camera, cameraL, cameraR) { 28669 _cameraLPos.setFromMatrixPosition(cameraL.matrixWorld); 28670 _cameraRPos.setFromMatrixPosition(cameraR.matrixWorld); 28671 const ipd = _cameraLPos.distanceTo(_cameraRPos); 28672 const projL = cameraL.projectionMatrix.elements; 28673 const projR = cameraR.projectionMatrix.elements; 28674 const near = projL[14] / (projL[10] - 1); 28675 const far = projL[14] / (projL[10] + 1); 28676 const topFov = (projL[9] + 1) / projL[5]; 28677 const bottomFov = (projL[9] - 1) / projL[5]; 28678 const leftFov = (projL[8] - 1) / projL[0]; 28679 const rightFov = (projR[8] + 1) / projR[0]; 28680 const left = near * leftFov; 28681 const right = near * rightFov; 28682 const zOffset = ipd / (-leftFov + rightFov); 28683 const xOffset = zOffset * -leftFov; 28684 cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale); 28685 camera.translateX(xOffset); 28686 camera.translateZ(zOffset); 28687 camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale); 28688 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 28689 if (projL[10] === -1) { 28690 camera.projectionMatrix.copy(cameraL.projectionMatrix); 28691 camera.projectionMatrixInverse.copy(cameraL.projectionMatrixInverse); 28692 } else { 28693 const near2 = near + zOffset; 28694 const far2 = far + zOffset; 28695 const left2 = left - xOffset; 28696 const right2 = right + (ipd - xOffset); 28697 const top2 = topFov * far / far2 * near2; 28698 const bottom2 = bottomFov * far / far2 * near2; 28699 camera.projectionMatrix.makePerspective(left2, right2, top2, bottom2, near2, far2); 28700 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 28701 } 28702} 28703function updateCamera(camera, parent) { 28704 if (parent === null) { 28705 camera.matrixWorld.copy(camera.matrix); 28706 } else { 28707 camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix); 28708 } 28709 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 28710} 28711function updateUserCamera(camera, cameraXR, parent) { 28712 if (parent === null) { 28713 camera.matrix.copy(cameraXR.matrixWorld); 28714 } else { 28715 camera.matrix.copy(parent.matrixWorld); 28716 camera.matrix.invert(); 28717 camera.matrix.multiply(cameraXR.matrixWorld); 28718 } 28719 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 28720 camera.updateMatrixWorld(true); 28721 camera.projectionMatrix.copy(cameraXR.projectionMatrix); 28722 camera.projectionMatrixInverse.copy(cameraXR.projectionMatrixInverse); 28723 if (camera.isPerspectiveCamera) { 28724 camera.fov = RAD2DEG * 2 * Math.atan(1 / camera.projectionMatrix.elements[5]); 28725 camera.zoom = 1; 28726 } 28727} 28728function onSessionEvent(event) { 28729 const controllerIndex = this._controllerInputSources.indexOf(event.inputSource); 28730 if (controllerIndex === -1) { 28731 return; 28732 } 28733 const controller = this._controllers[controllerIndex]; 28734 if (controller !== void 0) { 28735 const referenceSpace = this.getReferenceSpace(); 28736 controller.update(event.inputSource, event.frame, referenceSpace); 28737 controller.dispatchEvent({ type: event.type, data: event.inputSource }); 28738 } 28739} 28740function onSessionEnd() { 28741 const session = this._session; 28742 const renderer = this._renderer; 28743 session.removeEventListener("select", this._onSessionEvent); 28744 session.removeEventListener("selectstart", this._onSessionEvent); 28745 session.removeEventListener("selectend", this._onSessionEvent); 28746 session.removeEventListener("squeeze", this._onSessionEvent); 28747 session.removeEventListener("squeezestart", this._onSessionEvent); 28748 session.removeEventListener("squeezeend", this._onSessionEvent); 28749 session.removeEventListener("end", this._onSessionEnd); 28750 session.removeEventListener("inputsourceschange", this._onInputSourcesChange); 28751 for (let i = 0; i < this._controllers.length; i++) { 28752 const inputSource = this._controllerInputSources[i]; 28753 if (inputSource === null) continue; 28754 this._controllerInputSources[i] = null; 28755 this._controllers[i].disconnect(inputSource); 28756 } 28757 this._currentDepthNear = null; 28758 this._currentDepthFar = null; 28759 renderer._resetXRState(); 28760 this._session = null; 28761 this._xrRenderTarget = null; 28762 this._glBinding = null; 28763 this._glBaseLayer = null; 28764 this._glProjLayer = null; 28765 if (this._sessionUsesLayers === true) { 28766 for (const layer of this._layers) { 28767 layer.renderTarget = new XRRenderTarget( 28768 layer.pixelwidth, 28769 layer.pixelheight, 28770 { 28771 format: RGBAFormat, 28772 type: UnsignedByteType, 28773 depthTexture: new DepthTexture( 28774 layer.pixelwidth, 28775 layer.pixelheight, 28776 layer.stencilBuffer ? UnsignedInt248Type : UnsignedIntType, 28777 void 0, 28778 void 0, 28779 void 0, 28780 void 0, 28781 void 0, 28782 void 0, 28783 layer.stencilBuffer ? DepthStencilFormat : DepthFormat 28784 ), 28785 stencilBuffer: layer.stencilBuffer, 28786 resolveDepthBuffer: false, 28787 resolveStencilBuffer: false 28788 } 28789 ); 28790 layer.renderTarget.isXRRenderTarget = false; 28791 layer.plane.material = layer.material; 28792 layer.material.map = layer.renderTarget.texture; 28793 layer.material.map.offset.y = 1; 28794 layer.material.map.repeat.y = -1; 28795 delete layer.xrlayer; 28796 } 28797 } 28798 this.isPresenting = false; 28799 this._useMultiview = false; 28800 renderer._animation.stop(); 28801 renderer._animation.setAnimationLoop(this._currentAnimationLoop); 28802 renderer._animation.setContext(this._currentAnimationContext); 28803 renderer._animation.start(); 28804 renderer.setPixelRatio(this._currentPixelRatio); 28805 renderer.setSize(this._currentSize.width, this._currentSize.height, false); 28806 this.dispatchEvent({ type: "sessionend" }); 28807} 28808function onInputSourcesChange(event) { 28809 const controllers = this._controllers; 28810 const controllerInputSources = this._controllerInputSources; 28811 for (let i = 0; i < event.removed.length; i++) { 28812 const inputSource = event.removed[i]; 28813 const index = controllerInputSources.indexOf(inputSource); 28814 if (index >= 0) { 28815 controllerInputSources[index] = null; 28816 controllers[index].disconnect(inputSource); 28817 } 28818 } 28819 for (let i = 0; i < event.added.length; i++) { 28820 const inputSource = event.added[i]; 28821 let controllerIndex = controllerInputSources.indexOf(inputSource); 28822 if (controllerIndex === -1) { 28823 for (let i2 = 0; i2 < controllers.length; i2++) { 28824 if (i2 >= controllerInputSources.length) { 28825 controllerInputSources.push(inputSource); 28826 controllerIndex = i2; 28827 break; 28828 } else if (controllerInputSources[i2] === null) { 28829 controllerInputSources[i2] = inputSource; 28830 controllerIndex = i2; 28831 break; 28832 } 28833 } 28834 if (controllerIndex === -1) break; 28835 } 28836 const controller = controllers[controllerIndex]; 28837 if (controller) { 28838 controller.connect(inputSource); 28839 } 28840 } 28841} 28842function createXRLayer(layer) { 28843 if (layer.type === "quad") { 28844 return this._glBinding.createQuadLayer({ 28845 transform: new XRRigidTransform(layer.translation, layer.quaternion), 28846 width: layer.width / 2, 28847 height: layer.height / 2, 28848 space: this._referenceSpace, 28849 viewPixelWidth: layer.pixelwidth, 28850 viewPixelHeight: layer.pixelheight, 28851 clearOnAccess: false 28852 }); 28853 } else { 28854 return this._glBinding.createCylinderLayer({ 28855 transform: new XRRigidTransform(layer.translation, layer.quaternion), 28856 radius: layer.radius, 28857 centralAngle: layer.centralAngle, 28858 aspectRatio: layer.aspectRatio, 28859 space: this._referenceSpace, 28860 viewPixelWidth: layer.pixelwidth, 28861 viewPixelHeight: layer.pixelheight, 28862 clearOnAccess: false 28863 }); 28864 } 28865} 28866function onAnimationFrame(time3, frame) { 28867 if (frame === void 0) return; 28868 const cameraXR = this._cameraXR; 28869 const renderer = this._renderer; 28870 const backend = renderer.backend; 28871 const glBaseLayer = this._glBaseLayer; 28872 const referenceSpace = this.getReferenceSpace(); 28873 const pose = frame.getViewerPose(referenceSpace); 28874 this._xrFrame = frame; 28875 if (pose !== null) { 28876 const views = pose.views; 28877 if (this._glBaseLayer !== null) { 28878 backend.setXRTarget(glBaseLayer.framebuffer); 28879 } 28880 let cameraXRNeedsUpdate = false; 28881 if (views.length !== cameraXR.cameras.length) { 28882 cameraXR.cameras.length = 0; 28883 cameraXRNeedsUpdate = true; 28884 } 28885 for (let i = 0; i < views.length; i++) { 28886 const view = views[i]; 28887 let viewport3; 28888 if (this._supportsLayers === true) { 28889 const glSubImage = this._glBinding.getViewSubImage(this._glProjLayer, view); 28890 viewport3 = glSubImage.viewport; 28891 if (i === 0) { 28892 backend.setXRRenderTargetTextures( 28893 this._xrRenderTarget, 28894 glSubImage.colorTexture, 28895 this._glProjLayer.ignoreDepthValues && !this._useMultiview ? void 0 : glSubImage.depthStencilTexture 28896 ); 28897 } 28898 } else { 28899 viewport3 = glBaseLayer.getViewport(view); 28900 } 28901 let camera = this._cameras[i]; 28902 if (camera === void 0) { 28903 camera = new PerspectiveCamera(); 28904 camera.layers.enable(i); 28905 camera.viewport = new Vector4(); 28906 this._cameras[i] = camera; 28907 } 28908 camera.matrix.fromArray(view.transform.matrix); 28909 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 28910 camera.projectionMatrix.fromArray(view.projectionMatrix); 28911 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 28912 camera.viewport.set(viewport3.x, viewport3.y, viewport3.width, viewport3.height); 28913 if (i === 0) { 28914 cameraXR.matrix.copy(camera.matrix); 28915 cameraXR.matrix.decompose(cameraXR.position, cameraXR.quaternion, cameraXR.scale); 28916 } 28917 if (cameraXRNeedsUpdate === true) { 28918 cameraXR.cameras.push(camera); 28919 } 28920 } 28921 renderer.setOutputRenderTarget(this._xrRenderTarget); 28922 } 28923 for (let i = 0; i < this._controllers.length; i++) { 28924 const inputSource = this._controllerInputSources[i]; 28925 const controller = this._controllers[i]; 28926 if (inputSource !== null && controller !== void 0) { 28927 controller.update(inputSource, frame, referenceSpace); 28928 } 28929 } 28930 if (this._currentAnimationLoop) this._currentAnimationLoop(time3, frame); 28931 if (frame.detectedPlanes) { 28932 this.dispatchEvent({ type: "planesdetected", data: frame }); 28933 } 28934 this._xrFrame = null; 28935} 28936var CanvasTarget = class extends EventDispatcher { 28937 /** 28938 * Constructs a new CanvasTarget. 28939 * 28940 * @param {HTMLCanvasElement|OffscreenCanvas} domElement - The canvas element to render to. 28941 */ 28942 constructor(domElement) { 28943 super(); 28944 this.domElement = domElement; 28945 this._pixelRatio = 1; 28946 this._width = this.domElement.width; 28947 this._height = this.domElement.height; 28948 this._viewport = new Vector4(0, 0, this._width, this._height); 28949 this._scissor = new Vector4(0, 0, this._width, this._height); 28950 this._scissorTest = false; 28951 this.colorTexture = new FramebufferTexture(); 28952 this.depthTexture = new DepthTexture(); 28953 } 28954 /** 28955 * Returns the pixel ratio. 28956 * 28957 * @return {number} The pixel ratio. 28958 */ 28959 getPixelRatio() { 28960 return this._pixelRatio; 28961 } 28962 /** 28963 * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. 28964 * 28965 * @param {Vector2} target - The method writes the result in this target object. 28966 * @return {Vector2} The drawing buffer size. 28967 */ 28968 getDrawingBufferSize(target) { 28969 return target.set(this._width * this._pixelRatio, this._height * this._pixelRatio).floor(); 28970 } 28971 /** 28972 * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. 28973 * 28974 * @param {Vector2} target - The method writes the result in this target object. 28975 * @return {Vector2} The renderer's size in logical pixels. 28976 */ 28977 getSize(target) { 28978 return target.set(this._width, this._height); 28979 } 28980 /** 28981 * Sets the given pixel ratio and resizes the canvas if necessary. 28982 * 28983 * @param {number} [value=1] - The pixel ratio. 28984 */ 28985 setPixelRatio(value = 1) { 28986 if (this._pixelRatio === value) return; 28987 this._pixelRatio = value; 28988 this.setSize(this._width, this._height, false); 28989 } 28990 /** 28991 * This method allows to define the drawing buffer size by specifying 28992 * width, height and pixel ratio all at once. The size of the drawing 28993 * buffer is computed with this formula: 28994 * ```js 28995 * size.x = width * pixelRatio; 28996 * size.y = height * pixelRatio; 28997 * ``` 28998 * 28999 * @param {number} width - The width in logical pixels. 29000 * @param {number} height - The height in logical pixels. 29001 * @param {number} pixelRatio - The pixel ratio. 29002 */ 29003 setDrawingBufferSize(width, height, pixelRatio) { 29004 if (this.xr && this.xr.isPresenting) return; 29005 this._width = width; 29006 this._height = height; 29007 this._pixelRatio = pixelRatio; 29008 this.domElement.width = Math.floor(width * pixelRatio); 29009 this.domElement.height = Math.floor(height * pixelRatio); 29010 this.setViewport(0, 0, width, height); 29011 this._dispatchResize(); 29012 } 29013 /** 29014 * Sets the size of the renderer. 29015 * 29016 * @param {number} width - The width in logical pixels. 29017 * @param {number} height - The height in logical pixels. 29018 * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. 29019 */ 29020 setSize(width, height, updateStyle = true) { 29021 if (this.xr && this.xr.isPresenting) return; 29022 this._width = width; 29023 this._height = height; 29024 this.domElement.width = Math.floor(width * this._pixelRatio); 29025 this.domElement.height = Math.floor(height * this._pixelRatio); 29026 if (updateStyle === true) { 29027 this.domElement.style.width = width + "px"; 29028 this.domElement.style.height = height + "px"; 29029 } 29030 this.setViewport(0, 0, width, height); 29031 this._dispatchResize(); 29032 } 29033 /** 29034 * Returns the scissor rectangle. 29035 * 29036 * @param {Vector4} target - The method writes the result in this target object. 29037 * @return {Vector4} The scissor rectangle. 29038 */ 29039 getScissor(target) { 29040 const scissor = this._scissor; 29041 target.x = scissor.x; 29042 target.y = scissor.y; 29043 target.width = scissor.width; 29044 target.height = scissor.height; 29045 return target; 29046 } 29047 /** 29048 * Defines the scissor rectangle. 29049 * 29050 * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. 29051 * Instead of passing four arguments, the method also works with a single four-dimensional vector. 29052 * @param {number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. 29053 * @param {number} width - The width of the scissor box in logical pixel unit. 29054 * @param {number} height - The height of the scissor box in logical pixel unit. 29055 */ 29056 setScissor(x, y, width, height) { 29057 const scissor = this._scissor; 29058 if (x.isVector4) { 29059 scissor.copy(x); 29060 } else { 29061 scissor.set(x, y, width, height); 29062 } 29063 } 29064 /** 29065 * Returns the scissor test value. 29066 * 29067 * @return {boolean} Whether the scissor test should be enabled or not. 29068 */ 29069 getScissorTest() { 29070 return this._scissorTest; 29071 } 29072 /** 29073 * Defines the scissor test. 29074 * 29075 * @param {boolean} boolean - Whether the scissor test should be enabled or not. 29076 */ 29077 setScissorTest(boolean) { 29078 this._scissorTest = boolean; 29079 } 29080 /** 29081 * Returns the viewport definition. 29082 * 29083 * @param {Vector4} target - The method writes the result in this target object. 29084 * @return {Vector4} The viewport definition. 29085 */ 29086 getViewport(target) { 29087 return target.copy(this._viewport); 29088 } 29089 /** 29090 * Defines the viewport. 29091 * 29092 * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. 29093 * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. 29094 * @param {number} width - The width of the viewport in logical pixel unit. 29095 * @param {number} height - The height of the viewport in logical pixel unit. 29096 * @param {number} minDepth - The minimum depth value of the viewport. WebGPU only. 29097 * @param {number} maxDepth - The maximum depth value of the viewport. WebGPU only. 29098 */ 29099 setViewport(x, y, width, height, minDepth = 0, maxDepth = 1) { 29100 const viewport3 = this._viewport; 29101 if (x.isVector4) { 29102 viewport3.copy(x); 29103 } else { 29104 viewport3.set(x, y, width, height); 29105 } 29106 viewport3.minDepth = minDepth; 29107 viewport3.maxDepth = maxDepth; 29108 } 29109 /** 29110 * Dispatches the resize event. 29111 * 29112 * @private 29113 */ 29114 _dispatchResize() { 29115 this.dispatchEvent({ type: "resize" }); 29116 } 29117 /** 29118 * Frees the GPU-related resources allocated by this instance. Call this 29119 * method whenever this instance is no longer used in your app. 29120 * 29121 * @fires RenderTarget#dispose 29122 */ 29123 dispose() { 29124 this.dispatchEvent({ type: "dispose" }); 29125 } 29126}; 29127var _scene = /* @__PURE__ */ new Scene(); 29128var _drawingBufferSize = /* @__PURE__ */ new Vector2(); 29129var _screen = /* @__PURE__ */ new Vector4(); 29130var _frustum = /* @__PURE__ */ new Frustum(); 29131var _frustumArray = /* @__PURE__ */ new FrustumArray(); 29132var _projScreenMatrix = /* @__PURE__ */ new Matrix4(); 29133var _vector4 = /* @__PURE__ */ new Vector4(); 29134var _shadowSide = { [FrontSide]: BackSide, [BackSide]: FrontSide, [DoubleSide]: DoubleSide }; 29135var Renderer = class { 29136 /** 29137 * Renderer options. 29138 * 29139 * @typedef {Object} Renderer~Options 29140 * @property {boolean} [logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. 29141 * @property {boolean} [reversedDepthBuffer=false] - Whether reversed depth buffer is enabled or not. 29142 * @property {boolean} [alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. 29143 * @property {boolean} [depth=true] - Whether the default framebuffer should have a depth buffer or not. 29144 * @property {boolean} [stencil=false] - Whether the default framebuffer should have a stencil buffer or not. 29145 * @property {boolean} [antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. 29146 * @property {number} [samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0 29147 * to overwrite the default. 29148 * @property {?Function} [getFallback=null] - This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. 29149 * @property {number} [outputBufferType=HalfFloatType] - Defines the type of output buffers. The default `HalfFloatType` is recommend for best 29150 * quality. To save memory and bandwidth, `UnsignedByteType` might be used. This will reduce rendering quality though. 29151 * @property {boolean} [multiview=false] - If set to `true`, the renderer will use multiview during WebXR rendering if supported. 29152 */ 29153 /** 29154 * Constructs a new renderer. 29155 * 29156 * @param {Backend} backend - The backend the renderer is targeting (e.g. WebGPU or WebGL 2). 29157 * @param {Renderer~Options} [parameters] - The configuration parameter. 29158 29159 */ 29160 constructor(backend, parameters = {}) { 29161 this.isRenderer = true; 29162 const { 29163 logarithmicDepthBuffer = false, 29164 reversedDepthBuffer = false, 29165 alpha = true, 29166 depth: depth3 = true, 29167 stencil = false, 29168 antialias = false, 29169 samples = 0, 29170 getFallback = null, 29171 outputBufferType = HalfFloatType, 29172 multiview = false 29173 } = parameters; 29174 this.backend = backend; 29175 this.autoClear = true; 29176 this.autoClearColor = true; 29177 this.autoClearDepth = true; 29178 this.autoClearStencil = true; 29179 this.alpha = alpha; 29180 this.logarithmicDepthBuffer = logarithmicDepthBuffer; 29181 this.reversedDepthBuffer = reversedDepthBuffer; 29182 this.outputColorSpace = SRGBColorSpace; 29183 this.toneMapping = NoToneMapping; 29184 this.toneMappingExposure = 1; 29185 this.sortObjects = true; 29186 this.depth = depth3; 29187 this.stencil = stencil; 29188 this.info = new Info(); 29189 this.contextNode = context(); 29190 this.library = new NodeLibrary(); 29191 this.lighting = new Lighting(); 29192 this._samples = samples || antialias === true ? 4 : 0; 29193 this._onCanvasTargetResize = this._onCanvasTargetResize.bind(this); 29194 this._canvasTarget = new CanvasTarget(backend.getDomElement()); 29195 this._canvasTarget.addEventListener("resize", this._onCanvasTargetResize); 29196 this._canvasTarget.isDefaultCanvasTarget = true; 29197 this._inspector = new InspectorBase(); 29198 this._inspector.setRenderer(this); 29199 this._getFallback = getFallback; 29200 this._attributes = null; 29201 this._geometries = null; 29202 this._nodes = null; 29203 this._animation = null; 29204 this._bindings = null; 29205 this._objects = null; 29206 this._pipelines = null; 29207 this._bundles = null; 29208 this._renderLists = null; 29209 this._renderContexts = null; 29210 this._textures = null; 29211 this._background = null; 29212 this._quadCache = /* @__PURE__ */ new Map(); 29213 this._currentRenderContext = null; 29214 this._opaqueSort = null; 29215 this._transparentSort = null; 29216 this._frameBufferTargets = /* @__PURE__ */ new Map(); 29217 const alphaClear = this.alpha === true ? 0 : 1; 29218 this._clearColor = new Color4(0, 0, 0, alphaClear); 29219 this._clearDepth = 1; 29220 this._clearStencil = 0; 29221 this._renderTarget = null; 29222 this._activeCubeFace = 0; 29223 this._activeMipmapLevel = 0; 29224 this._outputRenderTarget = null; 29225 this._mrt = null; 29226 this._renderObjectFunction = null; 29227 this._currentRenderObjectFunction = null; 29228 this._currentRenderBundle = null; 29229 this._handleObjectFunction = this._renderObjectDirect; 29230 this._isDeviceLost = false; 29231 this.onDeviceLost = this._onDeviceLost; 29232 this._outputBufferType = outputBufferType; 29233 this._cacheShadowNodes = /* @__PURE__ */ new WeakMap(); 29234 this._initialized = false; 29235 this._callDepth = -1; 29236 this._initPromise = null; 29237 this._compilationPromises = null; 29238 this.transparent = true; 29239 this.opaque = true; 29240 this.shadowMap = { 29241 enabled: false, 29242 transmitted: false, 29243 type: PCFShadowMap 29244 }; 29245 this.xr = new XRManager(this, multiview); 29246 this.debug = { 29247 checkShaderErrors: true, 29248 onShaderError: null, 29249 getShaderAsync: async (scene, camera, object) => { 29250 await this.compileAsync(scene, camera); 29251 const renderList = this._renderLists.get(scene, camera); 29252 const renderContext = this._renderContexts.get(this._renderTarget, this._mrt); 29253 const material = scene.overrideMaterial || object.material; 29254 const renderObject = this._objects.get(object, material, scene, camera, renderList.lightsNode, renderContext, renderContext.clippingContext); 29255 const { fragmentShader, vertexShader } = renderObject.getNodeBuilderState(); 29256 return { fragmentShader, vertexShader }; 29257 } 29258 }; 29259 } 29260 /** 29261 * Initializes the renderer so it is ready for usage. 29262 * 29263 * @async 29264 * @return {Promise<this>} A Promise that resolves when the renderer has been initialized. 29265 */ 29266 async init() { 29267 if (this._initPromise !== null) { 29268 return this._initPromise; 29269 } 29270 this._initPromise = new Promise(async (resolve, reject) => { 29271 let backend = this.backend; 29272 try { 29273 await backend.init(this); 29274 } catch (error2) { 29275 if (this._getFallback !== null) { 29276 try { 29277 this.backend = backend = this._getFallback(error2); 29278 await backend.init(this); 29279 } catch (error3) { 29280 reject(error3); 29281 return; 29282 } 29283 } else { 29284 reject(error2); 29285 return; 29286 } 29287 } 29288 this._nodes = new NodeManager(this, backend); 29289 this._animation = new Animation(this, this._nodes, this.info); 29290 this._attributes = new Attributes(backend, this.info); 29291 this._background = new Background(this, this._nodes); 29292 this._geometries = new Geometries(this._attributes, this.info); 29293 this._textures = new Textures(this, backend, this.info); 29294 this._pipelines = new Pipelines(backend, this._nodes, this.info); 29295 this._bindings = new Bindings(backend, this._nodes, this._textures, this._attributes, this._pipelines, this.info); 29296 this._objects = new RenderObjects(this, this._nodes, this._geometries, this._pipelines, this._bindings, this.info); 29297 this._renderLists = new RenderLists(this.lighting); 29298 this._bundles = new RenderBundles(); 29299 this._renderContexts = new RenderContexts(this); 29300 this._animation.start(); 29301 this._initialized = true; 29302 this._inspector.init(); 29303 resolve(this); 29304 }); 29305 return this._initPromise; 29306 } 29307 /** 29308 * A reference to the canvas element the renderer is drawing to. 29309 * This value of this property will automatically be created by 29310 * the renderer. 29311 * 29312 * @type {HTMLCanvasElement|OffscreenCanvas} 29313 */ 29314 get domElement() { 29315 return this._canvasTarget.domElement; 29316 } 29317 /** 29318 * The coordinate system of the renderer. The value of this property 29319 * depends on the selected backend. Either `THREE.WebGLCoordinateSystem` or 29320 * `THREE.WebGPUCoordinateSystem`. 29321 * 29322 * @readonly 29323 * @type {number} 29324 */ 29325 get coordinateSystem() { 29326 return this.backend.coordinateSystem; 29327 } 29328 /** 29329 * Compiles all materials in the given scene. This can be useful to avoid a 29330 * phenomenon which is called "shader compilation stutter", which occurs when 29331 * rendering an object with a new shader for the first time. 29332 * 29333 * If you want to add a 3D object to an existing scene, use the third optional 29334 * parameter for applying the target scene. Note that the (target) scene's lighting 29335 * and environment must be configured before calling this method. 29336 * 29337 * @async 29338 * @param {Object3D} scene - The scene or 3D object to precompile. 29339 * @param {Camera} camera - The camera that is used to render the scene. 29340 * @param {?Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. 29341 * @return {Promise} A Promise that resolves when the compile has been finished. 29342 */ 29343 async compileAsync(scene, camera, targetScene = null) { 29344 if (this._isDeviceLost === true) return; 29345 if (this._initialized === false) await this.init(); 29346 const nodeFrame = this._nodes.nodeFrame; 29347 const previousRenderId = nodeFrame.renderId; 29348 const previousRenderContext = this._currentRenderContext; 29349 const previousRenderObjectFunction = this._currentRenderObjectFunction; 29350 const previousHandleObjectFunction = this._handleObjectFunction; 29351 const previousCompilationPromises = this._compilationPromises; 29352 if (targetScene === null) targetScene = scene; 29353 const sceneRef = scene.isScene === true ? scene : targetScene.isScene === true ? targetScene : _scene; 29354 const useFrameBufferTarget = this.needsFrameBufferTarget && this._renderTarget === null; 29355 const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : this._renderTarget || this._outputRenderTarget; 29356 const renderContext = this._renderContexts.get(renderTarget, this._mrt); 29357 const activeMipmapLevel = this._activeMipmapLevel; 29358 const compilationPromises = []; 29359 this._currentRenderContext = renderContext; 29360 this._currentRenderObjectFunction = this.renderObject; 29361 this._handleObjectFunction = this._createObjectPipeline; 29362 this._compilationPromises = compilationPromises; 29363 nodeFrame.renderId++; 29364 nodeFrame.update(); 29365 renderContext.depth = this.depth; 29366 renderContext.stencil = this.stencil; 29367 if (!renderContext.clippingContext) renderContext.clippingContext = new ClippingContext(); 29368 renderContext.clippingContext.updateGlobal(sceneRef, camera); 29369 sceneRef.onBeforeRender(this, scene, camera, renderTarget); 29370 const renderList = this._renderLists.get(sceneRef, camera); 29371 renderList.begin(); 29372 this._projectObject(scene, camera, 0, renderList, renderContext.clippingContext); 29373 if (targetScene !== scene) { 29374 targetScene.traverseVisible(function(object) { 29375 if (object.isLight && object.layers.test(camera.layers)) { 29376 renderList.pushLight(object); 29377 } 29378 }); 29379 } 29380 renderList.finish(); 29381 if (renderTarget !== null) { 29382 this._textures.updateRenderTarget(renderTarget, activeMipmapLevel); 29383 const renderTargetData = this._textures.get(renderTarget); 29384 renderContext.textures = renderTargetData.textures; 29385 renderContext.depthTexture = renderTargetData.depthTexture; 29386 } else { 29387 renderContext.textures = null; 29388 renderContext.depthTexture = null; 29389 } 29390 if (targetScene !== scene) { 29391 this._background.update(targetScene, renderList, renderContext); 29392 } else { 29393 this._background.update(sceneRef, renderList, renderContext); 29394 } 29395 const opaqueObjects = renderList.opaque; 29396 const transparentObjects = renderList.transparent; 29397 const transparentDoublePassObjects = renderList.transparentDoublePass; 29398 const lightsNode = renderList.lightsNode; 29399 if (this.opaque === true && opaqueObjects.length > 0) this._renderObjects(opaqueObjects, camera, sceneRef, lightsNode); 29400 if (this.transparent === true && transparentObjects.length > 0) this._renderTransparents(transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode); 29401 nodeFrame.renderId = previousRenderId; 29402 this._currentRenderContext = previousRenderContext; 29403 this._currentRenderObjectFunction = previousRenderObjectFunction; 29404 this._handleObjectFunction = previousHandleObjectFunction; 29405 this._compilationPromises = previousCompilationPromises; 29406 for (const item of compilationPromises) { 29407 const renderObject = this._objects.get(item.object, item.material, item.scene, item.camera, item.lightsNode, item.renderContext, item.clippingContext, item.passId); 29408 renderObject.drawRange = item.object.geometry.drawRange; 29409 renderObject.group = item.group; 29410 this._geometries.updateForRender(renderObject); 29411 await this._nodes.getForRenderAsync(renderObject); 29412 this._nodes.updateBefore(renderObject); 29413 this._nodes.updateForRender(renderObject); 29414 this._bindings.updateForRender(renderObject); 29415 const pipelinePromises = []; 29416 this._pipelines.getForRender(renderObject, pipelinePromises); 29417 if (pipelinePromises.length > 0) { 29418 await Promise.all(pipelinePromises); 29419 } 29420 this._nodes.updateAfter(renderObject); 29421 await yieldToMain(); 29422 } 29423 } 29424 /** 29425 * Renders the scene in an async fashion. 29426 * 29427 * @async 29428 * @deprecated 29429 * @param {Object3D} scene - The scene or 3D object to render. 29430 * @param {Camera} camera - The camera. 29431 * @return {Promise} A Promise that resolves when the render has been finished. 29432 */ 29433 async renderAsync(scene, camera) { 29434 warnOnce('Renderer: "renderAsync()" has been deprecated. Use "render()" and "await renderer.init();" when creating the renderer.'); 29435 await this.init(); 29436 this.render(scene, camera); 29437 } 29438 /** 29439 * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, 29440 * the CPU waits for the GPU to complete its operation (e.g. a compute task). 29441 * 29442 * @async 29443 * @deprecated 29444 * @return {Promise} A Promise that resolves when synchronization has been finished. 29445 */ 29446 async waitForGPU() { 29447 error("Renderer: waitForGPU() has been removed. Read https://github.com/mrdoob/three.js/issues/32012 for more information."); 29448 } 29449 // 29450 set inspector(value) { 29451 if (this._inspector !== null) { 29452 this._inspector.setRenderer(null); 29453 } 29454 this._inspector = value; 29455 this._inspector.setRenderer(this); 29456 } 29457 /** 29458 * The inspector instance. The inspector can be any class that extends from `InspectorBase`. 29459 * 29460 * @type {InspectorBase} 29461 */ 29462 get inspector() { 29463 return this._inspector; 29464 } 29465 /** 29466 * Enables or disables high precision for model-view and normal-view matrices. 29467 * When enabled, will use CPU 64-bit precision for higher precision instead of GPU 32-bit for higher performance. 29468 * 29469 * NOTE: 64-bit precision is not compatible with `InstancedMesh` and `SkinnedMesh`. 29470 * 29471 * @param {boolean} value - Whether to enable or disable high precision. 29472 * @type {boolean} 29473 */ 29474 set highPrecision(value) { 29475 const contextNodeData = this.contextNode.value; 29476 if (value === true) { 29477 contextNodeData.modelViewMatrix = highpModelViewMatrix; 29478 contextNodeData.modelNormalViewMatrix = highpModelNormalViewMatrix; 29479 } else if (this.highPrecision) { 29480 delete contextNodeData.modelViewMatrix; 29481 delete contextNodeData.modelNormalViewMatrix; 29482 } 29483 } 29484 /** 29485 * Returns whether high precision is enabled or not. 29486 * 29487 * @return {boolean} Whether high precision is enabled or not. 29488 * @type {boolean} 29489 */ 29490 get highPrecision() { 29491 const contextNodeData = this.contextNode.value; 29492 return contextNodeData.modelViewMatrix === highpModelViewMatrix && contextNodeData.modelNormalViewMatrix === highpModelNormalViewMatrix; 29493 } 29494 /** 29495 * Sets the given MRT configuration. 29496 * 29497 * @param {MRTNode} mrt - The MRT node to set. 29498 * @return {Renderer} A reference to this renderer. 29499 */ 29500 setMRT(mrt3) { 29501 this._mrt = mrt3; 29502 return this; 29503 } 29504 /** 29505 * Returns the MRT configuration. 29506 * 29507 * @return {MRTNode} The MRT configuration. 29508 */ 29509 getMRT() { 29510 return this._mrt; 29511 } 29512 /** 29513 * Returns the output buffer type. 29514 * 29515 * @return {number} The output buffer type. 29516 */ 29517 getOutputBufferType() { 29518 return this._outputBufferType; 29519 } 29520 /** 29521 * Returns the output buffer type. 29522 * 29523 * @deprecated since r182. Use `.getOutputBufferType()` instead. 29524 * @return {number} The output buffer type. 29525 */ 29526 getColorBufferType() { 29527 warnOnce('Renderer: ".getColorBufferType()" has been renamed to ".getOutputBufferType()".'); 29528 return this.getOutputBufferType(); 29529 } 29530 /** 29531 * Default implementation of the device lost callback. 29532 * 29533 * @private 29534 * @param {Object} info - Information about the context lost. 29535 */ 29536 _onDeviceLost(info) { 29537 let errorMessage = `THREE.WebGPURenderer: ${info.api} Device Lost: 29538 29539Message: ${info.message}`; 29540 if (info.reason) { 29541 errorMessage += ` 29542Reason: ${info.reason}`; 29543 } 29544 error(errorMessage); 29545 this._isDeviceLost = true; 29546 } 29547 /** 29548 * Renders the given render bundle. 29549 * 29550 * @private 29551 * @param {Object} bundle - Render bundle data. 29552 * @param {Scene} sceneRef - The scene the render bundle belongs to. 29553 * @param {LightsNode} lightsNode - The lights node. 29554 */ 29555 _renderBundle(bundle, sceneRef, lightsNode) { 29556 const { bundleGroup, camera, renderList } = bundle; 29557 const renderContext = this._currentRenderContext; 29558 const renderBundle = this._bundles.get(bundleGroup, camera, renderContext); 29559 const renderBundleData = this.backend.get(renderBundle); 29560 const needsUpdate = bundleGroup.version !== renderBundleData.version; 29561 const renderBundleNeedsUpdate = needsUpdate || renderBundleData.bundleGPU === void 0; 29562 if (renderBundleNeedsUpdate) { 29563 this.backend.beginBundle(renderContext); 29564 if (renderBundleData.renderObjects === void 0 || needsUpdate) { 29565 renderBundleData.renderObjects = []; 29566 } 29567 this._currentRenderBundle = renderBundle; 29568 const { 29569 transparentDoublePass: transparentDoublePassObjects, 29570 transparent: transparentObjects, 29571 opaque: opaqueObjects 29572 } = renderList; 29573 if (this.opaque === true && opaqueObjects.length > 0) this._renderObjects(opaqueObjects, camera, sceneRef, lightsNode); 29574 if (this.transparent === true && transparentObjects.length > 0) this._renderTransparents(transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode); 29575 this._currentRenderBundle = null; 29576 this.backend.finishBundle(renderContext, renderBundle); 29577 renderBundleData.version = bundleGroup.version; 29578 } else { 29579 const { renderObjects } = renderBundleData; 29580 for (let i = 0, l = renderObjects.length; i < l; i++) { 29581 const renderObject = renderObjects[i]; 29582 if (this._nodes.needsRefresh(renderObject)) { 29583 this._nodes.updateBefore(renderObject); 29584 this._nodes.updateForRender(renderObject); 29585 this._bindings.updateForRender(renderObject); 29586 this._nodes.updateAfter(renderObject); 29587 } 29588 } 29589 } 29590 this.backend.addBundle(renderContext, renderBundle); 29591 } 29592 /** 29593 * Renders the scene or 3D object with the given camera. This method can only be called 29594 * if the renderer has been initialized. When using `render()` inside an animation loop, 29595 * it's guaranteed the renderer will be initialized. The animation loop must be defined 29596 * with {@link Renderer#setAnimationLoop} though. 29597 * 29598 * For all other use cases (like when using on-demand rendering), you must call 29599 * {@link Renderer#init} before rendering. 29600 * 29601 * The target of the method is the default framebuffer (meaning the canvas) 29602 * or alternatively a render target when specified via `setRenderTarget()`. 29603 * 29604 * @param {Object3D} scene - The scene or 3D object to render. 29605 * @param {Camera} camera - The camera to render the scene with. 29606 */ 29607 render(scene, camera) { 29608 if (this._initialized === false) { 29609 throw new Error('Renderer: .render() called before the backend is initialized. Use "await renderer.init();" before rendering.'); 29610 } 29611 this._renderScene(scene, camera); 29612 } 29613 /** 29614 * Returns whether the renderer has been initialized or not. 29615 * 29616 * @readonly 29617 * @return {boolean} Whether the renderer has been initialized or not. 29618 */ 29619 get initialized() { 29620 return this._initialized; 29621 } 29622 /** 29623 * Returns an internal render target which is used when computing the output tone mapping 29624 * and color space conversion. Unlike in `WebGLRenderer`, this is done in a separate render 29625 * pass and not inline to achieve more correct results. 29626 * 29627 * @private 29628 * @return {?RenderTarget} The render target. The method returns `null` if no output conversion should be applied. 29629 */ 29630 _getFrameBufferTarget() { 29631 const { currentToneMapping, currentColorSpace } = this; 29632 const useToneMapping = currentToneMapping !== NoToneMapping; 29633 const useColorSpace = currentColorSpace !== ColorManagement.workingColorSpace; 29634 if (useToneMapping === false && useColorSpace === false) return null; 29635 const { width, height } = this.getDrawingBufferSize(_drawingBufferSize); 29636 const { depth: depth3, stencil } = this; 29637 const target = this._outputRenderTarget || this._canvasTarget; 29638 let frameBufferTarget = this._frameBufferTargets.get(target); 29639 if (frameBufferTarget === void 0) { 29640 frameBufferTarget = new RenderTarget(width, height, { 29641 depthBuffer: depth3, 29642 stencilBuffer: stencil, 29643 type: this._outputBufferType, 29644 format: RGBAFormat, 29645 colorSpace: ColorManagement.workingColorSpace, 29646 generateMipmaps: false, 29647 minFilter: LinearFilter, 29648 magFilter: LinearFilter, 29649 samples: this.samples 29650 }); 29651 frameBufferTarget.isPostProcessingRenderTarget = true; 29652 const dispose2 = () => { 29653 target.removeEventListener("dispose", dispose2); 29654 frameBufferTarget.dispose(); 29655 this._frameBufferTargets.delete(target); 29656 }; 29657 target.addEventListener("dispose", dispose2); 29658 this._frameBufferTargets.set(target, frameBufferTarget); 29659 } 29660 const outputRenderTarget = this.getOutputRenderTarget(); 29661 frameBufferTarget.depthBuffer = depth3; 29662 frameBufferTarget.stencilBuffer = stencil; 29663 if (outputRenderTarget !== null) { 29664 frameBufferTarget.setSize(outputRenderTarget.width, outputRenderTarget.height, outputRenderTarget.depth); 29665 } else { 29666 frameBufferTarget.setSize(width, height, 1); 29667 } 29668 const viewport3 = this._outputRenderTarget ? this._outputRenderTarget.viewport : target._viewport; 29669 const scissor = this._outputRenderTarget ? this._outputRenderTarget.scissor : target._scissor; 29670 const pixelRatio = this._outputRenderTarget ? 1 : target._pixelRatio; 29671 const scissorTest = this._outputRenderTarget ? this._outputRenderTarget.scissorTest : target._scissorTest; 29672 frameBufferTarget.viewport.copy(viewport3); 29673 frameBufferTarget.scissor.copy(scissor); 29674 frameBufferTarget.viewport.multiplyScalar(pixelRatio); 29675 frameBufferTarget.scissor.multiplyScalar(pixelRatio); 29676 frameBufferTarget.scissorTest = scissorTest; 29677 frameBufferTarget.multiview = outputRenderTarget !== null ? outputRenderTarget.multiview : false; 29678 frameBufferTarget.resolveDepthBuffer = outputRenderTarget !== null ? outputRenderTarget.resolveDepthBuffer : true; 29679 frameBufferTarget._autoAllocateDepthBuffer = outputRenderTarget !== null ? outputRenderTarget._autoAllocateDepthBuffer : false; 29680 return frameBufferTarget; 29681 } 29682 /** 29683 * Renders the scene or 3D object with the given camera. 29684 * 29685 * @private 29686 * @param {Object3D} scene - The scene or 3D object to render. 29687 * @param {Camera} camera - The camera to render the scene with. 29688 * @param {boolean} [useFrameBufferTarget=true] - Whether to use a framebuffer target or not. 29689 * @return {RenderContext} The current render context. 29690 */ 29691 _renderScene(scene, camera, useFrameBufferTarget = true) { 29692 if (this._isDeviceLost === true) return; 29693 const frameBufferTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : null; 29694 const nodeFrame = this._nodes.nodeFrame; 29695 const previousRenderId = nodeFrame.renderId; 29696 const previousRenderContext = this._currentRenderContext; 29697 const previousRenderObjectFunction = this._currentRenderObjectFunction; 29698 const previousHandleObjectFunction = this._handleObjectFunction; 29699 this._callDepth++; 29700 const sceneRef = scene.isScene === true ? scene : _scene; 29701 const outputRenderTarget = this._renderTarget || this._outputRenderTarget; 29702 const activeCubeFace = this._activeCubeFace; 29703 const activeMipmapLevel = this._activeMipmapLevel; 29704 let renderTarget; 29705 if (frameBufferTarget !== null) { 29706 renderTarget = frameBufferTarget; 29707 this.setRenderTarget(renderTarget); 29708 } else { 29709 renderTarget = outputRenderTarget; 29710 } 29711 if (renderTarget !== null && renderTarget.depthBuffer === true) { 29712 const renderTargetData = this._textures.get(renderTarget); 29713 if (renderTargetData.depthInitialized !== true) { 29714 if (this.autoClear === false || this.autoClear === true && this.autoClearDepth === false) { 29715 this.clearDepth(); 29716 } 29717 renderTargetData.depthInitialized = true; 29718 } 29719 } 29720 const renderContext = this._renderContexts.get(renderTarget, this._mrt, this._callDepth); 29721 this._currentRenderContext = renderContext; 29722 this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject; 29723 this._handleObjectFunction = this._renderObjectDirect; 29724 this.info.calls++; 29725 this.info.render.calls++; 29726 this.info.render.frameCalls++; 29727 nodeFrame.renderId = this.info.calls; 29728 this.backend.updateTimeStampUID(renderContext); 29729 this.inspector.beginRender(this.backend.getTimestampUID(renderContext), scene, camera, renderTarget); 29730 const xr = this.xr; 29731 if (xr.isPresenting === false) { 29732 let projectionMatrixNeedsUpdate = false; 29733 if (this.reversedDepthBuffer === true && camera.reversedDepth !== true) { 29734 camera._reversedDepth = true; 29735 if (camera.isArrayCamera) { 29736 for (const subCamera of camera.cameras) { 29737 subCamera._reversedDepth = true; 29738 } 29739 } 29740 projectionMatrixNeedsUpdate = true; 29741 } 29742 const coordinateSystem = this.coordinateSystem; 29743 if (camera.coordinateSystem !== coordinateSystem) { 29744 camera.coordinateSystem = coordinateSystem; 29745 if (camera.isArrayCamera) { 29746 for (const subCamera of camera.cameras) { 29747 subCamera.coordinateSystem = coordinateSystem; 29748 } 29749 } 29750 projectionMatrixNeedsUpdate = true; 29751 } 29752 if (projectionMatrixNeedsUpdate === true) { 29753 camera.updateProjectionMatrix(); 29754 if (camera.isArrayCamera) { 29755 for (const subCamera of camera.cameras) { 29756 subCamera.updateProjectionMatrix(); 29757 } 29758 } 29759 } 29760 } 29761 if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld(); 29762 if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld(); 29763 if (xr.enabled === true && xr.isPresenting === true) { 29764 if (xr.cameraAutoUpdate === true) xr.updateCamera(camera); 29765 camera = xr.getCamera(); 29766 } 29767 const canvasTarget = this._canvasTarget; 29768 let viewport3 = canvasTarget._viewport; 29769 let scissor = canvasTarget._scissor; 29770 let pixelRatio = canvasTarget._pixelRatio; 29771 if (renderTarget !== null) { 29772 viewport3 = renderTarget.viewport; 29773 scissor = renderTarget.scissor; 29774 pixelRatio = 1; 29775 } 29776 this.getDrawingBufferSize(_drawingBufferSize); 29777 _screen.set(0, 0, _drawingBufferSize.width, _drawingBufferSize.height); 29778 const minDepth = viewport3.minDepth === void 0 ? 0 : viewport3.minDepth; 29779 const maxDepth = viewport3.maxDepth === void 0 ? 1 : viewport3.maxDepth; 29780 renderContext.viewportValue.copy(viewport3).multiplyScalar(pixelRatio).floor(); 29781 renderContext.viewportValue.width >>= activeMipmapLevel; 29782 renderContext.viewportValue.height >>= activeMipmapLevel; 29783 renderContext.viewportValue.minDepth = minDepth; 29784 renderContext.viewportValue.maxDepth = maxDepth; 29785 renderContext.viewport = renderContext.viewportValue.equals(_screen) === false; 29786 renderContext.scissorValue.copy(scissor).multiplyScalar(pixelRatio).floor(); 29787 renderContext.scissor = canvasTarget._scissorTest && renderContext.scissorValue.equals(_screen) === false; 29788 renderContext.scissorValue.width >>= activeMipmapLevel; 29789 renderContext.scissorValue.height >>= activeMipmapLevel; 29790 if (!renderContext.clippingContext) renderContext.clippingContext = new ClippingContext(); 29791 renderContext.clippingContext.updateGlobal(sceneRef, camera); 29792 sceneRef.onBeforeRender(this, scene, camera, renderTarget); 29793 const frustum = camera.isArrayCamera ? _frustumArray : _frustum; 29794 if (!camera.isArrayCamera) { 29795 _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 29796 frustum.setFromProjectionMatrix(_projScreenMatrix, camera.coordinateSystem, camera.reversedDepth); 29797 } 29798 const renderList = this._renderLists.get(scene, camera); 29799 renderList.begin(); 29800 this._projectObject(scene, camera, 0, renderList, renderContext.clippingContext); 29801 renderList.finish(); 29802 if (this.sortObjects === true) { 29803 renderList.sort(this._opaqueSort, this._transparentSort); 29804 } 29805 if (renderTarget !== null) { 29806 this._textures.updateRenderTarget(renderTarget, activeMipmapLevel); 29807 const renderTargetData = this._textures.get(renderTarget); 29808 renderContext.textures = renderTargetData.textures; 29809 renderContext.depthTexture = renderTargetData.depthTexture; 29810 renderContext.width = renderTargetData.width; 29811 renderContext.height = renderTargetData.height; 29812 renderContext.renderTarget = renderTarget; 29813 renderContext.depth = renderTarget.depthBuffer; 29814 renderContext.stencil = renderTarget.stencilBuffer; 29815 } else { 29816 renderContext.textures = null; 29817 renderContext.depthTexture = null; 29818 renderContext.width = _drawingBufferSize.width; 29819 renderContext.height = _drawingBufferSize.height; 29820 renderContext.depth = this.depth; 29821 renderContext.stencil = this.stencil; 29822 } 29823 renderContext.width >>= activeMipmapLevel; 29824 renderContext.height >>= activeMipmapLevel; 29825 renderContext.activeCubeFace = activeCubeFace; 29826 renderContext.activeMipmapLevel = activeMipmapLevel; 29827 renderContext.occlusionQueryCount = renderList.occlusionQueryCount; 29828 renderContext.scissorValue.max(_vector4.set(0, 0, 0, 0)); 29829 if (renderContext.scissorValue.x + renderContext.scissorValue.width > renderContext.width) { 29830 renderContext.scissorValue.width = Math.max(renderContext.width - renderContext.scissorValue.x, 0); 29831 } 29832 if (renderContext.scissorValue.y + renderContext.scissorValue.height > renderContext.height) { 29833 renderContext.scissorValue.height = Math.max(renderContext.height - renderContext.scissorValue.y, 0); 29834 } 29835 this._background.update(sceneRef, renderList, renderContext); 29836 renderContext.camera = camera; 29837 this.backend.beginRender(renderContext); 29838 const { 29839 bundles, 29840 lightsNode, 29841 transparentDoublePass: transparentDoublePassObjects, 29842 transparent: transparentObjects, 29843 opaque: opaqueObjects 29844 } = renderList; 29845 if (bundles.length > 0) this._renderBundles(bundles, sceneRef, lightsNode); 29846 if (this.opaque === true && opaqueObjects.length > 0) this._renderObjects(opaqueObjects, camera, sceneRef, lightsNode); 29847 if (this.transparent === true && transparentObjects.length > 0) this._renderTransparents(transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode); 29848 this.backend.finishRender(renderContext); 29849 nodeFrame.renderId = previousRenderId; 29850 this._currentRenderContext = previousRenderContext; 29851 this._currentRenderObjectFunction = previousRenderObjectFunction; 29852 this._handleObjectFunction = previousHandleObjectFunction; 29853 this._callDepth--; 29854 if (frameBufferTarget !== null) { 29855 this.setRenderTarget(outputRenderTarget, activeCubeFace, activeMipmapLevel); 29856 this._renderOutput(renderTarget); 29857 } 29858 sceneRef.onAfterRender(this, scene, camera, renderTarget); 29859 this.inspector.finishRender(this.backend.getTimestampUID(renderContext)); 29860 return renderContext; 29861 } 29862 _setXRLayerSize(width, height) { 29863 this._canvasTarget._width = width; 29864 this._canvasTarget._height = height; 29865 this.setViewport(0, 0, width, height); 29866 } 29867 /** 29868 * The output pass performs tone mapping and color space conversion. 29869 * 29870 * @private 29871 * @param {RenderTarget} renderTarget - The current render target. 29872 */ 29873 _renderOutput(renderTarget) { 29874 const cacheKey = this._nodes.getOutputCacheKey(); 29875 let quadData = this._quadCache.get(renderTarget.texture); 29876 let quad; 29877 if (quadData === void 0) { 29878 quad = new QuadMesh(new NodeMaterial()); 29879 quad.name = "Output Color Transform"; 29880 quad.material.name = "outputColorTransform"; 29881 quad.material.fragmentNode = this._nodes.getOutputNode(renderTarget.texture); 29882 quadData = { 29883 quad, 29884 cacheKey 29885 }; 29886 this._quadCache.set(renderTarget.texture, quadData); 29887 const dispose2 = () => { 29888 quad.material.dispose(); 29889 this._quadCache.delete(renderTarget.texture); 29890 renderTarget.texture.removeEventListener("dispose", dispose2); 29891 }; 29892 renderTarget.texture.addEventListener("dispose", dispose2); 29893 } else { 29894 quad = quadData.quad; 29895 if (quadData.cacheKey !== cacheKey) { 29896 quad.material.fragmentNode = this._nodes.getOutputNode(renderTarget.texture); 29897 quad.material.needsUpdate = true; 29898 quadData.cacheKey = cacheKey; 29899 } 29900 } 29901 const currentAutoClear = this.autoClear; 29902 const currentXR = this.xr.enabled; 29903 this.autoClear = false; 29904 this.xr.enabled = false; 29905 this._renderScene(quad, quad.camera, false); 29906 this.autoClear = currentAutoClear; 29907 this.xr.enabled = currentXR; 29908 } 29909 /** 29910 * Returns the maximum available anisotropy for texture filtering. 29911 * 29912 * @return {number} The maximum available anisotropy. 29913 */ 29914 getMaxAnisotropy() { 29915 return this.backend.capabilities.getMaxAnisotropy(); 29916 } 29917 /** 29918 * Returns the active cube face. 29919 * 29920 * @return {number} The active cube face. 29921 */ 29922 getActiveCubeFace() { 29923 return this._activeCubeFace; 29924 } 29925 /** 29926 * Returns the active mipmap level. 29927 * 29928 * @return {number} The active mipmap level. 29929 */ 29930 getActiveMipmapLevel() { 29931 return this._activeMipmapLevel; 29932 } 29933 /** 29934 * Applications are advised to always define the animation loop 29935 * with this method and not manually with `requestAnimationFrame()` 29936 * for best compatibility. 29937 * 29938 * @async 29939 * @param {?onAnimationCallback} callback - The application's animation loop. 29940 * @return {Promise} A Promise that resolves when the set has been executed. 29941 */ 29942 async setAnimationLoop(callback) { 29943 if (this._initialized === false) await this.init(); 29944 this._animation.setAnimationLoop(callback); 29945 } 29946 /** 29947 * Returns the current animation loop callback. 29948 * 29949 * @return {?Function} The current animation loop callback. 29950 */ 29951 getAnimationLoop() { 29952 return this._animation.getAnimationLoop(); 29953 } 29954 /** 29955 * Can be used to transfer buffer data from a storage buffer attribute 29956 * from the GPU to the CPU in context of compute shaders. 29957 * 29958 * @async 29959 * @param {BufferAttribute} attribute - The storage buffer attribute to read frm. 29960 * @param {ReadbackBuffer|ArrayBuffer} target - The storage buffer attribute. 29961 * @param {number} offset - The storage buffer attribute. 29962 * @param {number} count - The offset from which to start reading the 29963 * @return {Promise<ArrayBuffer|ReadbackBuffer>} A promise that resolves with the buffer data when the data are ready. 29964 */ 29965 async getArrayBufferAsync(attribute3, target = null, offset3 = 0, count = -1) { 29966 if (target !== null && target.isReadbackBuffer) { 29967 if (this.info.memoryMap.has(target) === false) { 29968 this.info.createReadbackBuffer(target); 29969 const disposeInfo = () => { 29970 target.removeEventListener("dispose", disposeInfo); 29971 this.info.destroyReadbackBuffer(target); 29972 }; 29973 target.addEventListener("dispose", disposeInfo); 29974 } 29975 } 29976 if (offset3 % 4 !== 0 || count > 0 && count % 4 !== 0) { 29977 throw new Error('THREE.Renderer: "getArrayBufferAsync()" offset and count must be a multiple of 4.'); 29978 } 29979 return await this.backend.getArrayBufferAsync(attribute3, target, offset3, count); 29980 } 29981 /** 29982 * Returns the rendering context. 29983 * 29984 * @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context. 29985 */ 29986 getContext() { 29987 return this.backend.getContext(); 29988 } 29989 /** 29990 * Returns the pixel ratio. 29991 * 29992 * @return {number} The pixel ratio. 29993 */ 29994 getPixelRatio() { 29995 return this._canvasTarget.getPixelRatio(); 29996 } 29997 /** 29998 * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. 29999 * 30000 * @param {Vector2} target - The method writes the result in this target object. 30001 * @return {Vector2} The drawing buffer size. 30002 */ 30003 getDrawingBufferSize(target) { 30004 return this._canvasTarget.getDrawingBufferSize(target); 30005 } 30006 /** 30007 * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. 30008 * 30009 * @param {Vector2} target - The method writes the result in this target object. 30010 * @return {Vector2} The renderer's size in logical pixels. 30011 */ 30012 getSize(target) { 30013 return this._canvasTarget.getSize(target); 30014 } 30015 /** 30016 * Sets the given pixel ratio and resizes the canvas if necessary. 30017 * 30018 * @param {number} [value=1] - The pixel ratio. 30019 */ 30020 setPixelRatio(value = 1) { 30021 this._canvasTarget.setPixelRatio(value); 30022 } 30023 /** 30024 * This method allows to define the drawing buffer size by specifying 30025 * width, height and pixel ratio all at once. The size of the drawing 30026 * buffer is computed with this formula: 30027 * ```js 30028 * size.x = width * pixelRatio; 30029 * size.y = height * pixelRatio; 30030 * ``` 30031 * 30032 * @param {number} width - The width in logical pixels. 30033 * @param {number} height - The height in logical pixels. 30034 * @param {number} pixelRatio - The pixel ratio. 30035 */ 30036 setDrawingBufferSize(width, height, pixelRatio) { 30037 if (this.xr && this.xr.isPresenting) return; 30038 this._canvasTarget.setDrawingBufferSize(width, height, pixelRatio); 30039 } 30040 /** 30041 * Sets the size of the renderer. 30042 * 30043 * @param {number} width - The width in logical pixels. 30044 * @param {number} height - The height in logical pixels. 30045 * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. 30046 */ 30047 setSize(width, height, updateStyle = true) { 30048 if (this.xr && this.xr.isPresenting) return; 30049 this._canvasTarget.setSize(width, height, updateStyle); 30050 } 30051 /** 30052 * Defines a manual sort function for the opaque render list. 30053 * Pass `null` to use the default sort. 30054 * 30055 * @param {Function} method - The sort function. 30056 */ 30057 setOpaqueSort(method) { 30058 this._opaqueSort = method; 30059 } 30060 /** 30061 * Defines a manual sort function for the transparent render list. 30062 * Pass `null` to use the default sort. 30063 * 30064 * @param {Function} method - The sort function. 30065 */ 30066 setTransparentSort(method) { 30067 this._transparentSort = method; 30068 } 30069 /** 30070 * Returns the scissor rectangle. 30071 * 30072 * @param {Vector4} target - The method writes the result in this target object. 30073 * @return {Vector4} The scissor rectangle. 30074 */ 30075 getScissor(target) { 30076 return this._canvasTarget.getScissor(target); 30077 } 30078 /** 30079 * Defines the scissor rectangle. 30080 * 30081 * @param {number | Vector4} x - The horizontal coordinate for the upper left corner of the box in logical pixel unit. 30082 * Instead of passing four arguments, the method also works with a single four-dimensional vector. 30083 * @param {number} y - The vertical coordinate for the upper left corner of the box in logical pixel unit. 30084 * @param {number} width - The width of the scissor box in logical pixel unit. 30085 * @param {number} height - The height of the scissor box in logical pixel unit. 30086 */ 30087 setScissor(x, y, width, height) { 30088 this._canvasTarget.setScissor(x, y, width, height); 30089 } 30090 /** 30091 * Returns the scissor test value. 30092 * 30093 * @return {boolean} Whether the scissor test should be enabled or not. 30094 */ 30095 getScissorTest() { 30096 return this._canvasTarget.getScissorTest(); 30097 } 30098 /** 30099 * Defines the scissor test. 30100 * 30101 * @param {boolean} boolean - Whether the scissor test should be enabled or not. 30102 */ 30103 setScissorTest(boolean) { 30104 this._canvasTarget.setScissorTest(boolean); 30105 this.backend.setScissorTest(boolean); 30106 } 30107 /** 30108 * Returns the viewport definition. 30109 * 30110 * @param {Vector4} target - The method writes the result in this target object. 30111 * @return {Vector4} The viewport definition. 30112 */ 30113 getViewport(target) { 30114 return this._canvasTarget.getViewport(target); 30115 } 30116 /** 30117 * Defines the viewport. 30118 * 30119 * @param {number | Vector4} x - The horizontal coordinate for the upper left corner of the viewport origin in logical pixel unit. 30120 * @param {number} y - The vertical coordinate for the upper left corner of the viewport origin in logical pixel unit. 30121 * @param {number} width - The width of the viewport in logical pixel unit. 30122 * @param {number} height - The height of the viewport in logical pixel unit. 30123 * @param {number} minDepth - The minimum depth value of the viewport. WebGPU only. 30124 * @param {number} maxDepth - The maximum depth value of the viewport. WebGPU only. 30125 */ 30126 setViewport(x, y, width, height, minDepth = 0, maxDepth = 1) { 30127 this._canvasTarget.setViewport(x, y, width, height, minDepth, maxDepth); 30128 } 30129 /** 30130 * Returns the clear color. 30131 * 30132 * @param {Color} target - The method writes the result in this target object. 30133 * @return {Color} The clear color. 30134 */ 30135 getClearColor(target) { 30136 return target.copy(this._clearColor); 30137 } 30138 /** 30139 * Defines the clear color and optionally the clear alpha. 30140 * 30141 * @param {Color} color - The clear color. 30142 * @param {number} [alpha=1] - The clear alpha. 30143 */ 30144 setClearColor(color3, alpha = 1) { 30145 this._clearColor.set(color3); 30146 this._clearColor.a = alpha; 30147 } 30148 /** 30149 * Returns the clear alpha. 30150 * 30151 * @return {number} The clear alpha. 30152 */ 30153 getClearAlpha() { 30154 return this._clearColor.a; 30155 } 30156 /** 30157 * Defines the clear alpha. 30158 * 30159 * @param {number} alpha - The clear alpha. 30160 */ 30161 setClearAlpha(alpha) { 30162 this._clearColor.a = alpha; 30163 } 30164 /** 30165 * Returns the clear depth. 30166 * 30167 * @return {number} The clear depth. 30168 */ 30169 getClearDepth() { 30170 return this.reversedDepthBuffer === true ? 1 - this._clearDepth : this._clearDepth; 30171 } 30172 /** 30173 * Defines the clear depth. 30174 * 30175 * @param {number} depth - The clear depth. 30176 */ 30177 setClearDepth(depth3) { 30178 this._clearDepth = depth3; 30179 } 30180 /** 30181 * Returns the clear stencil. 30182 * 30183 * @return {number} The clear stencil. 30184 */ 30185 getClearStencil() { 30186 return this._clearStencil; 30187 } 30188 /** 30189 * Defines the clear stencil. 30190 * 30191 * @param {number} stencil - The clear stencil. 30192 */ 30193 setClearStencil(stencil) { 30194 this._clearStencil = stencil; 30195 } 30196 /** 30197 * This method performs an occlusion query for the given 3D object. 30198 * It returns `true` if the given 3D object is fully occluded by other 30199 * 3D objects in the scene. 30200 * 30201 * @param {Object3D} object - The 3D object to test. 30202 * @return {boolean} Whether the 3D object is fully occluded or not. 30203 */ 30204 isOccluded(object) { 30205 const renderContext = this._currentRenderContext; 30206 return renderContext && this.backend.isOccluded(renderContext, object); 30207 } 30208 /** 30209 * Performs a manual clear operation. This method ignores `autoClear` properties. 30210 * 30211 * @param {boolean} [color=true] - Whether the color buffer should be cleared or not. 30212 * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not. 30213 * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. 30214 */ 30215 clear(color3 = true, depth3 = true, stencil = true) { 30216 if (this._initialized === false) { 30217 throw new Error('Renderer: .clear() called before the backend is initialized. Use "await renderer.init();" before before using this method.'); 30218 } 30219 const renderTarget = this._renderTarget || this._getFrameBufferTarget(); 30220 let renderContext = null; 30221 if (renderTarget !== null) { 30222 this._textures.updateRenderTarget(renderTarget); 30223 const renderTargetData = this._textures.get(renderTarget); 30224 renderContext = this._renderContexts.get(renderTarget, null, -1); 30225 renderContext.textures = renderTargetData.textures; 30226 renderContext.depthTexture = renderTargetData.depthTexture; 30227 renderContext.width = renderTargetData.width; 30228 renderContext.height = renderTargetData.height; 30229 renderContext.renderTarget = renderTarget; 30230 renderContext.depth = renderTarget.depthBuffer; 30231 renderContext.stencil = renderTarget.stencilBuffer; 30232 const color4 = this.backend.getClearColor(); 30233 renderContext.clearColorValue.r = color4.r; 30234 renderContext.clearColorValue.g = color4.g; 30235 renderContext.clearColorValue.b = color4.b; 30236 renderContext.clearColorValue.a = color4.a; 30237 renderContext.clearDepthValue = this.getClearDepth(); 30238 renderContext.clearStencilValue = this.getClearStencil(); 30239 renderContext.activeCubeFace = this.getActiveCubeFace(); 30240 renderContext.activeMipmapLevel = this.getActiveMipmapLevel(); 30241 if (renderTarget.depthBuffer === true) renderTargetData.depthInitialized = true; 30242 } 30243 this.backend.clear(color3, depth3, stencil, renderContext); 30244 if (renderTarget !== null && this._renderTarget === null) { 30245 this._renderOutput(renderTarget); 30246 } 30247 } 30248 /** 30249 * Performs a manual clear operation of the color buffer. This method ignores `autoClear` properties. 30250 */ 30251 clearColor() { 30252 this.clear(true, false, false); 30253 } 30254 /** 30255 * Performs a manual clear operation of the depth buffer. This method ignores `autoClear` properties. 30256 */ 30257 clearDepth() { 30258 this.clear(false, true, false); 30259 } 30260 /** 30261 * Performs a manual clear operation of the stencil buffer. This method ignores `autoClear` properties. 30262 */ 30263 clearStencil() { 30264 this.clear(false, false, true); 30265 } 30266 /** 30267 * Async version of {@link Renderer#clear}. 30268 * 30269 * @async 30270 * @deprecated 30271 * @param {boolean} [color=true] - Whether the color buffer should be cleared or not. 30272 * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not. 30273 * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. 30274 * @return {Promise} A Promise that resolves when the clear operation has been executed. 30275 */ 30276 async clearAsync(color3 = true, depth3 = true, stencil = true) { 30277 warnOnce('Renderer: "clearAsync()" has been deprecated. Use "clear()" and "await renderer.init();" when creating the renderer.'); 30278 await this.init(); 30279 this.clear(color3, depth3, stencil); 30280 } 30281 /** 30282 * Async version of {@link Renderer#clearColor}. 30283 * 30284 * @async 30285 * @deprecated 30286 * @return {Promise} A Promise that resolves when the clear operation has been executed. 30287 */ 30288 async clearColorAsync() { 30289 warnOnce('Renderer: "clearColorAsync()" has been deprecated. Use "clearColor()" and "await renderer.init();" when creating the renderer.'); 30290 this.clear(true, false, false); 30291 } 30292 /** 30293 * Async version of {@link Renderer#clearDepth}. 30294 * 30295 * @async 30296 * @deprecated 30297 * @return {Promise} A Promise that resolves when the clear operation has been executed. 30298 */ 30299 async clearDepthAsync() { 30300 warnOnce('Renderer: "clearDepthAsync()" has been deprecated. Use "clearDepth()" and "await renderer.init();" when creating the renderer.'); 30301 this.clear(false, true, false); 30302 } 30303 /** 30304 * Async version of {@link Renderer#clearStencil}. 30305 * 30306 * @async 30307 * @deprecated 30308 * @return {Promise} A Promise that resolves when the clear operation has been executed. 30309 */ 30310 async clearStencilAsync() { 30311 warnOnce('Renderer: "clearStencilAsync()" has been deprecated. Use "clearStencil()" and "await renderer.init();" when creating the renderer.'); 30312 this.clear(false, false, true); 30313 } 30314 /** 30315 * Returns `true` if a framebuffer target is needed to perform tone mapping or color space conversion. 30316 * If this is the case, the renderer allocates an internal render target for that purpose. 30317 * 30318 */ 30319 get needsFrameBufferTarget() { 30320 const useToneMapping = this.currentToneMapping !== NoToneMapping; 30321 const useColorSpace = this.currentColorSpace !== ColorManagement.workingColorSpace; 30322 return useToneMapping || useColorSpace; 30323 } 30324 /** 30325 * The number of samples used for multi-sample anti-aliasing (MSAA). 30326 * 30327 * @type {number} 30328 * @default 0 30329 */ 30330 get samples() { 30331 return this._samples; 30332 } 30333 /** 30334 * The current number of samples used for multi-sample anti-aliasing (MSAA). 30335 * 30336 * When rendering to a custom render target, the number of samples of that render target is used. 30337 * If the renderer needs an internal framebuffer target for tone mapping or color space conversion, 30338 * the number of samples is set to 0. 30339 * 30340 * @type {number} 30341 */ 30342 get currentSamples() { 30343 let samples = this._samples; 30344 if (this._renderTarget !== null) { 30345 samples = this._renderTarget.samples; 30346 } else if (this.needsFrameBufferTarget) { 30347 samples = 0; 30348 } 30349 return samples; 30350 } 30351 /** 30352 * The current tone mapping of the renderer. When not producing screen output, 30353 * the tone mapping is always `NoToneMapping`. 30354 * 30355 * @type {number} 30356 */ 30357 get currentToneMapping() { 30358 return this.isOutputTarget ? this.toneMapping : NoToneMapping; 30359 } 30360 /** 30361 * The current color space of the renderer. When not producing screen output, 30362 * the color space is always the working color space. 30363 * 30364 * @type {string} 30365 */ 30366 get currentColorSpace() { 30367 return this.isOutputTarget ? this.outputColorSpace : ColorManagement.workingColorSpace; 30368 } 30369 /** 30370 * Returns `true` if the rendering settings are set to screen output. 30371 * 30372 * @returns {boolean} True if the current render target is the same of output render target or `null`, otherwise false. 30373 */ 30374 get isOutputTarget() { 30375 return this._renderTarget === this._outputRenderTarget || this._renderTarget === null; 30376 } 30377 /** 30378 * Frees all internal resources of the renderer. Call this method if the renderer 30379 * is no longer in use by your app. 30380 */ 30381 dispose() { 30382 if (this._initialized === true) { 30383 this.info.dispose(); 30384 this.backend.dispose(); 30385 this._animation.dispose(); 30386 this._objects.dispose(); 30387 this._geometries.dispose(); 30388 this._pipelines.dispose(); 30389 this._nodes.dispose(); 30390 this._bindings.dispose(); 30391 this._renderLists.dispose(); 30392 this._renderContexts.dispose(); 30393 this._textures.dispose(); 30394 for (const canvasTarget of this._frameBufferTargets.keys()) { 30395 canvasTarget.dispose(); 30396 } 30397 Object.values(this.backend.timestampQueryPool).forEach((queryPool) => { 30398 if (queryPool !== null) queryPool.dispose(); 30399 }); 30400 } 30401 this.setRenderTarget(null); 30402 this.setAnimationLoop(null); 30403 } 30404 /** 30405 * Sets the given render target. Calling this method means the renderer does not 30406 * target the default framebuffer (meaning the canvas) anymore but a custom framebuffer. 30407 * Use `null` as the first argument to reset the state. 30408 * 30409 * @param {?RenderTarget} renderTarget - The render target to set. 30410 * @param {number} [activeCubeFace=0] - The active cube face. 30411 * @param {number} [activeMipmapLevel=0] - The active mipmap level. 30412 */ 30413 setRenderTarget(renderTarget, activeCubeFace = 0, activeMipmapLevel = 0) { 30414 this._renderTarget = renderTarget; 30415 this._activeCubeFace = activeCubeFace; 30416 this._activeMipmapLevel = activeMipmapLevel; 30417 } 30418 /** 30419 * Returns the current render target. 30420 * 30421 * @return {?RenderTarget} The render target. Returns `null` if no render target is set. 30422 */ 30423 getRenderTarget() { 30424 return this._renderTarget; 30425 } 30426 /** 30427 * Sets the output render target for the renderer. 30428 * 30429 * @param {?RenderTarget} renderTarget - The render target to set as the output target. 30430 */ 30431 setOutputRenderTarget(renderTarget) { 30432 this._outputRenderTarget = renderTarget; 30433 } 30434 /** 30435 * Returns the current output target. 30436 * 30437 * @return {?RenderTarget} The current output render target. Returns `null` if no output target is set. 30438 */ 30439 getOutputRenderTarget() { 30440 return this._outputRenderTarget; 30441 } 30442 /** 30443 * Sets the canvas target. The canvas target manages the HTML canvas 30444 * or the offscreen canvas the renderer draws into. 30445 * 30446 * @param {CanvasTarget} canvasTarget - The canvas target. 30447 */ 30448 setCanvasTarget(canvasTarget) { 30449 this._canvasTarget.removeEventListener("resize", this._onCanvasTargetResize); 30450 this._canvasTarget = canvasTarget; 30451 this._canvasTarget.addEventListener("resize", this._onCanvasTargetResize); 30452 } 30453 /** 30454 * Returns the current canvas target. 30455 * 30456 * @return {CanvasTarget} The current canvas target. 30457 */ 30458 getCanvasTarget() { 30459 return this._canvasTarget; 30460 } 30461 /** 30462 * Resets the renderer to the initial state before WebXR started. 30463 * 30464 * @private 30465 */ 30466 _resetXRState() { 30467 this.backend.setXRTarget(null); 30468 this.setOutputRenderTarget(null); 30469 this.setRenderTarget(null); 30470 for (const canvasTarget of this._frameBufferTargets.keys()) { 30471 canvasTarget.dispose(); 30472 } 30473 } 30474 /** 30475 * Callback for {@link Renderer#setRenderObjectFunction}. 30476 * 30477 * @callback renderObjectFunction 30478 * @param {Object3D} object - The 3D object. 30479 * @param {Scene} scene - The scene the 3D object belongs to. 30480 * @param {Camera} camera - The camera the object should be rendered with. 30481 * @param {BufferGeometry} geometry - The object's geometry. 30482 * @param {Material} material - The object's material. 30483 * @param {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 30484 * @param {LightsNode} lightsNode - The current lights node. 30485 * @param {ClippingContext} clippingContext - The clipping context. 30486 * @param {?string} [passId=null] - An optional ID for identifying the pass. 30487 */ 30488 /** 30489 * Sets the given render object function. Calling this method overwrites the default implementation 30490 * which is {@link Renderer#renderObject}. Defining a custom function can be useful 30491 * if you want to modify the way objects are rendered. For example you can define things like "every 30492 * object that has material of a certain type should perform a pre-pass with a special overwrite material". 30493 * The custom function must always call `renderObject()` in its implementation. 30494 * 30495 * Use `null` as the first argument to reset the state. 30496 * 30497 * @param {?renderObjectFunction} renderObjectFunction - The render object function. 30498 */ 30499 setRenderObjectFunction(renderObjectFunction) { 30500 this._renderObjectFunction = renderObjectFunction; 30501 } 30502 /** 30503 * Returns the current render object function. 30504 * 30505 * @return {?Function} The current render object function. Returns `null` if no function is set. 30506 */ 30507 getRenderObjectFunction() { 30508 return this._renderObjectFunction; 30509 } 30510 /** 30511 * Execute a single or an array of compute nodes. This method can only be called 30512 * if the renderer has been initialized. 30513 * 30514 * @param {Node|Array<Node>} computeNodes - The compute node(s). 30515 * @param {number|Array<number>|IndirectStorageBufferAttribute} [dispatchSize=null] 30516 * - A single number representing count, or 30517 * - An array [x, y, z] representing dispatch size, or 30518 * - A IndirectStorageBufferAttribute for indirect dispatch size. 30519 * @return {Promise|undefined} A Promise that resolve when the compute has finished. Only returned when the renderer has not been initialized. 30520 */ 30521 compute(computeNodes, dispatchSize = null) { 30522 if (this._isDeviceLost === true) return; 30523 if (this._initialized === false) { 30524 warn("Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead."); 30525 return this.computeAsync(computeNodes, dispatchSize); 30526 } 30527 const nodeFrame = this._nodes.nodeFrame; 30528 const previousRenderId = nodeFrame.renderId; 30529 this.info.calls++; 30530 this.info.compute.calls++; 30531 this.info.compute.frameCalls++; 30532 nodeFrame.renderId = this.info.calls; 30533 this.backend.updateTimeStampUID(computeNodes); 30534 this.inspector.beginCompute(this.backend.getTimestampUID(computeNodes), computeNodes); 30535 const backend = this.backend; 30536 const pipelines = this._pipelines; 30537 const bindings = this._bindings; 30538 const nodes = this._nodes; 30539 const computeList = Array.isArray(computeNodes) ? computeNodes : [computeNodes]; 30540 if (computeList[0] === void 0 || computeList[0].isComputeNode !== true) { 30541 throw new Error("THREE.Renderer: .compute() expects a ComputeNode."); 30542 } 30543 backend.beginCompute(computeNodes); 30544 for (const computeNode of computeList) { 30545 if (pipelines.has(computeNode) === false) { 30546 const dispose2 = () => { 30547 computeNode.removeEventListener("dispose", dispose2); 30548 pipelines.delete(computeNode); 30549 bindings.deleteForCompute(computeNode); 30550 nodes.delete(computeNode); 30551 }; 30552 computeNode.addEventListener("dispose", dispose2); 30553 const onInitFn = computeNode.onInitFunction; 30554 if (onInitFn !== null) { 30555 onInitFn.call(computeNode, { renderer: this }); 30556 } 30557 } 30558 nodes.updateForCompute(computeNode); 30559 bindings.updateForCompute(computeNode); 30560 const computeBindings = bindings.getForCompute(computeNode); 30561 const computePipeline = pipelines.getForCompute(computeNode, computeBindings); 30562 backend.compute(computeNodes, computeNode, computeBindings, computePipeline, dispatchSize); 30563 } 30564 backend.finishCompute(computeNodes); 30565 nodeFrame.renderId = previousRenderId; 30566 this.inspector.finishCompute(this.backend.getTimestampUID(computeNodes)); 30567 } 30568 /** 30569 * Execute a single or an array of compute nodes. 30570 * 30571 * @async 30572 * @param {Node|Array<Node>} computeNodes - The compute node(s). 30573 * @param {number|Array<number>|IndirectStorageBufferAttribute} [dispatchSize=null] 30574 * - A single number representing count, or 30575 * - An array [x, y, z] representing dispatch size, or 30576 * - A IndirectStorageBufferAttribute for indirect dispatch size. 30577 * @return {Promise} A Promise that resolve when the compute has finished. 30578 */ 30579 async computeAsync(computeNodes, dispatchSize = null) { 30580 if (this._initialized === false) await this.init(); 30581 this.compute(computeNodes, dispatchSize); 30582 } 30583 /** 30584 * Checks if the given feature is supported by the selected backend. 30585 * 30586 * @async 30587 * @deprecated 30588 * @param {string} name - The feature's name. 30589 * @return {Promise<boolean>} A Promise that resolves with a bool that indicates whether the feature is supported or not. 30590 */ 30591 async hasFeatureAsync(name) { 30592 warnOnce('Renderer: "hasFeatureAsync()" has been deprecated. Use "hasFeature()" and "await renderer.init();" when creating the renderer.'); 30593 await this.init(); 30594 return this.hasFeature(name); 30595 } 30596 async resolveTimestampsAsync(type = "render") { 30597 if (this._initialized === false) await this.init(); 30598 return this.backend.resolveTimestampsAsync(type); 30599 } 30600 /** 30601 * Checks if the given feature is supported by the selected backend. If the 30602 * renderer has not been initialized, this method always returns `false`. 30603 * 30604 * @param {string} name - The feature's name. 30605 * @return {boolean} Whether the feature is supported or not. 30606 */ 30607 hasFeature(name) { 30608 if (this._initialized === false) { 30609 throw new Error('Renderer: .hasFeature() called before the backend is initialized. Use "await renderer.init();" before before using this method.'); 30610 } 30611 return this.backend.hasFeature(name); 30612 } 30613 /** 30614 * Returns `true` when the renderer has been initialized. 30615 * 30616 * @return {boolean} Whether the renderer has been initialized or not. 30617 */ 30618 hasInitialized() { 30619 return this._initialized; 30620 } 30621 /** 30622 * Initializes the given textures. Useful for preloading a texture rather than waiting until first render 30623 * (which can cause noticeable lags due to decode and GPU upload overhead). 30624 * 30625 * @async 30626 * @deprecated 30627 * @param {Texture} texture - The texture. 30628 * @return {Promise} A Promise that resolves when the texture has been initialized. 30629 */ 30630 async initTextureAsync(texture3) { 30631 warnOnce('Renderer: "initTextureAsync()" has been deprecated. Use "initTexture()" and "await renderer.init();" when creating the renderer.'); 30632 await this.init(); 30633 this.initTexture(texture3); 30634 } 30635 /** 30636 * Initializes the given texture. Useful for preloading a texture rather than waiting until first render 30637 * (which can cause noticeable lags due to decode and GPU upload overhead). 30638 * 30639 * This method can only be used if the renderer has been initialized. 30640 * 30641 * @param {Texture} texture - The texture. 30642 */ 30643 initTexture(texture3) { 30644 if (this._initialized === false) { 30645 throw new Error('Renderer: .initTexture() called before the backend is initialized. Use "await renderer.init();" before before using this method.'); 30646 } 30647 this._textures.updateTexture(texture3); 30648 } 30649 /** 30650 * Initializes the given render target. 30651 * 30652 * @param {RenderTarget} renderTarget - The render target to intialize. 30653 */ 30654 initRenderTarget(renderTarget) { 30655 if (this._initialized === false) { 30656 throw new Error('Renderer: .initRenderTarget() called before the backend is initialized. Use "await renderer.init();" before before using this method.'); 30657 } 30658 this._textures.updateRenderTarget(renderTarget); 30659 const renderTargetData = this._textures.get(renderTarget); 30660 const renderContext = this._renderContexts.get(renderTarget); 30661 renderContext.textures = renderTargetData.textures; 30662 renderContext.depthTexture = renderTargetData.depthTexture; 30663 renderContext.width = renderTargetData.width; 30664 renderContext.height = renderTargetData.height; 30665 renderContext.renderTarget = renderTarget; 30666 renderContext.depth = renderTarget.depthBuffer; 30667 renderContext.stencil = renderTarget.stencilBuffer; 30668 this.backend.initRenderTarget(renderContext); 30669 } 30670 /** 30671 * Copies the current bound framebuffer into the given texture. 30672 * 30673 * @param {FramebufferTexture} framebufferTexture - The texture. 30674 * @param {?(Vector2|Vector4)} [rectangle=null] - A two or four dimensional vector that defines the rectangular portion of the framebuffer that should be copied. 30675 */ 30676 copyFramebufferToTexture(framebufferTexture, rectangle = null) { 30677 if (rectangle !== null) { 30678 if (rectangle.isVector2) { 30679 rectangle = _vector4.set(rectangle.x, rectangle.y, framebufferTexture.image.width, framebufferTexture.image.height).floor(); 30680 } else if (rectangle.isVector4) { 30681 rectangle = _vector4.copy(rectangle).floor(); 30682 } else { 30683 error("Renderer.copyFramebufferToTexture: Invalid rectangle."); 30684 return; 30685 } 30686 } else { 30687 rectangle = _vector4.set(0, 0, framebufferTexture.image.width, framebufferTexture.image.height); 30688 } 30689 let renderContext = this._currentRenderContext; 30690 let renderTarget; 30691 if (renderContext !== null) { 30692 renderTarget = renderContext.renderTarget; 30693 } else { 30694 renderTarget = this._renderTarget || this._getFrameBufferTarget(); 30695 if (renderTarget !== null) { 30696 this._textures.updateRenderTarget(renderTarget); 30697 renderContext = this._textures.get(renderTarget); 30698 } 30699 } 30700 this._textures.updateTexture(framebufferTexture, { renderTarget }); 30701 this.backend.copyFramebufferToTexture(framebufferTexture, renderContext, rectangle); 30702 this._inspector.copyFramebufferToTexture(framebufferTexture); 30703 } 30704 /** 30705 * Copies data of the given source texture into a destination texture. 30706 * 30707 * @param {Texture} srcTexture - The source texture. 30708 * @param {Texture} dstTexture - The destination texture. 30709 * @param {Box2|Box3} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional. 30710 * @param {Vector2|Vector3} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional. 30711 * @param {number} [srcLevel=0] - The source mip level to copy from. 30712 * @param {number} [dstLevel=0] - The destination mip level to copy to. 30713 */ 30714 copyTextureToTexture(srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0) { 30715 this._textures.updateTexture(srcTexture); 30716 this._textures.updateTexture(dstTexture); 30717 this.backend.copyTextureToTexture(srcTexture, dstTexture, srcRegion, dstPosition, srcLevel, dstLevel); 30718 this._inspector.copyTextureToTexture(srcTexture, dstTexture); 30719 } 30720 /** 30721 * Reads pixel data from the given render target. 30722 * 30723 * @async 30724 * @param {RenderTarget} renderTarget - The render target to read from. 30725 * @param {number} x - The `x` coordinate of the copy region's origin. 30726 * @param {number} y - The `y` coordinate of the copy region's origin. 30727 * @param {number} width - The width of the copy region. 30728 * @param {number} height - The height of the copy region. 30729 * @param {number} [textureIndex=0] - The texture index of a MRT render target. 30730 * @param {number} [faceIndex=0] - The active cube face index. 30731 * @return {Promise<TypedArray>} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. 30732 */ 30733 async readRenderTargetPixelsAsync(renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0) { 30734 return this.backend.copyTextureToBuffer(renderTarget.textures[textureIndex], x, y, width, height, faceIndex); 30735 } 30736 /** 30737 * Analyzes the given 3D object's hierarchy and builds render lists from the 30738 * processed hierarchy. 30739 * 30740 * @private 30741 * @param {Object3D} object - The 3D object to process (usually a scene). 30742 * @param {Camera} camera - The camera the object is rendered with. 30743 * @param {number} groupOrder - The group order is derived from the `renderOrder` of groups and is used to group 3D objects within groups. 30744 * @param {RenderList} renderList - The current render list. 30745 * @param {ClippingContext} clippingContext - The current clipping context. 30746 */ 30747 _projectObject(object, camera, groupOrder, renderList, clippingContext) { 30748 if (object.visible === false) return; 30749 const visible = object.layers.test(camera.layers); 30750 if (visible) { 30751 if (object.isGroup) { 30752 groupOrder = object.renderOrder; 30753 if (object.isClippingGroup && object.enabled) clippingContext = clippingContext.getGroupContext(object); 30754 } else if (object.isLOD) { 30755 if (object.autoUpdate === true) object.update(camera); 30756 } else if (object.isLight) { 30757 renderList.pushLight(object); 30758 } else if (object.isSprite) { 30759 const frustum = camera.isArrayCamera ? _frustumArray : _frustum; 30760 if (!object.frustumCulled || frustum.intersectsSprite(object, camera)) { 30761 if (this.sortObjects === true) { 30762 _vector4.setFromMatrixPosition(object.matrixWorld).applyMatrix4(_projScreenMatrix); 30763 } 30764 const { geometry, material } = object; 30765 if (material.visible) { 30766 renderList.push(object, geometry, material, groupOrder, _vector4.z, null, clippingContext); 30767 } 30768 } 30769 } else if (object.isLineLoop) { 30770 error("Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments."); 30771 } else if (object.isMesh || object.isLine || object.isPoints) { 30772 const frustum = camera.isArrayCamera ? _frustumArray : _frustum; 30773 if (!object.frustumCulled || frustum.intersectsObject(object, camera)) { 30774 const { geometry, material } = object; 30775 if (this.sortObjects === true) { 30776 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 30777 _vector4.copy(geometry.boundingSphere.center).applyMatrix4(object.matrixWorld).applyMatrix4(_projScreenMatrix); 30778 } 30779 if (Array.isArray(material)) { 30780 const groups = geometry.groups; 30781 for (let i = 0, l = groups.length; i < l; i++) { 30782 const group = groups[i]; 30783 const groupMaterial = material[group.materialIndex]; 30784 if (groupMaterial && groupMaterial.visible) { 30785 renderList.push(object, geometry, groupMaterial, groupOrder, _vector4.z, group, clippingContext); 30786 } 30787 } 30788 } else if (material.visible) { 30789 renderList.push(object, geometry, material, groupOrder, _vector4.z, null, clippingContext); 30790 } 30791 } 30792 } 30793 } 30794 if (object.isBundleGroup === true && this.backend.beginBundle !== void 0) { 30795 const baseRenderList = renderList; 30796 renderList = this._renderLists.get(object, camera); 30797 renderList.begin(); 30798 baseRenderList.pushBundle({ 30799 bundleGroup: object, 30800 camera, 30801 renderList 30802 }); 30803 renderList.finish(); 30804 } 30805 const children2 = object.children; 30806 for (let i = 0, l = children2.length; i < l; i++) { 30807 this._projectObject(children2[i], camera, groupOrder, renderList, clippingContext); 30808 } 30809 } 30810 /** 30811 * Renders the given render bundles. 30812 * 30813 * @private 30814 * @param {Array<Object>} bundles - Array with render bundle data. 30815 * @param {Scene} sceneRef - The scene the render bundles belong to. 30816 * @param {LightsNode} lightsNode - The current lights node. 30817 */ 30818 _renderBundles(bundles, sceneRef, lightsNode) { 30819 for (const bundle of bundles) { 30820 this._renderBundle(bundle, sceneRef, lightsNode); 30821 } 30822 } 30823 /** 30824 * Renders the transparent objects from the given render lists. 30825 * 30826 * @private 30827 * @param {Array<Object>} renderList - The transparent render list. 30828 * @param {Array<Object>} doublePassList - The list of transparent objects which require a double pass (e.g. because of transmission). 30829 * @param {Camera} camera - The camera the render list should be rendered with. 30830 * @param {Scene} scene - The scene the render list belongs to. 30831 * @param {LightsNode} lightsNode - The current lights node. 30832 */ 30833 _renderTransparents(renderList, doublePassList, camera, scene, lightsNode) { 30834 if (doublePassList.length > 0) { 30835 for (const { material } of doublePassList) { 30836 material.side = BackSide; 30837 } 30838 this._renderObjects(doublePassList, camera, scene, lightsNode, "backSide"); 30839 for (const { material } of doublePassList) { 30840 material.side = FrontSide; 30841 } 30842 this._renderObjects(renderList, camera, scene, lightsNode); 30843 for (const { material } of doublePassList) { 30844 material.side = DoubleSide; 30845 } 30846 } else { 30847 this._renderObjects(renderList, camera, scene, lightsNode); 30848 } 30849 } 30850 /** 30851 * Renders the objects from the given render list. 30852 * 30853 * @private 30854 * @param {Array<Object>} renderList - The render list. 30855 * @param {Camera} camera - The camera the render list should be rendered with. 30856 * @param {Scene} scene - The scene the render list belongs to. 30857 * @param {LightsNode} lightsNode - The current lights node. 30858 * @param {?string} [passId=null] - An optional ID for identifying the pass. 30859 */ 30860 _renderObjects(renderList, camera, scene, lightsNode, passId = null) { 30861 for (let i = 0, il = renderList.length; i < il; i++) { 30862 const { object, geometry, material, group, clippingContext } = renderList[i]; 30863 this._currentRenderObjectFunction(object, scene, camera, geometry, material, group, lightsNode, clippingContext, passId); 30864 } 30865 } 30866 /** 30867 * Retrieves shadow nodes for the given material. This is used to setup shadow passes. 30868 * The result is cached per material and updated when the material's version changes. 30869 * 30870 * @private 30871 * @param {Material} material 30872 * @returns {Object} - The shadow nodes for the material. 30873 */ 30874 _getShadowNodes(material) { 30875 const version = material.version; 30876 let cache4 = this._cacheShadowNodes.get(material); 30877 if (cache4 === void 0 || cache4.version !== version) { 30878 const hasMap = material.map !== null; 30879 const hasColorNode = material.colorNode && material.colorNode.isNode; 30880 const hasCastShadowNode = material.castShadowNode && material.castShadowNode.isNode; 30881 const hasMaskNode = material.maskShadowNode && material.maskShadowNode.isNode || material.maskNode && material.maskNode.isNode; 30882 let positionNode = null; 30883 let colorNode = null; 30884 let depthNode = null; 30885 if (hasMap || hasColorNode || hasCastShadowNode || hasMaskNode) { 30886 let shadowRGB; 30887 let shadowAlpha; 30888 if (hasCastShadowNode) { 30889 shadowRGB = material.castShadowNode.rgb; 30890 shadowAlpha = material.castShadowNode.a; 30891 if (this.shadowMap.transmitted !== true) { 30892 warnOnce("Renderer: `shadowMap.transmitted` needs to be set to `true` when using `material.castShadowNode`."); 30893 } 30894 } else { 30895 shadowRGB = vec3(0); 30896 shadowAlpha = float(1); 30897 } 30898 if (hasMap) { 30899 shadowAlpha = shadowAlpha.mul(reference("map", "texture", material).a); 30900 } 30901 if (hasColorNode) { 30902 shadowAlpha = shadowAlpha.mul(material.colorNode.a); 30903 } 30904 colorNode = vec4(shadowRGB, shadowAlpha); 30905 if (hasMaskNode) { 30906 const maskNode = material.maskShadowNode || material.maskNode; 30907 colorNode = Fn(([color3]) => { 30908 maskNode.not().discard(); 30909 return color3; 30910 })(colorNode); 30911 } 30912 } 30913 if (material.depthNode && material.depthNode.isNode) { 30914 depthNode = material.depthNode; 30915 } 30916 if (material.castShadowPositionNode && material.castShadowPositionNode.isNode) { 30917 positionNode = material.castShadowPositionNode; 30918 } else if (material.positionNode && material.positionNode.isNode) { 30919 positionNode = material.positionNode; 30920 } 30921 cache4 = { 30922 version, 30923 colorNode, 30924 depthNode, 30925 positionNode 30926 }; 30927 this._cacheShadowNodes.set(material, cache4); 30928 } 30929 return cache4; 30930 } 30931 /** 30932 * This method represents the default render object function that manages the render lifecycle 30933 * of the object. 30934 * 30935 * @param {Object3D} object - The 3D object. 30936 * @param {Scene} scene - The scene the 3D object belongs to. 30937 * @param {Camera} camera - The camera the object should be rendered with. 30938 * @param {BufferGeometry} geometry - The object's geometry. 30939 * @param {Material} material - The object's material. 30940 * @param {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 30941 * @param {LightsNode} lightsNode - The current lights node. 30942 * @param {?ClippingContext} clippingContext - The clipping context. 30943 * @param {?string} [passId=null] - An optional ID for identifying the pass. 30944 */ 30945 renderObject(object, scene, camera, geometry, material, group, lightsNode, clippingContext = null, passId = null) { 30946 let materialOverride = false; 30947 let materialColorNode; 30948 let materialDepthNode; 30949 let materialPositionNode; 30950 let materialSide; 30951 object.onBeforeRender(this, scene, camera, geometry, material, group); 30952 if (material.allowOverride === true && scene.overrideMaterial !== null) { 30953 const overrideMaterial = scene.overrideMaterial; 30954 materialOverride = true; 30955 materialColorNode = overrideMaterial.isNodeMaterial ? overrideMaterial.colorNode : null; 30956 materialDepthNode = overrideMaterial.isNodeMaterial ? overrideMaterial.depthNode : null; 30957 materialPositionNode = overrideMaterial.isNodeMaterial ? overrideMaterial.positionNode : null; 30958 materialSide = scene.overrideMaterial.side; 30959 if (material.positionNode && material.positionNode.isNode) { 30960 overrideMaterial.positionNode = material.positionNode; 30961 } 30962 overrideMaterial.alphaTest = material.alphaTest; 30963 overrideMaterial.alphaMap = material.alphaMap; 30964 overrideMaterial.transparent = material.transparent || material.transmission > 0 || material.transmissionNode && material.transmissionNode.isNode || material.backdropNode && material.backdropNode.isNode; 30965 if (overrideMaterial.isShadowPassMaterial) { 30966 const { colorNode, depthNode, positionNode } = this._getShadowNodes(material); 30967 if (this.shadowMap.type === VSMShadowMap) { 30968 overrideMaterial.side = material.shadowSide !== null ? material.shadowSide : material.side; 30969 } else { 30970 overrideMaterial.side = material.shadowSide !== null ? material.shadowSide : _shadowSide[material.side]; 30971 } 30972 if (colorNode !== null) overrideMaterial.colorNode = colorNode; 30973 if (depthNode !== null) overrideMaterial.depthNode = depthNode; 30974 if (positionNode !== null) overrideMaterial.positionNode = positionNode; 30975 } 30976 material = overrideMaterial; 30977 } 30978 if (material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false) { 30979 material.side = BackSide; 30980 this._handleObjectFunction(object, material, scene, camera, lightsNode, group, clippingContext, "backSide"); 30981 material.side = FrontSide; 30982 this._handleObjectFunction(object, material, scene, camera, lightsNode, group, clippingContext, passId); 30983 material.side = DoubleSide; 30984 } else { 30985 this._handleObjectFunction(object, material, scene, camera, lightsNode, group, clippingContext, passId); 30986 } 30987 if (materialOverride) { 30988 scene.overrideMaterial.colorNode = materialColorNode; 30989 scene.overrideMaterial.depthNode = materialDepthNode; 30990 scene.overrideMaterial.positionNode = materialPositionNode; 30991 scene.overrideMaterial.side = materialSide; 30992 } 30993 object.onAfterRender(this, scene, camera, geometry, material, group); 30994 } 30995 /** 30996 * Checks if the given compatibility is supported by the selected backend. 30997 * 30998 * @param {string} name - The compatibility's name. 30999 * @return {boolean} Whether the compatibility is supported or not. 31000 */ 31001 hasCompatibility(name) { 31002 if (this._initialized === false) { 31003 throw new Error('Renderer: .hasCompatibility() called before the backend is initialized. Use "await renderer.init();" before using this method.'); 31004 } 31005 return this.backend.hasCompatibility(name); 31006 } 31007 /** 31008 * This method represents the default `_handleObjectFunction` implementation which creates 31009 * a render object from the given data and performs the draw command with the selected backend. 31010 * 31011 * @private 31012 * @param {Object3D} object - The 3D object. 31013 * @param {Material} material - The object's material. 31014 * @param {Scene} scene - The scene the 3D object belongs to. 31015 * @param {Camera} camera - The camera the object should be rendered with. 31016 * @param {LightsNode} lightsNode - The current lights node. 31017 * @param {?{start: number, count: number}} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 31018 * @param {ClippingContext} clippingContext - The clipping context. 31019 * @param {string} [passId] - An optional ID for identifying the pass. 31020 */ 31021 _renderObjectDirect(object, material, scene, camera, lightsNode, group, clippingContext, passId) { 31022 const renderObject = this._objects.get(object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId); 31023 renderObject.drawRange = object.geometry.drawRange; 31024 renderObject.group = group; 31025 if (this._currentRenderBundle !== null) { 31026 const renderBundleData = this.backend.get(this._currentRenderBundle); 31027 renderBundleData.renderObjects.push(renderObject); 31028 renderObject.bundle = this._currentRenderBundle.bundleGroup; 31029 } 31030 const needsRefresh = this._nodes.needsRefresh(renderObject); 31031 if (needsRefresh) { 31032 this._nodes.updateBefore(renderObject); 31033 this._geometries.updateForRender(renderObject); 31034 this._nodes.updateForRender(renderObject); 31035 this._bindings.updateForRender(renderObject); 31036 } 31037 this._pipelines.updateForRender(renderObject); 31038 if (this._pipelines.isReady(renderObject)) { 31039 this.backend.draw(renderObject, this.info); 31040 if (needsRefresh) this._nodes.updateAfter(renderObject); 31041 } 31042 } 31043 /** 31044 * A different implementation for `_handleObjectFunction` which only makes sure the object is ready for rendering. 31045 * Used in `compileAsync()`. 31046 * 31047 * @private 31048 * @param {Object3D} object - The 3D object. 31049 * @param {Material} material - The object's material. 31050 * @param {Scene} scene - The scene the 3D object belongs to. 31051 * @param {Camera} camera - The camera the object should be rendered with. 31052 * @param {LightsNode} lightsNode - The current lights node. 31053 * @param {?{start: number, count: number}} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. 31054 * @param {ClippingContext} clippingContext - The clipping context. 31055 * @param {string} [passId] - An optional ID for identifying the pass. 31056 */ 31057 _createObjectPipeline(object, material, scene, camera, lightsNode, group, clippingContext, passId) { 31058 if (this._compilationPromises !== null) { 31059 this._compilationPromises.push({ 31060 object, 31061 material, 31062 scene, 31063 camera, 31064 lightsNode, 31065 group, 31066 clippingContext, 31067 passId, 31068 renderContext: this._currentRenderContext 31069 }); 31070 return; 31071 } 31072 const renderObject = this._objects.get(object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId); 31073 renderObject.drawRange = object.geometry.drawRange; 31074 renderObject.group = group; 31075 this._nodes.updateBefore(renderObject); 31076 this._geometries.updateForRender(renderObject); 31077 this._nodes.updateForRender(renderObject); 31078 this._bindings.updateForRender(renderObject); 31079 this._pipelines.getForRender(renderObject, this._compilationPromises); 31080 this._nodes.updateAfter(renderObject); 31081 } 31082 /** 31083 * Callback when the canvas has been resized. 31084 * 31085 * @private 31086 */ 31087 _onCanvasTargetResize() { 31088 if (this._initialized) this.backend.updateSize(); 31089 } 31090 /** 31091 * Alias for `compileAsync()`. 31092 * 31093 * @method 31094 * @param {Object3D} scene - The scene or 3D object to precompile. 31095 * @param {Camera} camera - The camera that is used to render the scene. 31096 * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. 31097 * @return {function(Object3D, Camera, ?Scene): Promise|undefined} A Promise that resolves when the compile has been finished. 31098 */ 31099 get compile() { 31100 return this.compileAsync; 31101 } 31102}; 31103var Binding = class { 31104 /** 31105 * Constructs a new binding. 31106 * 31107 * @param {string} [name=''] - The binding's name. 31108 */ 31109 constructor(name = "") { 31110 this.name = name; 31111 this.visibility = 0; 31112 } 31113 /** 31114 * Makes sure binding's resource is visible for the given shader stage. 31115 * 31116 * @param {number} visibility - The shader stage. 31117 */ 31118 setVisibility(visibility) { 31119 this.visibility |= visibility; 31120 } 31121 /** 31122 * The shader stages in which the binding's resource is visible. 31123 * 31124 * @return {number} The visibility bitmask. 31125 */ 31126 getVisibility() { 31127 return this.visibility; 31128 } 31129 /** 31130 * Clones the binding. 31131 * 31132 * @return {Binding} The cloned binding. 31133 */ 31134 clone() { 31135 return Object.assign(new this.constructor(), this); 31136 } 31137}; 31138function getFloatLength(floatLength) { 31139 return floatLength + (GPU_CHUNK_BYTES - floatLength % GPU_CHUNK_BYTES) % GPU_CHUNK_BYTES; 31140} 31141var Buffer = class extends Binding { 31142 /** 31143 * Constructs a new buffer. 31144 * 31145 * @param {string} name - The buffer's name. 31146 * @param {TypedArray} [buffer=null] - The buffer. 31147 */ 31148 constructor(name, buffer3 = null) { 31149 super(name); 31150 this.isBuffer = true; 31151 this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT; 31152 this._buffer = buffer3; 31153 this._updateRanges = []; 31154 } 31155 /** 31156 * The array of update ranges. 31157 * 31158 * @type {Array<{start: number, count: number}>} 31159 */ 31160 get updateRanges() { 31161 return this._updateRanges; 31162 } 31163 /** 31164 * Adds an update range. 31165 * 31166 * @param {number} start - The start index. 31167 * @param {number} count - The number of elements. 31168 */ 31169 addUpdateRange(start, count) { 31170 this.updateRanges.push({ start, count }); 31171 } 31172 /** 31173 * Clears all update ranges. 31174 */ 31175 clearUpdateRanges() { 31176 this.updateRanges.length = 0; 31177 } 31178 /** 31179 * The buffer's byte length. 31180 * 31181 * @type {number} 31182 * @readonly 31183 */ 31184 get byteLength() { 31185 return getFloatLength(this._buffer.byteLength); 31186 } 31187 /** 31188 * A reference to the internal buffer. 31189 * 31190 * @type {Float32Array} 31191 * @readonly 31192 */ 31193 get buffer() { 31194 return this._buffer; 31195 } 31196 /** 31197 * Updates the binding. 31198 * 31199 * @return {boolean} Whether the buffer has been updated and must be 31200 * uploaded to the GPU. 31201 */ 31202 update() { 31203 return true; 31204 } 31205}; 31206var UniformBuffer = class extends Buffer { 31207 /** 31208 * Constructs a new uniform buffer. 31209 * 31210 * @param {string} name - The buffer's name. 31211 * @param {TypedArray} [buffer=null] - The buffer. 31212 */ 31213 constructor(name, buffer3 = null) { 31214 super(name, buffer3); 31215 this.isUniformBuffer = true; 31216 } 31217}; 31218var _id$4 = 0; 31219var NodeUniformBuffer = class extends UniformBuffer { 31220 /** 31221 * Constructs a new node-based uniform buffer. 31222 * 31223 * @param {BufferNode} nodeUniform - The uniform buffer node. 31224 * @param {UniformGroupNode} groupNode - The uniform group node. 31225 */ 31226 constructor(nodeUniform, groupNode) { 31227 super("UniformBuffer_" + _id$4++, nodeUniform ? nodeUniform.value : null); 31228 this.nodeUniform = nodeUniform; 31229 this.groupNode = groupNode; 31230 this.isNodeUniformBuffer = true; 31231 } 31232 /** 31233 * The array of update ranges. 31234 * 31235 * @param {Array<{start: number, count: number}>} value - The update ranges. 31236 */ 31237 set updateRanges(value) { 31238 this.nodeUniform.updateRanges = value; 31239 } 31240 /** 31241 * The array of update ranges. 31242 * 31243 * @type {Array<{start: number, count: number}>} 31244 */ 31245 get updateRanges() { 31246 return this.nodeUniform.updateRanges; 31247 } 31248 /** 31249 * Adds a range of data in the data array to be updated on the GPU. 31250 * 31251 * @param {number} start - Position at which to start update. 31252 * @param {number} count - The number of components to update. 31253 */ 31254 addUpdateRange(start, count) { 31255 this.nodeUniform.addUpdateRange(start, count); 31256 } 31257 /** 31258 * Clears all update ranges. 31259 */ 31260 clearUpdateRanges() { 31261 this.nodeUniform.clearUpdateRanges(); 31262 } 31263 /** 31264 * The uniform buffer. 31265 * 31266 * @type {Float32Array} 31267 */ 31268 get buffer() { 31269 return this.nodeUniform.value; 31270 } 31271}; 31272var UniformsGroup2 = class extends UniformBuffer { 31273 /** 31274 * Constructs a new uniforms group. 31275 * 31276 * @param {string} name - The group's name. 31277 */ 31278 constructor(name) { 31279 super(name); 31280 this.isUniformsGroup = true; 31281 this._values = null; 31282 this.uniforms = []; 31283 this._updateRangeCache = /* @__PURE__ */ new Map(); 31284 } 31285 /** 31286 * Adds a uniform's update range to this buffer. 31287 * 31288 * @param {Uniform} uniform - The uniform. 31289 */ 31290 addUniformUpdateRange(uniform3) { 31291 const index = uniform3.index; 31292 if (this._updateRangeCache.has(index) !== true) { 31293 const updateRanges = this.updateRanges; 31294 const start = uniform3.offset; 31295 const count = uniform3.itemSize; 31296 const range3 = { start, count }; 31297 updateRanges.push(range3); 31298 this._updateRangeCache.set(index, range3); 31299 } 31300 } 31301 /** 31302 * Clears all update ranges of this buffer. 31303 */ 31304 clearUpdateRanges() { 31305 this._updateRangeCache.clear(); 31306 super.clearUpdateRanges(); 31307 } 31308 /** 31309 * Adds a uniform to this group. 31310 * 31311 * @param {Uniform} uniform - The uniform to add. 31312 * @return {UniformsGroup} A reference to this group. 31313 */ 31314 addUniform(uniform3) { 31315 this.uniforms.push(uniform3); 31316 return this; 31317 } 31318 /** 31319 * Removes a uniform from this group. 31320 * 31321 * @param {Uniform} uniform - The uniform to remove. 31322 * @return {UniformsGroup} A reference to this group. 31323 */ 31324 removeUniform(uniform3) { 31325 const index = this.uniforms.indexOf(uniform3); 31326 if (index !== -1) { 31327 this.uniforms.splice(index, 1); 31328 } 31329 return this; 31330 } 31331 /** 31332 * An array with the raw uniform values. 31333 * 31334 * @type {Array<number>} 31335 */ 31336 get values() { 31337 if (this._values === null) { 31338 this._values = Array.from(this.buffer); 31339 } 31340 return this._values; 31341 } 31342 /** 31343 * A Float32 array buffer with the uniform values. 31344 * 31345 * @type {Float32Array} 31346 */ 31347 get buffer() { 31348 let buffer3 = this._buffer; 31349 if (buffer3 === null) { 31350 const byteLength = this.byteLength; 31351 buffer3 = new Float32Array(new ArrayBuffer(byteLength)); 31352 this._buffer = buffer3; 31353 } 31354 return buffer3; 31355 } 31356 /** 31357 * The byte length of the buffer with correct buffer alignment. 31358 * 31359 * @type {number} 31360 */ 31361 get byteLength() { 31362 const bytesPerElement = this.bytesPerElement; 31363 let offset3 = 0; 31364 for (let i = 0, l = this.uniforms.length; i < l; i++) { 31365 const uniform3 = this.uniforms[i]; 31366 const boundary = uniform3.boundary; 31367 const itemSize = uniform3.itemSize * bytesPerElement; 31368 const chunkOffset = offset3 % GPU_CHUNK_BYTES; 31369 const chunkPadding = chunkOffset % boundary; 31370 const chunkStart = chunkOffset + chunkPadding; 31371 offset3 += chunkPadding; 31372 if (chunkStart !== 0 && GPU_CHUNK_BYTES - chunkStart < itemSize) { 31373 offset3 += GPU_CHUNK_BYTES - chunkStart; 31374 } 31375 uniform3.offset = offset3 / bytesPerElement; 31376 uniform3.index = i; 31377 offset3 += itemSize; 31378 } 31379 return Math.ceil(offset3 / GPU_CHUNK_BYTES) * GPU_CHUNK_BYTES; 31380 } 31381 /** 31382 * Updates this group by updating each uniform object of 31383 * the internal uniform list. The uniform objects check if their 31384 * values has actually changed so this method only returns 31385 * `true` if there is a real value change. 31386 * 31387 * @return {boolean} Whether the uniforms have been updated and 31388 * must be uploaded to the GPU. 31389 */ 31390 update() { 31391 let updated = false; 31392 for (const uniform3 of this.uniforms) { 31393 if (this.updateByType(uniform3) === true) { 31394 updated = true; 31395 } 31396 } 31397 return updated; 31398 } 31399 /** 31400 * Updates a given uniform by calling an update method matching 31401 * the uniforms type. 31402 * 31403 * @param {Uniform} uniform - The uniform to update. 31404 * @return {boolean} Whether the uniform has been updated or not. 31405 */ 31406 updateByType(uniform3) { 31407 if (uniform3.isNumberUniform) return this.updateNumber(uniform3); 31408 if (uniform3.isVector2Uniform) return this.updateVector2(uniform3); 31409 if (uniform3.isVector3Uniform) return this.updateVector3(uniform3); 31410 if (uniform3.isVector4Uniform) return this.updateVector4(uniform3); 31411 if (uniform3.isColorUniform) return this.updateColor(uniform3); 31412 if (uniform3.isMatrix3Uniform) return this.updateMatrix3(uniform3); 31413 if (uniform3.isMatrix4Uniform) return this.updateMatrix4(uniform3); 31414 error("WebGPUUniformsGroup: Unsupported uniform type.", uniform3); 31415 } 31416 /** 31417 * Updates a given Number uniform. 31418 * 31419 * @param {NumberUniform} uniform - The Number uniform. 31420 * @return {boolean} Whether the uniform has been updated or not. 31421 */ 31422 updateNumber(uniform3) { 31423 let updated = false; 31424 const a = this.values; 31425 const v = uniform3.getValue(); 31426 const offset3 = uniform3.offset; 31427 const type = uniform3.getType(); 31428 if (a[offset3] !== v) { 31429 const b = this._getBufferForType(type); 31430 b[offset3] = a[offset3] = v; 31431 updated = true; 31432 this.addUniformUpdateRange(uniform3); 31433 } 31434 return updated; 31435 } 31436 /** 31437 * Updates a given Vector2 uniform. 31438 * 31439 * @param {Vector2Uniform} uniform - The Vector2 uniform. 31440 * @return {boolean} Whether the uniform has been updated or not. 31441 */ 31442 updateVector2(uniform3) { 31443 let updated = false; 31444 const a = this.values; 31445 const v = uniform3.getValue(); 31446 const offset3 = uniform3.offset; 31447 const type = uniform3.getType(); 31448 if (a[offset3 + 0] !== v.x || a[offset3 + 1] !== v.y) { 31449 const b = this._getBufferForType(type); 31450 b[offset3 + 0] = a[offset3 + 0] = v.x; 31451 b[offset3 + 1] = a[offset3 + 1] = v.y; 31452 updated = true; 31453 this.addUniformUpdateRange(uniform3); 31454 } 31455 return updated; 31456 } 31457 /** 31458 * Updates a given Vector3 uniform. 31459 * 31460 * @param {Vector3Uniform} uniform - The Vector3 uniform. 31461 * @return {boolean} Whether the uniform has been updated or not. 31462 */ 31463 updateVector3(uniform3) { 31464 let updated = false; 31465 const a = this.values; 31466 const v = uniform3.getValue(); 31467 const offset3 = uniform3.offset; 31468 const type = uniform3.getType(); 31469 if (a[offset3 + 0] !== v.x || a[offset3 + 1] !== v.y || a[offset3 + 2] !== v.z) { 31470 const b = this._getBufferForType(type); 31471 b[offset3 + 0] = a[offset3 + 0] = v.x; 31472 b[offset3 + 1] = a[offset3 + 1] = v.y; 31473 b[offset3 + 2] = a[offset3 + 2] = v.z; 31474 updated = true; 31475 this.addUniformUpdateRange(uniform3); 31476 } 31477 return updated; 31478 } 31479 /** 31480 * Updates a given Vector4 uniform. 31481 * 31482 * @param {Vector4Uniform} uniform - The Vector4 uniform. 31483 * @return {boolean} Whether the uniform has been updated or not. 31484 */ 31485 updateVector4(uniform3) { 31486 let updated = false; 31487 const a = this.values; 31488 const v = uniform3.getValue(); 31489 const offset3 = uniform3.offset; 31490 const type = uniform3.getType(); 31491 if (a[offset3 + 0] !== v.x || a[offset3 + 1] !== v.y || a[offset3 + 2] !== v.z || a[offset3 + 3] !== v.w) { 31492 const b = this._getBufferForType(type); 31493 b[offset3 + 0] = a[offset3 + 0] = v.x; 31494 b[offset3 + 1] = a[offset3 + 1] = v.y; 31495 b[offset3 + 2] = a[offset3 + 2] = v.z; 31496 b[offset3 + 3] = a[offset3 + 3] = v.w; 31497 updated = true; 31498 this.addUniformUpdateRange(uniform3); 31499 } 31500 return updated; 31501 } 31502 /** 31503 * Updates a given Color uniform. 31504 * 31505 * @param {ColorUniform} uniform - The Color uniform. 31506 * @return {boolean} Whether the uniform has been updated or not. 31507 */ 31508 updateColor(uniform3) { 31509 let updated = false; 31510 const a = this.values; 31511 const c = uniform3.getValue(); 31512 const offset3 = uniform3.offset; 31513 if (a[offset3 + 0] !== c.r || a[offset3 + 1] !== c.g || a[offset3 + 2] !== c.b) { 31514 const b = this.buffer; 31515 b[offset3 + 0] = a[offset3 + 0] = c.r; 31516 b[offset3 + 1] = a[offset3 + 1] = c.g; 31517 b[offset3 + 2] = a[offset3 + 2] = c.b; 31518 updated = true; 31519 this.addUniformUpdateRange(uniform3); 31520 } 31521 return updated; 31522 } 31523 /** 31524 * Updates a given Matrix3 uniform. 31525 * 31526 * @param {Matrix3Uniform} uniform - The Matrix3 uniform. 31527 * @return {boolean} Whether the uniform has been updated or not. 31528 */ 31529 updateMatrix3(uniform3) { 31530 let updated = false; 31531 const a = this.values; 31532 const e = uniform3.getValue().elements; 31533 const offset3 = uniform3.offset; 31534 if (a[offset3 + 0] !== e[0] || a[offset3 + 1] !== e[1] || a[offset3 + 2] !== e[2] || a[offset3 + 4] !== e[3] || a[offset3 + 5] !== e[4] || a[offset3 + 6] !== e[5] || a[offset3 + 8] !== e[6] || a[offset3 + 9] !== e[7] || a[offset3 + 10] !== e[8]) { 31535 const b = this.buffer; 31536 b[offset3 + 0] = a[offset3 + 0] = e[0]; 31537 b[offset3 + 1] = a[offset3 + 1] = e[1]; 31538 b[offset3 + 2] = a[offset3 + 2] = e[2]; 31539 b[offset3 + 4] = a[offset3 + 4] = e[3]; 31540 b[offset3 + 5] = a[offset3 + 5] = e[4]; 31541 b[offset3 + 6] = a[offset3 + 6] = e[5]; 31542 b[offset3 + 8] = a[offset3 + 8] = e[6]; 31543 b[offset3 + 9] = a[offset3 + 9] = e[7]; 31544 b[offset3 + 10] = a[offset3 + 10] = e[8]; 31545 updated = true; 31546 this.addUniformUpdateRange(uniform3); 31547 } 31548 return updated; 31549 } 31550 /** 31551 * Updates a given Matrix4 uniform. 31552 * 31553 * @param {Matrix4Uniform} uniform - The Matrix4 uniform. 31554 * @return {boolean} Whether the uniform has been updated or not. 31555 */ 31556 updateMatrix4(uniform3) { 31557 let updated = false; 31558 const a = this.values; 31559 const e = uniform3.getValue().elements; 31560 const offset3 = uniform3.offset; 31561 if (arraysEqual(a, e, offset3) === false) { 31562 const b = this.buffer; 31563 b.set(e, offset3); 31564 setArray(a, e, offset3); 31565 updated = true; 31566 this.addUniformUpdateRange(uniform3); 31567 } 31568 return updated; 31569 } 31570 /** 31571 * Returns a typed array that matches the given data type. 31572 * 31573 * @private 31574 * @param {string} type - The data type. 31575 * @return {TypedArray} The typed array. 31576 */ 31577 _getBufferForType(type) { 31578 if (type === "int" || type === "ivec2" || type === "ivec3" || type === "ivec4") return new Int32Array(this.buffer.buffer); 31579 if (type === "uint" || type === "uvec2" || type === "uvec3" || type === "uvec4") return new Uint32Array(this.buffer.buffer); 31580 return this.buffer; 31581 } 31582}; 31583function setArray(a, b, offset3) { 31584 for (let i = 0, l = b.length; i < l; i++) { 31585 a[offset3 + i] = b[i]; 31586 } 31587} 31588function arraysEqual(a, b, offset3) { 31589 for (let i = 0, l = b.length; i < l; i++) { 31590 if (a[offset3 + i] !== b[i]) return false; 31591 } 31592 return true; 31593} 31594var _id$3 = 0; 31595var NodeUniformsGroup = class extends UniformsGroup2 { 31596 /** 31597 * Constructs a new node-based uniforms group. 31598 * 31599 * @param {string} name - The group's name. 31600 * @param {UniformGroupNode} groupNode - The uniform group node. 31601 */ 31602 constructor(name, groupNode) { 31603 super(name); 31604 this.id = _id$3++; 31605 this.groupNode = groupNode; 31606 this.isNodeUniformsGroup = true; 31607 } 31608}; 31609var Sampler = class extends Binding { 31610 /** 31611 * Constructs a new sampler. 31612 * 31613 * @param {string} name - The samplers's name. 31614 * @param {?Texture} texture - The texture this binding is referring to. 31615 */ 31616 constructor(name, texture3) { 31617 super(name); 31618 this._texture = null; 31619 this._onTextureDispose = () => { 31620 this.generation = null; 31621 this.version = -1; 31622 }; 31623 this.texture = texture3; 31624 this.version = texture3 ? texture3.version : -1; 31625 this.generation = null; 31626 this.samplerKey = ""; 31627 this.isSampler = true; 31628 } 31629 /** 31630 * Sets the texture of this sampler. 31631 * 31632 * @param {Texture} value - The texture to set. 31633 */ 31634 set texture(value) { 31635 if (this._texture === value) return; 31636 if (this._texture) { 31637 this._texture.removeEventListener("dispose", this._onTextureDispose); 31638 } 31639 this._texture = value; 31640 this.generation = null; 31641 this.version = -1; 31642 if (this._texture) { 31643 this._texture.addEventListener("dispose", this._onTextureDispose); 31644 } 31645 } 31646 /** 31647 * Gets the texture of this sampler. 31648 * @return {?Texture} The texture. 31649 */ 31650 get texture() { 31651 return this._texture; 31652 } 31653 /** 31654 * Updates the binding. 31655 * 31656 * @return {boolean} Whether the texture has been updated and must be 31657 * uploaded to the GPU. 31658 */ 31659 update() { 31660 const { texture: texture3, version } = this; 31661 if (version !== texture3.version) { 31662 this.version = texture3.version; 31663 return true; 31664 } 31665 return false; 31666 } 31667 clone() { 31668 const clonedSampler = super.clone(); 31669 clonedSampler._texture = null; 31670 clonedSampler._onTextureDispose = () => { 31671 clonedSampler.generation = null; 31672 clonedSampler.version = -1; 31673 }; 31674 clonedSampler.texture = this.texture; 31675 return clonedSampler; 31676 } 31677}; 31678var _id$2 = 0; 31679var SampledTexture = class extends Sampler { 31680 /** 31681 * Constructs a new sampled texture. 31682 * 31683 * @param {string} name - The sampled texture's name. 31684 * @param {?Texture} texture - The texture this binding is referring to. 31685 */ 31686 constructor(name, texture3) { 31687 super(name, texture3); 31688 this.id = _id$2++; 31689 this.store = false; 31690 this.mipLevel = 0; 31691 this.isSampledTexture = true; 31692 } 31693}; 31694var NodeSampledTexture = class extends SampledTexture { 31695 /** 31696 * Constructs a new node-based sampled texture. 31697 * 31698 * @param {string} name - The textures's name. 31699 * @param {TextureNode} textureNode - The texture node. 31700 * @param {UniformGroupNode} groupNode - The uniform group node. 31701 * @param {?string} [access=null] - The access type. 31702 */ 31703 constructor(name, textureNode, groupNode, access6 = null) { 31704 super(name, textureNode ? textureNode.value : null); 31705 this.textureNode = textureNode; 31706 this.groupNode = groupNode; 31707 this.access = access6; 31708 } 31709 /** 31710 * Updates the binding. 31711 * 31712 * @return {boolean} Whether the texture has been updated and must be 31713 * uploaded to the GPU. 31714 */ 31715 update() { 31716 const { textureNode } = this; 31717 if (this.texture !== textureNode.value) { 31718 this.texture = textureNode.value; 31719 return true; 31720 } 31721 return super.update(); 31722 } 31723}; 31724var NodeSampledCubeTexture = class extends NodeSampledTexture { 31725 /** 31726 * Constructs a new node-based sampled cube texture. 31727 * 31728 * @param {string} name - The textures's name. 31729 * @param {TextureNode} textureNode - The texture node. 31730 * @param {UniformGroupNode} groupNode - The uniform group node. 31731 * @param {?string} [access=null] - The access type. 31732 */ 31733 constructor(name, textureNode, groupNode, access6 = null) { 31734 super(name, textureNode, groupNode, access6); 31735 this.isSampledCubeTexture = true; 31736 } 31737}; 31738var NodeSampledTexture3D = class extends NodeSampledTexture { 31739 /** 31740 * Constructs a new node-based sampled 3D texture. 31741 * 31742 * @param {string} name - The textures's name. 31743 * @param {TextureNode} textureNode - The texture node. 31744 * @param {UniformGroupNode} groupNode - The uniform group node. 31745 * @param {?string} [access=null] - The access type. 31746 */ 31747 constructor(name, textureNode, groupNode, access6 = null) { 31748 super(name, textureNode, groupNode, access6); 31749 this.isSampledTexture3D = true; 31750 } 31751}; 31752var glslPolyfills = { 31753 bitcast_int_uint: new CodeNode( 31754 /* glsl */ 31755 "uint tsl_bitcast_int_to_uint ( int x ) { return floatBitsToUint( intBitsToFloat ( x ) ); }" 31756 ), 31757 bitcast_uint_int: new CodeNode( 31758 /* glsl */ 31759 "uint tsl_bitcast_uint_to_int ( uint x ) { return floatBitsToInt( uintBitsToFloat ( x ) ); }" 31760 ) 31761}; 31762var glslMethods = { 31763 textureDimensions: "textureSize", 31764 equals: "equal", 31765 bitcast_float_int: "floatBitsToInt", 31766 bitcast_int_float: "intBitsToFloat", 31767 bitcast_uint_float: "uintBitsToFloat", 31768 bitcast_float_uint: "floatBitsToUint", 31769 bitcast_uint_int: "tsl_bitcast_uint_to_int", 31770 bitcast_int_uint: "tsl_bitcast_int_to_uint", 31771 floatpack_snorm_2x16: "packSnorm2x16", 31772 floatpack_unorm_2x16: "packUnorm2x16", 31773 floatpack_float16_2x16: "packHalf2x16", 31774 floatunpack_snorm_2x16: "unpackSnorm2x16", 31775 floatunpack_unorm_2x16: "unpackUnorm2x16", 31776 floatunpack_float16_2x16: "unpackHalf2x16" 31777}; 31778var precisionLib = { 31779 low: "lowp", 31780 medium: "mediump", 31781 high: "highp" 31782}; 31783var supports$1 = { 31784 swizzleAssign: true, 31785 storageBuffer: false 31786}; 31787var interpolationTypeMap = { 31788 perspective: "smooth", 31789 linear: "noperspective" 31790}; 31791var interpolationModeMap = { 31792 "centroid": "centroid" 31793}; 31794var defaultPrecisions = ` 31795precision highp float; 31796precision highp int; 31797precision highp sampler2D; 31798precision highp sampler3D; 31799precision highp samplerCube; 31800precision highp sampler2DArray; 31801 31802precision highp usampler2D; 31803precision highp usampler3D; 31804precision highp usamplerCube; 31805precision highp usampler2DArray; 31806 31807precision highp isampler2D; 31808precision highp isampler3D; 31809precision highp isamplerCube; 31810precision highp isampler2DArray; 31811 31812precision highp sampler2DShadow; 31813precision highp sampler2DArrayShadow; 31814precision highp samplerCubeShadow; 31815`; 31816var GLSLNodeBuilder = class extends NodeBuilder { 31817 /** 31818 * Constructs a new GLSL node builder renderer. 31819 * 31820 * @param {Object3D} object - The 3D object. 31821 * @param {Renderer} renderer - The renderer. 31822 */ 31823 constructor(object, renderer) { 31824 super(object, renderer, new GLSLNodeParser()); 31825 this.uniformGroups = {}; 31826 this.transforms = []; 31827 this.extensions = {}; 31828 this.builtins = { vertex: [], fragment: [], compute: [] }; 31829 } 31830 /** 31831 * Checks if the given texture requires a manual conversion to the working color space. 31832 * 31833 * @param {Texture} texture - The texture to check. 31834 * @return {boolean} Whether the given texture requires a conversion to working color space or not. 31835 */ 31836 needsToWorkingColorSpace(texture3) { 31837 return texture3.isVideoTexture === true && texture3.colorSpace !== NoColorSpace; 31838 } 31839 /** 31840 * Includes the given method name into the current 31841 * function node. 31842 * 31843 * @private 31844 * @param {string} name - The method name to include. 31845 * @return {CodeNode} The respective code node. 31846 */ 31847 _include(name) { 31848 const codeNode = glslPolyfills[name]; 31849 codeNode.build(this); 31850 this.addInclude(codeNode); 31851 return codeNode; 31852 } 31853 /** 31854 * Returns the native shader method name for a given generic name. 31855 * 31856 * @param {string} method - The method name to resolve. 31857 * @return {string} The resolved GLSL method name. 31858 */ 31859 getMethod(method) { 31860 if (glslPolyfills[method] !== void 0) { 31861 this._include(method); 31862 } 31863 return glslMethods[method] || method; 31864 } 31865 /** 31866 * Returns the bitcast method name for a given input and outputType. 31867 * 31868 * @param {string} type - The output type to bitcast to. 31869 * @param {string} inputType - The input type of the. 31870 * @return {string} The resolved WGSL bitcast invocation. 31871 */ 31872 getBitcastMethod(type, inputType) { 31873 return this.getMethod(`bitcast_${inputType}_${type}`); 31874 } 31875 /** 31876 * Returns the float packing method name for a given numeric encoding. 31877 * 31878 * @param {string} encoding - The numeric encoding that describes how the float values are mapped to the integer range. 31879 * @returns {string} The resolved GLSL float packing method name. 31880 */ 31881 getFloatPackingMethod(encoding) { 31882 return this.getMethod(`floatpack_${encoding}_2x16`); 31883 } 31884 /** 31885 * Returns the float unpacking method name for a given numeric encoding. 31886 * 31887 * @param {string} encoding - The numeric encoding that describes how the integer values are mapped to the float range. 31888 * @returns {string} The resolved GLSL float unpacking method name. 31889 */ 31890 getFloatUnpackingMethod(encoding) { 31891 return this.getMethod(`floatunpack_${encoding}_2x16`); 31892 } 31893 /** 31894 * Returns the native snippet for a ternary operation. 31895 * 31896 * @param {string} condSnippet - The condition determining which expression gets resolved. 31897 * @param {string} ifSnippet - The expression to resolve to if the condition is true. 31898 * @param {string} elseSnippet - The expression to resolve to if the condition is false. 31899 * @return {string} The resolved method name. 31900 */ 31901 getTernary(condSnippet, ifSnippet, elseSnippet) { 31902 return `${condSnippet} ? ${ifSnippet} : ${elseSnippet}`; 31903 } 31904 /** 31905 * Returns the output struct name. Not relevant for GLSL. 31906 * 31907 * @return {string} 31908 */ 31909 getOutputStructName() { 31910 return ""; 31911 } 31912 /** 31913 * Builds the given shader node. 31914 * 31915 * @param {ShaderNodeInternal} shaderNode - The shader node. 31916 * @return {string} The GLSL function code. 31917 */ 31918 buildFunctionCode(shaderNode) { 31919 const layout = shaderNode.layout; 31920 const flowData = this.flowShaderNode(shaderNode); 31921 const parameters = []; 31922 for (const input of layout.inputs) { 31923 parameters.push(this.getType(input.type) + " " + input.name); 31924 } 31925 const code3 = `${this.getType(layout.type)} ${layout.name}( ${parameters.join(", ")} ) { 31926 31927 ${flowData.vars} 31928 31929${flowData.code} 31930 return ${flowData.result}; 31931 31932}`; 31933 return code3; 31934 } 31935 /** 31936 * Setups the Pixel Buffer Object (PBO) for the given storage 31937 * buffer node. 31938 * 31939 * @param {StorageBufferNode} storageBufferNode - The storage buffer node. 31940 */ 31941 setupPBO(storageBufferNode) { 31942 const attribute3 = storageBufferNode.value; 31943 if (attribute3.pbo === void 0) { 31944 const originalArray = attribute3.array; 31945 const numElements = attribute3.count * attribute3.itemSize; 31946 const { itemSize } = attribute3; 31947 const isInteger = attribute3.array.constructor.name.toLowerCase().includes("int"); 31948 let format = isInteger ? RedIntegerFormat : RedFormat; 31949 if (itemSize === 2) { 31950 format = isInteger ? RGIntegerFormat : RGFormat; 31951 } else if (itemSize === 3) { 31952 format = isInteger ? RGBIntegerFormat : RGBFormat; 31953 } else if (itemSize === 4) { 31954 format = isInteger ? RGBAIntegerFormat : RGBAFormat; 31955 } 31956 const typeMap = { 31957 Float32Array: FloatType, 31958 Uint8Array: UnsignedByteType, 31959 Uint16Array: UnsignedShortType, 31960 Uint32Array: UnsignedIntType, 31961 Int8Array: ByteType, 31962 Int16Array: ShortType, 31963 Int32Array: IntType, 31964 Uint8ClampedArray: UnsignedByteType 31965 }; 31966 const width = Math.pow(2, Math.ceil(Math.log2(Math.sqrt(numElements / itemSize)))); 31967 let height = Math.ceil(numElements / itemSize / width); 31968 if (width * height * itemSize < numElements) height++; 31969 const newSize = width * height * itemSize; 31970 const newArray = new originalArray.constructor(newSize); 31971 newArray.set(originalArray, 0); 31972 attribute3.array = newArray; 31973 const pboTexture = new DataTexture(attribute3.array, width, height, format, typeMap[attribute3.array.constructor.name] || FloatType); 31974 pboTexture.needsUpdate = true; 31975 pboTexture.isPBOTexture = true; 31976 const pbo = new TextureNode(pboTexture, null, null); 31977 pbo.setPrecision("high"); 31978 attribute3.pboNode = pbo; 31979 attribute3.pbo = pbo.value; 31980 this.getUniformFromNode(attribute3.pboNode, "texture", this.shaderStage, this.context.nodeName); 31981 } 31982 } 31983 /** 31984 * Returns a GLSL snippet that represents the property name of the given node. 31985 * 31986 * @param {Node} node - The node. 31987 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 31988 * @return {string} The property name. 31989 */ 31990 getPropertyName(node, shaderStage = this.shaderStage) { 31991 if (node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true) { 31992 return node.name; 31993 } 31994 return super.getPropertyName(node, shaderStage); 31995 } 31996 /** 31997 * Setups the Pixel Buffer Object (PBO) for the given storage 31998 * buffer node. 31999 * 32000 * @param {StorageArrayElementNode} storageArrayElementNode - The storage array element node. 32001 * @return {string} The property name. 32002 */ 32003 generatePBO(storageArrayElementNode) { 32004 const { node, indexNode } = storageArrayElementNode; 32005 const attribute3 = node.value; 32006 if (this.renderer.backend.has(attribute3)) { 32007 const attributeData = this.renderer.backend.get(attribute3); 32008 attributeData.pbo = attribute3.pbo; 32009 } 32010 const nodeUniform = this.getUniformFromNode(attribute3.pboNode, "texture", this.shaderStage, this.context.nodeName); 32011 const textureName = this.getPropertyName(nodeUniform); 32012 this.increaseUsage(indexNode); 32013 const indexSnippet = indexNode.build(this, "uint"); 32014 const elementNodeData = this.getDataFromNode(storageArrayElementNode); 32015 let propertyName = elementNodeData.propertyName; 32016 if (propertyName === void 0) { 32017 const nodeVar = this.getVarFromNode(storageArrayElementNode); 32018 propertyName = this.getPropertyName(nodeVar); 32019 const bufferNodeData = this.getDataFromNode(node); 32020 let propertySizeName = bufferNodeData.propertySizeName; 32021 if (propertySizeName === void 0) { 32022 propertySizeName = propertyName + "Size"; 32023 this.getVarFromNode(node, propertySizeName, "uint"); 32024 this.addLineFlowCode(`${propertySizeName} = uint( textureSize( ${textureName}, 0 ).x )`, storageArrayElementNode); 32025 bufferNodeData.propertySizeName = propertySizeName; 32026 } 32027 const { itemSize } = attribute3; 32028 const channel = "." + vectorComponents.join("").slice(0, itemSize); 32029 const uvSnippet = `ivec2(${indexSnippet} % ${propertySizeName}, ${indexSnippet} / ${propertySizeName})`; 32030 const snippet = this.generateTextureLoad(null, textureName, uvSnippet, "0", null, null); 32031 let prefix = "vec4"; 32032 if (attribute3.pbo.type === UnsignedIntType) { 32033 prefix = "uvec4"; 32034 } else if (attribute3.pbo.type === IntType) { 32035 prefix = "ivec4"; 32036 } 32037 this.addLineFlowCode(`${propertyName} = ${prefix}(${snippet})${channel}`, storageArrayElementNode); 32038 elementNodeData.propertyName = propertyName; 32039 } 32040 return propertyName; 32041 } 32042 /** 32043 * Generates the GLSL snippet that reads a single texel from a texture without sampling or filtering. 32044 * 32045 * @param {?Texture} texture - The texture. 32046 * @param {string} textureProperty - The name of the texture uniform in the shader. 32047 * @param {string} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32048 * @param {?string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 32049 * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. 32050 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32051 * @return {string} The GLSL snippet. 32052 */ 32053 generateTextureLoad(texture3, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet) { 32054 if (levelSnippet === null) levelSnippet = "0"; 32055 let snippet; 32056 if (depthSnippet) { 32057 if (offsetSnippet) { 32058 snippet = `texelFetchOffset( ${textureProperty}, ivec3( ${uvIndexSnippet}, ${depthSnippet} ), int( ${levelSnippet} ), ${offsetSnippet} )`; 32059 } else { 32060 snippet = `texelFetch( ${textureProperty}, ivec3( ${uvIndexSnippet}, ${depthSnippet} ), int( ${levelSnippet} ) )`; 32061 } 32062 } else { 32063 if (offsetSnippet) { 32064 snippet = `texelFetchOffset( ${textureProperty}, ${uvIndexSnippet}, int( ${levelSnippet} ), ${offsetSnippet} )`; 32065 } else { 32066 snippet = `texelFetch( ${textureProperty}, ${uvIndexSnippet}, int( ${levelSnippet} ) )`; 32067 } 32068 } 32069 if (texture3 !== null && texture3.isDepthTexture) { 32070 snippet += ".x"; 32071 } 32072 return snippet; 32073 } 32074 /** 32075 * Generates the GLSL snippet for sampling/loading the given texture. 32076 * 32077 * @param {Texture} texture - The texture. 32078 * @param {string} textureProperty - The name of the texture uniform in the shader. 32079 * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32080 * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. 32081 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32082 * @return {string} The GLSL snippet. 32083 */ 32084 generateTexture(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet) { 32085 if (depthSnippet) uvSnippet = `vec3( ${uvSnippet}, ${depthSnippet} )`; 32086 if (texture3.isDepthTexture) { 32087 if (offsetSnippet) return `textureOffset( ${textureProperty}, ${uvSnippet}, ${offsetSnippet} ).x`; 32088 return `texture( ${textureProperty}, ${uvSnippet} ).x`; 32089 } 32090 if (offsetSnippet) return `textureOffset( ${textureProperty}, ${uvSnippet}, ${offsetSnippet} )`; 32091 return `texture( ${textureProperty}, ${uvSnippet} )`; 32092 } 32093 /** 32094 * Generates the GLSL snippet when sampling textures with explicit mip level. 32095 * 32096 * @param {Texture} texture - The texture. 32097 * @param {string} textureProperty - The name of the texture uniform in the shader. 32098 * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32099 * @param {string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 32100 * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. 32101 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32102 * @return {string} The GLSL snippet. 32103 */ 32104 generateTextureLevel(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet) { 32105 if (depthSnippet) uvSnippet = `vec3( ${uvSnippet}, ${depthSnippet} )`; 32106 if (offsetSnippet) { 32107 return `textureLodOffset( ${textureProperty}, ${uvSnippet}, ${levelSnippet}, ${offsetSnippet} )`; 32108 } 32109 return `textureLod( ${textureProperty}, ${uvSnippet}, ${levelSnippet} )`; 32110 } 32111 /** 32112 * Generates the GLSL snippet when sampling textures with a bias to the mip level. 32113 * 32114 * @param {Texture} texture - The texture. 32115 * @param {string} textureProperty - The name of the texture uniform in the shader. 32116 * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32117 * @param {string} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling. 32118 * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. 32119 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32120 * @return {string} The GLSL snippet. 32121 */ 32122 generateTextureBias(texture3, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet) { 32123 if (depthSnippet) uvSnippet = `vec3( ${uvSnippet}, ${depthSnippet} )`; 32124 if (offsetSnippet) { 32125 return `textureOffset( ${textureProperty}, ${uvSnippet}, ${offsetSnippet}, ${biasSnippet} )`; 32126 } 32127 return `texture( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`; 32128 } 32129 /** 32130 * Generates the GLSL snippet for sampling/loading the given texture using explicit gradients. 32131 * 32132 * @param {Texture} texture - The texture. 32133 * @param {string} textureProperty - The name of the texture uniform in the shader. 32134 * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32135 * @param {Array<string>} gradSnippet - An array holding both gradient GLSL snippets. 32136 * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. 32137 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32138 * @return {string} The GLSL snippet. 32139 */ 32140 generateTextureGrad(texture3, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet) { 32141 if (depthSnippet) uvSnippet = `vec3( ${uvSnippet}, ${depthSnippet} )`; 32142 if (offsetSnippet) { 32143 return `textureGradOffset( ${textureProperty}, ${uvSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]}, ${offsetSnippet} )`; 32144 } 32145 return `textureGrad( ${textureProperty}, ${uvSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]} )`; 32146 } 32147 /** 32148 * Generates the GLSL snippet for sampling a depth texture and comparing the sampled depth values 32149 * against a reference value. 32150 * 32151 * @param {Texture} texture - The texture. 32152 * @param {string} textureProperty - The name of the texture uniform in the shader. 32153 * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. 32154 * @param {string} compareSnippet - A GLSL snippet that represents the reference value. 32155 * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. 32156 * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 32157 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 32158 * @return {string} The GLSL snippet. 32159 */ 32160 generateTextureCompare(texture3, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 32161 if (shaderStage === "fragment") { 32162 if (texture3.isCubeTexture) { 32163 return `texture( ${textureProperty}, vec4( ${uvSnippet}, ${compareSnippet} ) )`; 32164 } 32165 if (depthSnippet) { 32166 if (offsetSnippet) { 32167 return `textureOffset( ${textureProperty}, vec4( ${uvSnippet}, ${depthSnippet}, ${compareSnippet} ), ${offsetSnippet} )`; 32168 } 32169 return `texture( ${textureProperty}, vec4( ${uvSnippet}, ${depthSnippet}, ${compareSnippet} ) )`; 32170 } 32171 if (offsetSnippet) { 32172 return `textureOffset( ${textureProperty}, vec3( ${uvSnippet}, ${compareSnippet} ), ${offsetSnippet} )`; 32173 } 32174 return `texture( ${textureProperty}, vec3( ${uvSnippet}, ${compareSnippet} ) )`; 32175 } else { 32176 error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${shaderStage} shader.`); 32177 } 32178 } 32179 /** 32180 * Returns the uniforms of the given shader stage as a GLSL string. 32181 * 32182 * @param {string} shaderStage - The shader stage. 32183 * @return {string} The GLSL snippet that defines the uniforms. 32184 */ 32185 getUniforms(shaderStage) { 32186 const uniforms = this.uniforms[shaderStage]; 32187 const bindingSnippets = []; 32188 const uniformGroups = {}; 32189 for (const uniform3 of uniforms) { 32190 let snippet = null; 32191 let group = false; 32192 if (uniform3.type === "texture" || uniform3.type === "texture3D") { 32193 const texture3 = uniform3.node.value; 32194 let typePrefix = ""; 32195 if (texture3.isDataTexture === true || texture3.isData3DTexture === true) { 32196 if (texture3.type === UnsignedIntType) { 32197 typePrefix = "u"; 32198 } else if (texture3.type === IntType) { 32199 typePrefix = "i"; 32200 } 32201 } 32202 if (uniform3.type === "texture3D" && texture3.isArrayTexture === false) { 32203 snippet = `${typePrefix}sampler3D ${uniform3.name};`; 32204 } else if (texture3.compareFunction) { 32205 if (texture3.isArrayTexture === true) { 32206 snippet = `sampler2DArrayShadow ${uniform3.name};`; 32207 } else { 32208 snippet = `sampler2DShadow ${uniform3.name};`; 32209 } 32210 } else if (texture3.isArrayTexture === true || texture3.isDataArrayTexture === true || texture3.isCompressedArrayTexture === true) { 32211 snippet = `${typePrefix}sampler2DArray ${uniform3.name};`; 32212 } else { 32213 snippet = `${typePrefix}sampler2D ${uniform3.name};`; 32214 } 32215 } else if (uniform3.type === "cubeTexture") { 32216 snippet = `samplerCube ${uniform3.name};`; 32217 } else if (uniform3.type === "cubeDepthTexture") { 32218 const texture3 = uniform3.node.value; 32219 if (texture3.compareFunction) { 32220 snippet = `samplerCubeShadow ${uniform3.name};`; 32221 } else { 32222 snippet = `samplerCube ${uniform3.name};`; 32223 } 32224 } else if (uniform3.type === "buffer") { 32225 const bufferNode = uniform3.node; 32226 const bufferType = this.getType(bufferNode.bufferType); 32227 const bufferCount = bufferNode.bufferCount; 32228 const bufferCountSnippet = bufferCount > 0 ? bufferCount : ""; 32229 snippet = `${bufferNode.name} { 32230 ${bufferType} ${uniform3.name}[${bufferCountSnippet}]; 32231}; 32232`; 32233 } else { 32234 const groupName = uniform3.groupNode.name; 32235 if (uniformGroups[groupName] === void 0) { 32236 const sharedUniformGroup3 = this.uniformGroups[groupName]; 32237 if (sharedUniformGroup3 !== void 0) { 32238 const snippets = []; 32239 for (const sharedUniform of sharedUniformGroup3.uniforms) { 32240 const type = sharedUniform.getType(); 32241 const vectorType = this.getVectorType(type); 32242 const precision = sharedUniform.nodeUniform.node.precision; 32243 let uniformSnippet = `${vectorType} ${sharedUniform.name};`; 32244 if (precision !== null) { 32245 uniformSnippet = precisionLib[precision] + " " + uniformSnippet; 32246 } 32247 snippets.push(" " + uniformSnippet); 32248 } 32249 uniformGroups[groupName] = snippets; 32250 } 32251 } 32252 group = true; 32253 } 32254 if (!group) { 32255 const precision = uniform3.node.precision; 32256 if (precision !== null) { 32257 snippet = precisionLib[precision] + " " + snippet; 32258 } 32259 snippet = "uniform " + snippet; 32260 bindingSnippets.push(snippet); 32261 } 32262 } 32263 let output3 = ""; 32264 for (const name in uniformGroups) { 32265 const groupSnippets = uniformGroups[name]; 32266 output3 += this._getGLSLUniformStruct(name, groupSnippets.join("\n")) + "\n"; 32267 } 32268 output3 += bindingSnippets.join("\n"); 32269 return output3; 32270 } 32271 /** 32272 * Returns the type for a given buffer attribute. 32273 * 32274 * @param {BufferAttribute} attribute - The buffer attribute. 32275 * @return {string} The type. 32276 */ 32277 getTypeFromAttribute(attribute3) { 32278 let nodeType = super.getTypeFromAttribute(attribute3); 32279 if (/^[iu]/.test(nodeType) && attribute3.gpuType !== IntType) { 32280 let dataAttribute = attribute3; 32281 if (attribute3.isInterleavedBufferAttribute) dataAttribute = attribute3.data; 32282 const array3 = dataAttribute.array; 32283 if ((array3 instanceof Uint32Array || array3 instanceof Int32Array) === false) { 32284 nodeType = nodeType.slice(1); 32285 } 32286 } 32287 return nodeType; 32288 } 32289 /** 32290 * Returns the shader attributes of the given shader stage as a GLSL string. 32291 * 32292 * @param {string} shaderStage - The shader stage. 32293 * @return {string} The GLSL snippet that defines the shader attributes. 32294 */ 32295 getAttributes(shaderStage) { 32296 let snippet = ""; 32297 if (shaderStage === "vertex" || shaderStage === "compute") { 32298 const attributes = this.getAttributesArray(); 32299 let location = 0; 32300 for (const attribute3 of attributes) { 32301 snippet += `layout( location = ${location++} ) in ${attribute3.type} ${attribute3.name}; 32302`; 32303 } 32304 } 32305 return snippet; 32306 } 32307 /** 32308 * Returns the members of the given struct type node as a GLSL string. 32309 * 32310 * @param {StructTypeNode} struct - The struct type node. 32311 * @return {string} The GLSL snippet that defines the struct members. 32312 */ 32313 getStructMembers(struct3) { 32314 const snippets = []; 32315 for (const member of struct3.members) { 32316 snippets.push(` ${member.type} ${member.name};`); 32317 } 32318 return snippets.join("\n"); 32319 } 32320 /** 32321 * Returns the structs of the given shader stage as a GLSL string. 32322 * 32323 * @param {string} shaderStage - The shader stage. 32324 * @return {string} The GLSL snippet that defines the structs. 32325 */ 32326 getStructs(shaderStage) { 32327 const snippets = []; 32328 const structs = this.structs[shaderStage]; 32329 const outputSnippet = []; 32330 for (const struct3 of structs) { 32331 if (struct3.output) { 32332 for (const member of struct3.members) { 32333 outputSnippet.push(`layout( location = ${member.index} ) out ${member.type} ${member.name};`); 32334 } 32335 } else { 32336 let snippet = "struct " + struct3.name + " {\n"; 32337 snippet += this.getStructMembers(struct3); 32338 snippet += "\n};\n"; 32339 snippets.push(snippet); 32340 } 32341 } 32342 if (outputSnippet.length === 0) { 32343 outputSnippet.push("layout( location = 0 ) out vec4 fragColor;"); 32344 } 32345 return "\n" + outputSnippet.join("\n") + "\n\n" + snippets.join("\n"); 32346 } 32347 /** 32348 * Returns the varyings of the given shader stage as a GLSL string. 32349 * 32350 * @param {string} shaderStage - The shader stage. 32351 * @return {string} The GLSL snippet that defines the varyings. 32352 */ 32353 getVaryings(shaderStage) { 32354 let snippet = ""; 32355 const varyings = this.varyings; 32356 if (shaderStage === "vertex" || shaderStage === "compute") { 32357 for (const varying3 of varyings) { 32358 if (shaderStage === "compute") varying3.needsInterpolation = true; 32359 const type = this.getType(varying3.type); 32360 if (varying3.needsInterpolation) { 32361 if (varying3.interpolationType) { 32362 const interpolationType = interpolationTypeMap[varying3.interpolationType] || varying3.interpolationType; 32363 const sampling = interpolationModeMap[varying3.interpolationSampling] || ""; 32364 snippet += `${interpolationType} ${sampling} out ${type} ${varying3.name}; 32365`; 32366 } else { 32367 const flat = type.includes("int") || type.includes("uv") || type.includes("iv") ? "flat " : ""; 32368 snippet += `${flat}out ${type} ${varying3.name}; 32369`; 32370 } 32371 } else { 32372 snippet += `${type} ${varying3.name}; 32373`; 32374 } 32375 } 32376 } else if (shaderStage === "fragment") { 32377 for (const varying3 of varyings) { 32378 if (varying3.needsInterpolation) { 32379 const type = this.getType(varying3.type); 32380 if (varying3.interpolationType) { 32381 const interpolationType = interpolationTypeMap[varying3.interpolationType] || varying3.interpolationType; 32382 const sampling = interpolationModeMap[varying3.interpolationSampling] || ""; 32383 snippet += `${interpolationType} ${sampling} in ${type} ${varying3.name}; 32384`; 32385 } else { 32386 const flat = type.includes("int") || type.includes("uv") || type.includes("iv") ? "flat " : ""; 32387 snippet += `${flat}in ${type} ${varying3.name}; 32388`; 32389 } 32390 } 32391 } 32392 } 32393 for (const builtin3 of this.builtins[shaderStage]) { 32394 snippet += `${builtin3}; 32395`; 32396 } 32397 return snippet; 32398 } 32399 /** 32400 * Returns the vertex index builtin. 32401 * 32402 * @return {string} The vertex index. 32403 */ 32404 getVertexIndex() { 32405 return "uint( gl_VertexID )"; 32406 } 32407 /** 32408 * Contextually returns either the vertex stage instance index builtin 32409 * or the linearized index of an compute invocation within a grid of workgroups. 32410 * 32411 * @return {string} The instance index. 32412 */ 32413 getInstanceIndex() { 32414 return "uint( gl_InstanceID )"; 32415 } 32416 /** 32417 * Returns a builtin representing the index of an invocation within its workgroup. 32418 * 32419 * @return {string} The invocation local index. 32420 */ 32421 getInvocationLocalIndex() { 32422 const workgroupSize = this.object.workgroupSize; 32423 const size3 = workgroupSize.reduce((acc, curr) => acc * curr, 1); 32424 return `uint( gl_InstanceID ) % ${size3}u`; 32425 } 32426 /** 32427 * Returns a builtin representing the size of a subgroup within the current shader. 32428 */ 32429 getSubgroupSize() { 32430 error("GLSLNodeBuilder: WebGLBackend does not support the subgroupSize node"); 32431 } 32432 /** 32433 * Returns a builtin representing the index of an invocation within its subgroup. 32434 */ 32435 getInvocationSubgroupIndex() { 32436 error("GLSLNodeBuilder: WebGLBackend does not support the invocationSubgroupIndex node"); 32437 } 32438 /** 32439 * Returns a builtin representing the index of the current invocation's subgroup within its workgroup. 32440 */ 32441 getSubgroupIndex() { 32442 error("GLSLNodeBuilder: WebGLBackend does not support the subgroupIndex node"); 32443 } 32444 /** 32445 * Returns the draw index builtin. 32446 * 32447 * @return {?string} The drawIndex shader string. Returns `null` if `WEBGL_multi_draw` isn't supported by the device. 32448 */ 32449 getDrawIndex() { 32450 const extensions = this.renderer.backend.extensions; 32451 if (extensions.has("WEBGL_multi_draw")) { 32452 return "uint( gl_DrawID )"; 32453 } else { 32454 return "nodeUniformDrawId"; 32455 } 32456 } 32457 /** 32458 * Returns the front facing builtin. 32459 * 32460 * @return {string} The front facing builtin. 32461 */ 32462 getFrontFacing() { 32463 return "gl_FrontFacing"; 32464 } 32465 /** 32466 * Returns the frag coord builtin. 32467 * 32468 * @return {string} The frag coord builtin. 32469 */ 32470 getFragCoord() { 32471 return "gl_FragCoord.xy"; 32472 } 32473 /** 32474 * Returns the frag depth builtin. 32475 * 32476 * @return {string} The frag depth builtin. 32477 */ 32478 getFragDepth() { 32479 return "gl_FragDepth"; 32480 } 32481 /** 32482 * Enables the given extension. 32483 * 32484 * @param {string} name - The extension name. 32485 * @param {string} behavior - The extension behavior. 32486 * @param {string} [shaderStage=this.shaderStage] - The shader stage. 32487 */ 32488 enableExtension(name, behavior, shaderStage = this.shaderStage) { 32489 const map = this.extensions[shaderStage] || (this.extensions[shaderStage] = /* @__PURE__ */ new Map()); 32490 if (map.has(name) === false) { 32491 map.set(name, { 32492 name, 32493 behavior 32494 }); 32495 } 32496 } 32497 /** 32498 * Returns the enabled extensions of the given shader stage as a GLSL string. 32499 * 32500 * @param {string} shaderStage - The shader stage. 32501 * @return {string} The GLSL snippet that defines the enabled extensions. 32502 */ 32503 getExtensions(shaderStage) { 32504 const snippets = []; 32505 if (shaderStage === "vertex") { 32506 const ext = this.renderer.backend.extensions; 32507 const isBatchedMesh = this.object.isBatchedMesh; 32508 if (isBatchedMesh && ext.has("WEBGL_multi_draw")) { 32509 this.enableExtension("GL_ANGLE_multi_draw", "require", shaderStage); 32510 } 32511 } 32512 const extensions = this.extensions[shaderStage]; 32513 if (extensions !== void 0) { 32514 for (const { name, behavior } of extensions.values()) { 32515 snippets.push(`#extension ${name} : ${behavior}`); 32516 } 32517 } 32518 return snippets.join("\n"); 32519 } 32520 /** 32521 * Returns the clip distances builtin. 32522 * 32523 * @return {string} The clip distances builtin. 32524 */ 32525 getClipDistance() { 32526 return "gl_ClipDistance"; 32527 } 32528 /** 32529 * Whether the requested feature is available or not. 32530 * 32531 * @param {string} name - The requested feature. 32532 * @return {boolean} Whether the requested feature is supported or not. 32533 */ 32534 isAvailable(name) { 32535 let result = supports$1[name]; 32536 if (result === void 0) { 32537 let extensionName; 32538 result = false; 32539 switch (name) { 32540 case "float32Filterable": 32541 extensionName = "OES_texture_float_linear"; 32542 break; 32543 case "clipDistance": 32544 extensionName = "WEBGL_clip_cull_distance"; 32545 break; 32546 } 32547 if (extensionName !== void 0) { 32548 const extensions = this.renderer.backend.extensions; 32549 if (extensions.has(extensionName)) { 32550 extensions.get(extensionName); 32551 result = true; 32552 } 32553 } 32554 supports$1[name] = result; 32555 } 32556 return result; 32557 } 32558 /** 32559 * Whether to flip texture data along its vertical axis or not. 32560 * 32561 * @return {boolean} Returns always `true` in context of GLSL. 32562 */ 32563 isFlipY() { 32564 return true; 32565 } 32566 /** 32567 * Enables hardware clipping. 32568 * 32569 * @param {string} planeCount - The clipping plane count. 32570 */ 32571 enableHardwareClipping(planeCount) { 32572 this.enableExtension("GL_ANGLE_clip_cull_distance", "require"); 32573 this.builtins["vertex"].push(`out float gl_ClipDistance[ ${planeCount} ]`); 32574 } 32575 /** 32576 * Enables multiview. 32577 */ 32578 enableMultiview() { 32579 this.enableExtension("GL_OVR_multiview2", "require", "fragment"); 32580 this.enableExtension("GL_OVR_multiview2", "require", "vertex"); 32581 this.builtins["vertex"].push("layout(num_views = 2) in"); 32582 } 32583 /** 32584 * Registers a transform in context of Transform Feedback. 32585 * 32586 * @param {string} varyingName - The varying name. 32587 * @param {AttributeNode} attributeNode - The attribute node. 32588 */ 32589 registerTransform(varyingName, attributeNode) { 32590 this.transforms.push({ varyingName, attributeNode }); 32591 } 32592 /** 32593 * Returns the transforms of the given shader stage as a GLSL string. 32594 * 32595 * @param {string} shaderStage - The shader stage. 32596 * @return {string} The GLSL snippet that defines the transforms. 32597 */ 32598 getTransforms() { 32599 const transforms = this.transforms; 32600 let snippet = ""; 32601 for (let i = 0; i < transforms.length; i++) { 32602 const transform = transforms[i]; 32603 const attributeName = this.getPropertyName(transform.attributeNode); 32604 if (attributeName) snippet += `${transform.varyingName} = ${attributeName}; 32605 `; 32606 } 32607 return snippet; 32608 } 32609 /** 32610 * Returns a GLSL struct based on the given name and variables. 32611 * 32612 * @private 32613 * @param {string} name - The struct name. 32614 * @param {string} vars - The struct variables. 32615 * @return {string} The GLSL snippet representing a struct. 32616 */ 32617 _getGLSLUniformStruct(name, vars) { 32618 return ` 32619layout( std140 ) uniform ${name} { 32620${vars} 32621};`; 32622 } 32623 /** 32624 * Returns a GLSL vertex shader based on the given shader data. 32625 * 32626 * @private 32627 * @param {Object} shaderData - The shader data. 32628 * @return {string} The vertex shader. 32629 */ 32630 _getGLSLVertexCode(shaderData) { 32631 return `#version 300 es 32632 32633${this.getSignature()} 32634 32635// extensions 32636${shaderData.extensions} 32637 32638// precision 32639${defaultPrecisions} 32640 32641// uniforms 32642${shaderData.uniforms} 32643 32644// varyings 32645${shaderData.varyings} 32646 32647// attributes 32648${shaderData.attributes} 32649 32650// vars 32651${shaderData.vars} 32652 32653// codes 32654${shaderData.codes} 32655 32656void main() { 32657 32658 // transforms 32659 ${shaderData.transforms} 32660 32661 // flow 32662 ${shaderData.flow} 32663 32664 gl_PointSize = 1.0; 32665 32666} 32667`; 32668 } 32669 /** 32670 * Returns a GLSL fragment shader based on the given shader data. 32671 * 32672 * @private 32673 * @param {Object} shaderData - The shader data. 32674 * @return {string} The vertex shader. 32675 */ 32676 _getGLSLFragmentCode(shaderData) { 32677 return `#version 300 es 32678 32679${this.getSignature()} 32680 32681// extensions 32682${shaderData.extensions} 32683 32684// precision 32685${defaultPrecisions} 32686 32687// structs 32688${shaderData.structs} 32689 32690// uniforms 32691${shaderData.uniforms} 32692 32693// varyings 32694${shaderData.varyings} 32695 32696// vars 32697${shaderData.vars} 32698 32699// codes 32700${shaderData.codes} 32701 32702void main() { 32703 32704 // flow 32705 ${shaderData.flow} 32706 32707} 32708`; 32709 } 32710 /** 32711 * Controls the code build of the shader stages. 32712 */ 32713 buildCode() { 32714 const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; 32715 this.sortBindingGroups(); 32716 for (const shaderStage in shadersData) { 32717 let flow = "// code\n\n"; 32718 flow += this.flowCode[shaderStage]; 32719 const flowNodes = this.flowNodes[shaderStage]; 32720 const mainNode = flowNodes[flowNodes.length - 1]; 32721 for (const node of flowNodes) { 32722 const flowSlotData = this.getFlowData( 32723 node 32724 /*, shaderStage*/ 32725 ); 32726 const slotName = node.name; 32727 if (slotName) { 32728 if (flow.length > 0) flow += "\n"; 32729 flow += ` // flow -> ${slotName} 32730 `; 32731 } 32732 flow += `${flowSlotData.code} 32733 `; 32734 if (node === mainNode && shaderStage !== "compute") { 32735 flow += "// result\n "; 32736 if (shaderStage === "vertex") { 32737 flow += "gl_Position = "; 32738 flow += `${flowSlotData.result};`; 32739 } else if (shaderStage === "fragment") { 32740 if (!node.outputNode.isOutputStructNode) { 32741 flow += "fragColor = "; 32742 flow += `${flowSlotData.result};`; 32743 } 32744 } 32745 } 32746 } 32747 const stageData = shadersData[shaderStage]; 32748 stageData.extensions = this.getExtensions(shaderStage); 32749 stageData.uniforms = this.getUniforms(shaderStage); 32750 stageData.attributes = this.getAttributes(shaderStage); 32751 stageData.varyings = this.getVaryings(shaderStage); 32752 stageData.vars = this.getVars(shaderStage, true); 32753 stageData.structs = this.getStructs(shaderStage); 32754 stageData.codes = this.getCodes(shaderStage); 32755 stageData.transforms = this.getTransforms(shaderStage); 32756 stageData.flow = flow; 32757 if (shaderStage === "vertex") { 32758 const ext = this.renderer.backend.extensions; 32759 if (this.object.isBatchedMesh && ext.has("WEBGL_multi_draw") === false) { 32760 stageData.uniforms += "\nuniform uint nodeUniformDrawId;\n"; 32761 } 32762 } 32763 } 32764 if (this.material !== null) { 32765 this.vertexShader = this._getGLSLVertexCode(shadersData.vertex); 32766 this.fragmentShader = this._getGLSLFragmentCode(shadersData.fragment); 32767 } else { 32768 this.computeShader = this._getGLSLVertexCode(shadersData.compute); 32769 } 32770 } 32771 /** 32772 * This method is one of the more important ones since it's responsible 32773 * for generating a matching binding instance for the given uniform node. 32774 * 32775 * These bindings are later used in the renderer to create bind groups 32776 * and layouts. 32777 * 32778 * @param {UniformNode} node - The uniform node. 32779 * @param {string} type - The node data type. 32780 * @param {string} shaderStage - The shader stage. 32781 * @param {?string} [name=null] - An optional uniform name. 32782 * @return {NodeUniform} The node uniform object. 32783 */ 32784 getUniformFromNode(node, type, shaderStage, name = null) { 32785 const uniformNode = super.getUniformFromNode(node, type, shaderStage, name); 32786 const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); 32787 let uniformGPU = nodeData.uniformGPU; 32788 if (uniformGPU === void 0) { 32789 const group = node.groupNode; 32790 const groupName = group.name; 32791 const bindings = this.getBindGroupArray(groupName, shaderStage); 32792 if (type === "texture") { 32793 uniformGPU = new NodeSampledTexture(uniformNode.name, uniformNode.node, group); 32794 bindings.push(uniformGPU); 32795 } else if (type === "cubeTexture" || type === "cubeDepthTexture") { 32796 uniformGPU = new NodeSampledCubeTexture(uniformNode.name, uniformNode.node, group); 32797 bindings.push(uniformGPU); 32798 } else if (type === "texture3D") { 32799 uniformGPU = new NodeSampledTexture3D(uniformNode.name, uniformNode.node, group); 32800 bindings.push(uniformGPU); 32801 } else if (type === "buffer") { 32802 uniformNode.name = `buffer${node.id}`; 32803 const sharedData = this.getSharedDataFromNode(node); 32804 let buffer3 = sharedData.buffer; 32805 if (buffer3 === void 0) { 32806 node.name = `NodeBuffer_${node.id}`; 32807 buffer3 = new NodeUniformBuffer(node, group); 32808 buffer3.name = node.name; 32809 sharedData.buffer = buffer3; 32810 } 32811 bindings.push(buffer3); 32812 uniformGPU = buffer3; 32813 } else { 32814 let uniformsGroup = this.uniformGroups[groupName]; 32815 if (uniformsGroup === void 0) { 32816 uniformsGroup = new NodeUniformsGroup(groupName, group); 32817 this.uniformGroups[groupName] = uniformsGroup; 32818 bindings.push(uniformsGroup); 32819 } else { 32820 if (bindings.indexOf(uniformsGroup) === -1) { 32821 bindings.push(uniformsGroup); 32822 } 32823 } 32824 uniformGPU = this.getNodeUniform(uniformNode, type); 32825 const uniformName = uniformGPU.name; 32826 const alreadyExists = uniformsGroup.uniforms.some((u) => u.name === uniformName); 32827 if (!alreadyExists) { 32828 uniformsGroup.addUniform(uniformGPU); 32829 } 32830 } 32831 nodeData.uniformGPU = uniformGPU; 32832 } 32833 return uniformNode; 32834 } 32835}; 32836var _vector2 = null; 32837var _color4 = null; 32838var Backend = class { 32839 /** 32840 * Constructs a new backend. 32841 * 32842 * @param {Object} parameters - An object holding parameters for the backend. 32843 */ 32844 constructor(parameters = {}) { 32845 this.parameters = Object.assign({}, parameters); 32846 this.data = /* @__PURE__ */ new WeakMap(); 32847 this.renderer = null; 32848 this.domElement = null; 32849 this.timestampQueryPool = { 32850 [TimestampQuery.RENDER]: null, 32851 [TimestampQuery.COMPUTE]: null 32852 }; 32853 this.trackTimestamp = parameters.trackTimestamp === true; 32854 } 32855 /** 32856 * Initializes the backend so it is ready for usage. Concrete backends 32857 * are supposed to implement their rendering context creation and related 32858 * operations in this method. 32859 * 32860 * @async 32861 * @param {Renderer} renderer - The renderer. 32862 * @return {Promise} A Promise that resolves when the backend has been initialized. 32863 */ 32864 async init(renderer) { 32865 this.renderer = renderer; 32866 } 32867 /** 32868 * The coordinate system of the backend. 32869 * 32870 * @abstract 32871 * @type {number} 32872 * @readonly 32873 */ 32874 get coordinateSystem() { 32875 } 32876 // render context 32877 /** 32878 * This method is executed at the beginning of a render call and 32879 * can be used by the backend to prepare the state for upcoming 32880 * draw calls. 32881 * 32882 * @abstract 32883 * @param {RenderContext} renderContext - The render context. 32884 */ 32885 beginRender() { 32886 } 32887 /** 32888 * This method is executed at the end of a render call and 32889 * can be used by the backend to finalize work after draw 32890 * calls. 32891 * 32892 * @abstract 32893 * @param {RenderContext} renderContext - The render context. 32894 */ 32895 finishRender() { 32896 } 32897 /** 32898 * This method is executed at the beginning of a compute call and 32899 * can be used by the backend to prepare the state for upcoming 32900 * compute tasks. 32901 * 32902 * @abstract 32903 * @param {Node|Array<Node>} computeGroup - The compute node(s). 32904 */ 32905 beginCompute() { 32906 } 32907 /** 32908 * This method is executed at the end of a compute call and 32909 * can be used by the backend to finalize work after compute 32910 * tasks. 32911 * 32912 * @abstract 32913 * @param {Node|Array<Node>} computeGroup - The compute node(s). 32914 */ 32915 finishCompute() { 32916 } 32917 // render object 32918 /** 32919 * Executes a draw command for the given render object. 32920 * 32921 * @abstract 32922 * @param {RenderObject} renderObject - The render object to draw. 32923 * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. 32924 */ 32925 draw() { 32926 } 32927 // compute node 32928 /** 32929 * Executes a compute command for the given compute node. 32930 * 32931 * @abstract 32932 * @param {Node|Array<Node>} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. 32933 * @param {Node} computeNode - The compute node. 32934 * @param {Array<BindGroup>} bindings - The bindings. 32935 * @param {ComputePipeline} computePipeline - The compute pipeline. 32936 */ 32937 compute() { 32938 } 32939 // program 32940 /** 32941 * Creates a shader program from the given programmable stage. 32942 * 32943 * @abstract 32944 * @param {ProgrammableStage} program - The programmable stage. 32945 */ 32946 createProgram() { 32947 } 32948 /** 32949 * Destroys the shader program of the given programmable stage. 32950 * 32951 * @abstract 32952 * @param {ProgrammableStage} program - The programmable stage. 32953 */ 32954 destroyProgram() { 32955 } 32956 // bindings 32957 /** 32958 * Creates bindings from the given bind group definition. 32959 * 32960 * @abstract 32961 * @param {BindGroup} bindGroup - The bind group. 32962 * @param {Array<BindGroup>} bindings - Array of bind groups. 32963 * @param {number} cacheIndex - The cache index. 32964 * @param {number} version - The version. 32965 */ 32966 createBindings() { 32967 } 32968 /** 32969 * Updates the given bind group definition. 32970 * 32971 * @abstract 32972 * @param {BindGroup} bindGroup - The bind group. 32973 * @param {Array<BindGroup>} bindings - Array of bind groups. 32974 * @param {number} cacheIndex - The cache index. 32975 * @param {number} version - The version. 32976 */ 32977 updateBindings() { 32978 } 32979 /** 32980 * Updates a buffer binding. 32981 * 32982 * @abstract 32983 * @param {Buffer} binding - The buffer binding to update. 32984 */ 32985 updateBinding() { 32986 } 32987 // pipeline 32988 /** 32989 * Creates a render pipeline for the given render object. 32990 * 32991 * @abstract 32992 * @param {RenderObject} renderObject - The render object. 32993 * @param {Array<Promise>} promises - An array of compilation promises which are used in `compileAsync()`. 32994 */ 32995 createRenderPipeline() { 32996 } 32997 /** 32998 * Creates a compute pipeline for the given compute node. 32999 * 33000 * @abstract 33001 * @param {ComputePipeline} computePipeline - The compute pipeline. 33002 * @param {Array<BindGroup>} bindings - The bindings. 33003 */ 33004 createComputePipeline() { 33005 } 33006 // cache key 33007 /** 33008 * Returns `true` if the render pipeline requires an update. 33009 * 33010 * @abstract 33011 * @param {RenderObject} renderObject - The render object. 33012 * @return {boolean} Whether the render pipeline requires an update or not. 33013 */ 33014 needsRenderUpdate() { 33015 } 33016 /** 33017 * Returns a cache key that is used to identify render pipelines. 33018 * 33019 * @abstract 33020 * @param {RenderObject} renderObject - The render object. 33021 * @return {string} The cache key. 33022 */ 33023 getRenderCacheKey() { 33024 } 33025 // node builder 33026 /** 33027 * Returns a node builder for the given render object. 33028 * 33029 * @abstract 33030 * @param {RenderObject} renderObject - The render object. 33031 * @param {Renderer} renderer - The renderer. 33032 * @return {NodeBuilder} The node builder. 33033 */ 33034 createNodeBuilder() { 33035 } 33036 // textures 33037 /** 33038 * Updates a GPU sampler for the given texture. 33039 * 33040 * @abstract 33041 * @param {Texture} texture - The texture to update the sampler for. 33042 * @return {string} The current sampler key. 33043 */ 33044 updateSampler() { 33045 } 33046 /** 33047 * Creates a default texture for the given texture that can be used 33048 * as a placeholder until the actual texture is ready for usage. 33049 * 33050 * @abstract 33051 * @param {Texture} texture - The texture to create a default texture for. 33052 */ 33053 createDefaultTexture() { 33054 } 33055 /** 33056 * Defines a texture on the GPU for the given texture object. 33057 * 33058 * @abstract 33059 * @param {Texture} texture - The texture. 33060 * @param {Object} [options={}] - Optional configuration parameter. 33061 */ 33062 createTexture() { 33063 } 33064 /** 33065 * Uploads the updated texture data to the GPU. 33066 * 33067 * @abstract 33068 * @param {Texture} texture - The texture. 33069 * @param {Object} [options={}] - Optional configuration parameter. 33070 */ 33071 updateTexture() { 33072 } 33073 /** 33074 * Generates mipmaps for the given texture. 33075 * 33076 * @abstract 33077 * @param {Texture} texture - The texture. 33078 */ 33079 generateMipmaps() { 33080 } 33081 /** 33082 * Destroys the GPU data for the given texture object. 33083 * 33084 * @abstract 33085 * @param {Texture} texture - The texture. 33086 * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. 33087 */ 33088 destroyTexture() { 33089 } 33090 /** 33091 * Returns texture data as a typed array. 33092 * 33093 * @abstract 33094 * @async 33095 * @param {Texture} texture - The texture to copy. 33096 * @param {number} x - The x coordinate of the copy origin. 33097 * @param {number} y - The y coordinate of the copy origin. 33098 * @param {number} width - The width of the copy. 33099 * @param {number} height - The height of the copy. 33100 * @param {number} faceIndex - The face index. 33101 * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished. 33102 */ 33103 async copyTextureToBuffer() { 33104 } 33105 /** 33106 * Copies data of the given source texture to the given destination texture. 33107 * 33108 * @abstract 33109 * @param {Texture} srcTexture - The source texture. 33110 * @param {Texture} dstTexture - The destination texture. 33111 * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy. 33112 * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy. 33113 * @param {number} [srcLevel=0] - The source mip level to copy from. 33114 * @param {number} [dstLevel=0] - The destination mip level to copy to. 33115 */ 33116 copyTextureToTexture() { 33117 } 33118 /** 33119 * Copies the current bound framebuffer to the given texture. 33120 * 33121 * @abstract 33122 * @param {Texture} texture - The destination texture. 33123 * @param {RenderContext} renderContext - The render context. 33124 * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. 33125 */ 33126 copyFramebufferToTexture() { 33127 } 33128 // attributes 33129 /** 33130 * Creates the GPU buffer of a shader attribute. 33131 * 33132 * @abstract 33133 * @param {BufferAttribute} attribute - The buffer attribute. 33134 */ 33135 createAttribute() { 33136 } 33137 /** 33138 * Creates the GPU buffer of an indexed shader attribute. 33139 * 33140 * @abstract 33141 * @param {BufferAttribute} attribute - The indexed buffer attribute. 33142 */ 33143 createIndexAttribute() { 33144 } 33145 /** 33146 * Creates the GPU buffer of a storage attribute. 33147 * 33148 * @abstract 33149 * @param {BufferAttribute} attribute - The buffer attribute. 33150 */ 33151 createStorageAttribute() { 33152 } 33153 /** 33154 * Updates the GPU buffer of a shader attribute. 33155 * 33156 * @abstract 33157 * @param {BufferAttribute} attribute - The buffer attribute to update. 33158 */ 33159 updateAttribute() { 33160 } 33161 /** 33162 * Destroys the GPU buffer of a shader attribute. 33163 * 33164 * @abstract 33165 * @param {BufferAttribute} attribute - The buffer attribute to destroy. 33166 */ 33167 destroyAttribute() { 33168 } 33169 // canvas 33170 /** 33171 * Returns the backend's rendering context. 33172 * 33173 * @abstract 33174 * @return {Object} The rendering context. 33175 */ 33176 getContext() { 33177 } 33178 /** 33179 * Backends can use this method if they have to run 33180 * logic when the renderer gets resized. 33181 * 33182 * @abstract 33183 */ 33184 updateSize() { 33185 } 33186 /** 33187 * Updates the viewport with the values from the given render context. 33188 * 33189 * @abstract 33190 * @param {RenderContext} renderContext - The render context. 33191 */ 33192 updateViewport() { 33193 } 33194 // utils 33195 /** 33196 * Updates a unique identifier for the given render context that can be used 33197 * to allocate resources like occlusion queries or timestamp queries. 33198 * 33199 * @param {RenderContext|ComputeNode} abstractRenderContext - The render context. 33200 */ 33201 updateTimeStampUID(abstractRenderContext) { 33202 const contextData = this.get(abstractRenderContext); 33203 const frame = this.renderer.info.frame; 33204 let prefix; 33205 if (abstractRenderContext.isComputeNode === true) { 33206 prefix = "c:" + this.renderer.info.compute.frameCalls; 33207 } else { 33208 prefix = "r:" + this.renderer.info.render.frameCalls; 33209 } 33210 contextData.timestampUID = prefix + ":" + abstractRenderContext.id + ":f" + frame; 33211 } 33212 /** 33213 * Returns a unique identifier for the given render context that can be used 33214 * to allocate resources like occlusion queries or timestamp queries. 33215 * 33216 * @param {RenderContext|ComputeNode} abstractRenderContext - The render context. 33217 * @return {string} The unique identifier. 33218 */ 33219 getTimestampUID(abstractRenderContext) { 33220 return this.get(abstractRenderContext).timestampUID; 33221 } 33222 /** 33223 * Returns all timestamp frames for the given type. 33224 * 33225 * @param {string} type - The type of the time stamp. 33226 * @return {Array<number>} The timestamp frames. 33227 */ 33228 getTimestampFrames(type) { 33229 const queryPool = this.timestampQueryPool[type]; 33230 return queryPool ? queryPool.getTimestampFrames() : []; 33231 } 33232 /** 33233 * Returns the query pool for the given uid. 33234 * 33235 * @param {string} uid - The unique identifier. 33236 * @return {TimestampQueryPool} The query pool. 33237 */ 33238 _getQueryPool(uid) { 33239 const type = uid.startsWith("c:") ? TimestampQuery.COMPUTE : TimestampQuery.RENDER; 33240 const queryPool = this.timestampQueryPool[type]; 33241 return queryPool; 33242 } 33243 /** 33244 * Returns the timestamp for the given uid. 33245 * 33246 * @param {string} uid - The unique identifier. 33247 * @return {number} The timestamp. 33248 */ 33249 getTimestamp(uid) { 33250 const queryPool = this._getQueryPool(uid); 33251 return queryPool.getTimestamp(uid); 33252 } 33253 /** 33254 * Returns `true` if a timestamp for the given uid is available. 33255 * 33256 * @param {string} uid - The unique identifier. 33257 * @return {boolean} Whether the timestamp is available or not. 33258 */ 33259 hasTimestamp(uid) { 33260 const queryPool = this._getQueryPool(uid); 33261 return queryPool.hasTimestamp(uid); 33262 } 33263 /** 33264 * Returns `true` if the given 3D object is fully occluded by other 33265 * 3D objects in the scene. Backends must implement this method by using 33266 * a Occlusion Query API. 33267 * 33268 * @abstract 33269 * @param {RenderContext} renderContext - The render context. 33270 * @param {Object3D} object - The 3D object to test. 33271 * @return {boolean} Whether the 3D object is fully occluded or not. 33272 */ 33273 isOccluded() { 33274 } 33275 /** 33276 * Resolves the time stamp for the given render context and type. 33277 * 33278 * @async 33279 * @abstract 33280 * @param {string} [type='render'] - The type of the time stamp. 33281 * @return {Promise<number>} A Promise that resolves with the time stamp. 33282 */ 33283 async resolveTimestampsAsync(type = "render") { 33284 if (!this.trackTimestamp) { 33285 warnOnce("WebGPURenderer: Timestamp tracking is disabled."); 33286 return; 33287 } 33288 const queryPool = this.timestampQueryPool[type]; 33289 if (!queryPool) { 33290 return; 33291 } 33292 const duration = await queryPool.resolveQueriesAsync(); 33293 this.renderer.info[type].timestamp = duration; 33294 return duration; 33295 } 33296 /** 33297 * This method performs a readback operation by moving buffer data from 33298 * a storage buffer attribute from the GPU to the CPU. 33299 * 33300 * @async 33301 * @param {StorageBufferAttribute} attribute - The storage buffer attribute. 33302 * @return {Promise<ArrayBuffer>} A promise that resolves with the buffer data when the data are ready. 33303 */ 33304 async getArrayBufferAsync() { 33305 } 33306 /** 33307 * Checks if the given feature is supported by the backend. 33308 * 33309 * @async 33310 * @abstract 33311 * @param {string} name - The feature's name. 33312 * @return {Promise<boolean>} A Promise that resolves with a bool that indicates whether the feature is supported or not. 33313 */ 33314 async hasFeatureAsync() { 33315 } 33316 /** 33317 * Checks if the given feature is supported by the backend. 33318 * 33319 * @abstract 33320 * @param {string} name - The feature's name. 33321 * @return {boolean} Whether the feature is supported or not. 33322 */ 33323 hasFeature() { 33324 } 33325 /** 33326 * Returns the drawing buffer size. 33327 * 33328 * @return {Vector2} The drawing buffer size. 33329 */ 33330 getDrawingBufferSize() { 33331 _vector2 = _vector2 || new Vector2(); 33332 return this.renderer.getDrawingBufferSize(_vector2); 33333 } 33334 /** 33335 * Defines the scissor test. 33336 * 33337 * @abstract 33338 * @param {boolean} boolean - Whether the scissor test should be enabled or not. 33339 */ 33340 setScissorTest() { 33341 } 33342 /** 33343 * Returns the clear color and alpha into a single 33344 * color object. 33345 * 33346 * @return {Color4} The clear color. 33347 */ 33348 getClearColor() { 33349 const renderer = this.renderer; 33350 _color4 = _color4 || new Color4(); 33351 renderer.getClearColor(_color4); 33352 _color4.getRGB(_color4); 33353 return _color4; 33354 } 33355 /** 33356 * Returns the DOM element. If no DOM element exists, the backend 33357 * creates a new one. 33358 * 33359 * @return {HTMLCanvasElement} The DOM element. 33360 */ 33361 getDomElement() { 33362 let domElement = this.domElement; 33363 if (domElement === null) { 33364 domElement = this.parameters.canvas !== void 0 ? this.parameters.canvas : createCanvasElement(); 33365 if ("setAttribute" in domElement) domElement.setAttribute("data-engine", `three.js r${REVISION} webgpu`); 33366 this.domElement = domElement; 33367 } 33368 return domElement; 33369 } 33370 /** 33371 * Checks if the backend has the given compatibility. 33372 * 33373 * @abstract 33374 * @param {string} name - The compatibility. 33375 * @return {boolean} Whether the backend has the given compatibility or not. 33376 */ 33377 hasCompatibility() { 33378 return false; 33379 } 33380 /** 33381 * Initializes the render target defined in the given render context. 33382 * 33383 * @abstract 33384 * @param {RenderContext} renderContext - The render context. 33385 */ 33386 initRenderTarget() { 33387 } 33388 /** 33389 * Sets a dictionary for the given object into the 33390 * internal data structure. 33391 * 33392 * @param {Object} object - The object. 33393 * @param {Object} value - The dictionary to set. 33394 */ 33395 set(object, value) { 33396 this.data.set(object, value); 33397 } 33398 /** 33399 * Returns the dictionary for the given object. 33400 * 33401 * @param {Object} object - The object. 33402 * @return {Object} The object's dictionary. 33403 */ 33404 get(object) { 33405 let map = this.data.get(object); 33406 if (map === void 0) { 33407 map = {}; 33408 this.data.set(object, map); 33409 } 33410 return map; 33411 } 33412 /** 33413 * Checks if the given object has a dictionary 33414 * with data defined. 33415 * 33416 * @param {Object} object - The object. 33417 * @return {boolean} Whether a dictionary for the given object as been defined or not. 33418 */ 33419 has(object) { 33420 return this.data.has(object); 33421 } 33422 /** 33423 * Deletes an object from the internal data structure. 33424 * 33425 * @param {Object} object - The object to delete. 33426 */ 33427 delete(object) { 33428 this.data.delete(object); 33429 } 33430 /** 33431 * Delete GPU data associated with a bind group. 33432 * 33433 * @abstract 33434 * @param {BindGroup} bindGroup - The bind group. 33435 */ 33436 deleteBindGroupData() { 33437 } 33438 /** 33439 * Frees internal resources. 33440 * 33441 * @abstract 33442 */ 33443 dispose() { 33444 } 33445}; 33446var _id$1 = 0; 33447var DualAttributeData = class { 33448 constructor(attributeData, dualBuffer) { 33449 this.buffers = [attributeData.bufferGPU, dualBuffer]; 33450 this.type = attributeData.type; 33451 this.bufferType = attributeData.bufferType; 33452 this.pbo = attributeData.pbo; 33453 this.byteLength = attributeData.byteLength; 33454 this.bytesPerElement = attributeData.BYTES_PER_ELEMENT; 33455 this.version = attributeData.version; 33456 this.isInteger = attributeData.isInteger; 33457 this.activeBufferIndex = 0; 33458 this.baseId = attributeData.id; 33459 } 33460 get id() { 33461 return `${this.baseId}|${this.activeBufferIndex}`; 33462 } 33463 get bufferGPU() { 33464 return this.buffers[this.activeBufferIndex]; 33465 } 33466 get transformBuffer() { 33467 return this.buffers[this.activeBufferIndex ^ 1]; 33468 } 33469 switchBuffers() { 33470 this.activeBufferIndex ^= 1; 33471 } 33472}; 33473var WebGLAttributeUtils = class { 33474 /** 33475 * Constructs a new utility object. 33476 * 33477 * @param {WebGLBackend} backend - The WebGL 2 backend. 33478 */ 33479 constructor(backend) { 33480 this.backend = backend; 33481 } 33482 /** 33483 * Creates the GPU buffer for the given buffer attribute. 33484 * 33485 * @param {BufferAttribute} attribute - The buffer attribute. 33486 * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. 33487 */ 33488 createAttribute(attribute3, bufferType) { 33489 const backend = this.backend; 33490 const { gl } = backend; 33491 const array3 = attribute3.array; 33492 const usage = attribute3.usage || gl.STATIC_DRAW; 33493 const bufferAttribute3 = attribute3.isInterleavedBufferAttribute ? attribute3.data : attribute3; 33494 const bufferData = backend.get(bufferAttribute3); 33495 let bufferGPU = bufferData.bufferGPU; 33496 if (bufferGPU === void 0) { 33497 bufferGPU = this._createBuffer(gl, bufferType, array3, usage); 33498 bufferData.bufferGPU = bufferGPU; 33499 bufferData.bufferType = bufferType; 33500 bufferData.version = bufferAttribute3.version; 33501 } 33502 let type; 33503 if (array3 instanceof Float32Array) { 33504 type = gl.FLOAT; 33505 } else if (typeof Float16Array !== "undefined" && array3 instanceof Float16Array) { 33506 type = gl.HALF_FLOAT; 33507 } else if (array3 instanceof Uint16Array) { 33508 if (attribute3.isFloat16BufferAttribute) { 33509 type = gl.HALF_FLOAT; 33510 } else { 33511 type = gl.UNSIGNED_SHORT; 33512 } 33513 } else if (array3 instanceof Int16Array) { 33514 type = gl.SHORT; 33515 } else if (array3 instanceof Uint32Array) { 33516 type = gl.UNSIGNED_INT; 33517 } else if (array3 instanceof Int32Array) { 33518 type = gl.INT; 33519 } else if (array3 instanceof Int8Array) { 33520 type = gl.BYTE; 33521 } else if (array3 instanceof Uint8Array) { 33522 type = gl.UNSIGNED_BYTE; 33523 } else if (array3 instanceof Uint8ClampedArray) { 33524 type = gl.UNSIGNED_BYTE; 33525 } else { 33526 throw new Error("THREE.WebGLBackend: Unsupported buffer data format: " + array3); 33527 } 33528 let attributeData = { 33529 bufferGPU, 33530 bufferType, 33531 type, 33532 byteLength: array3.byteLength, 33533 bytesPerElement: array3.BYTES_PER_ELEMENT, 33534 version: attribute3.version, 33535 pbo: attribute3.pbo, 33536 isInteger: type === gl.INT || type === gl.UNSIGNED_INT || attribute3.gpuType === IntType, 33537 id: _id$1++ 33538 }; 33539 if (attribute3.isStorageBufferAttribute || attribute3.isStorageInstancedBufferAttribute) { 33540 const bufferGPUDual = this._createBuffer(gl, bufferType, array3, usage); 33541 attributeData = new DualAttributeData(attributeData, bufferGPUDual); 33542 } 33543 backend.set(attribute3, attributeData); 33544 } 33545 /** 33546 * Updates the GPU buffer of the given buffer attribute. 33547 * 33548 * @param {BufferAttribute} attribute - The buffer attribute. 33549 */ 33550 updateAttribute(attribute3) { 33551 const backend = this.backend; 33552 const { gl } = backend; 33553 const array3 = attribute3.array; 33554 const bufferAttribute3 = attribute3.isInterleavedBufferAttribute ? attribute3.data : attribute3; 33555 const bufferData = backend.get(bufferAttribute3); 33556 const bufferType = bufferData.bufferType; 33557 const updateRanges = attribute3.isInterleavedBufferAttribute ? attribute3.data.updateRanges : attribute3.updateRanges; 33558 gl.bindBuffer(bufferType, bufferData.bufferGPU); 33559 if (updateRanges.length === 0) { 33560 gl.bufferSubData(bufferType, 0, array3); 33561 } else { 33562 for (let i = 0, l = updateRanges.length; i < l; i++) { 33563 const range3 = updateRanges[i]; 33564 gl.bufferSubData( 33565 bufferType, 33566 range3.start * array3.BYTES_PER_ELEMENT, 33567 array3, 33568 range3.start, 33569 range3.count 33570 ); 33571 } 33572 bufferAttribute3.clearUpdateRanges(); 33573 } 33574 gl.bindBuffer(bufferType, null); 33575 bufferData.version = bufferAttribute3.version; 33576 } 33577 /** 33578 * Destroys the GPU buffer of the given buffer attribute. 33579 * 33580 * @param {BufferAttribute} attribute - The buffer attribute. 33581 */ 33582 destroyAttribute(attribute3) { 33583 const backend = this.backend; 33584 const { gl } = backend; 33585 if (attribute3.isInterleavedBufferAttribute) { 33586 backend.delete(attribute3.data); 33587 } 33588 const attributeData = backend.get(attribute3); 33589 gl.deleteBuffer(attributeData.bufferGPU); 33590 backend.delete(attribute3); 33591 } 33592 /** 33593 * This method performs a readback operation by moving buffer data from 33594 * a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can 33595 * be used to retain and reuse handles to the intermediate buffers and prevent 33596 * new allocation. 33597 * 33598 * @async 33599 * @param {BufferAttribute} attribute - The storage buffer attribute to read frm. 33600 * @param {ReadbackBuffer|ArrayBuffer} target - The storage buffer attribute. 33601 * @param {number} offset - The storage buffer attribute. 33602 * @param {number} count - The offset from which to start reading the 33603 * @return {Promise<ArrayBuffer|ReadbackBuffer>} A promise that resolves with the buffer data when the data are ready. 33604 */ 33605 async getArrayBufferAsync(attribute3, target = null, offset3 = 0, count = -1) { 33606 const backend = this.backend; 33607 const { gl } = backend; 33608 const bufferAttribute3 = attribute3.isInterleavedBufferAttribute ? attribute3.data : attribute3; 33609 const attributeInfo = backend.get(bufferAttribute3); 33610 const { bufferGPU } = attributeInfo; 33611 const byteLength = count === -1 ? attributeInfo.byteLength - offset3 : count; 33612 let dstBuffer; 33613 if (target === null) { 33614 dstBuffer = new Uint8Array(new ArrayBuffer(byteLength)); 33615 } else if (target.isReadbackBuffer) { 33616 if (target._mapped === true) { 33617 throw new Error("WebGPURenderer: ReadbackBuffer must be released before being used again."); 33618 } 33619 const releaseCallback = () => { 33620 target.buffer = null; 33621 target._mapped = false; 33622 target.removeEventListener("release", releaseCallback); 33623 target.removeEventListener("dispose", releaseCallback); 33624 }; 33625 target.addEventListener("release", releaseCallback); 33626 target.addEventListener("dispose", releaseCallback); 33627 dstBuffer = new Uint8Array(new ArrayBuffer(byteLength)); 33628 target.buffer = dstBuffer.buffer; 33629 } else { 33630 dstBuffer = new Uint8Array(target); 33631 } 33632 gl.bindBuffer(gl.COPY_READ_BUFFER, bufferGPU); 33633 gl.getBufferSubData(gl.COPY_READ_BUFFER, offset3, dstBuffer); 33634 gl.bindBuffer(gl.COPY_READ_BUFFER, null); 33635 gl.bindBuffer(gl.COPY_WRITE_BUFFER, null); 33636 if (target && target.isReadbackBuffer) { 33637 return target; 33638 } else { 33639 return dstBuffer.buffer; 33640 } 33641 } 33642 /** 33643 * Creates a WebGL buffer with the given data. 33644 * 33645 * @private 33646 * @param {WebGL2RenderingContext} gl - The rendering context. 33647 * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. 33648 * @param {TypedArray} array - The array of the buffer attribute. 33649 * @param {GLenum} usage - The usage. 33650 * @return {WebGLBuffer} The WebGL buffer. 33651 */ 33652 _createBuffer(gl, bufferType, array3, usage) { 33653 const bufferGPU = gl.createBuffer(); 33654 gl.bindBuffer(bufferType, bufferGPU); 33655 gl.bufferData(bufferType, array3, usage); 33656 gl.bindBuffer(bufferType, null); 33657 return bufferGPU; 33658 } 33659}; 33660var equationToGL; 33661var factorToGL; 33662var WebGLState = class { 33663 /** 33664 * Constructs a new utility object. 33665 * 33666 * @param {WebGLBackend} backend - The WebGL 2 backend. 33667 */ 33668 constructor(backend) { 33669 this.backend = backend; 33670 this.gl = this.backend.gl; 33671 this.enabled = {}; 33672 this.parameters = {}; 33673 this.currentFlipSided = null; 33674 this.currentCullFace = null; 33675 this.currentProgram = null; 33676 this.currentBlendingEnabled = false; 33677 this.currentBlending = null; 33678 this.currentBlendSrc = null; 33679 this.currentBlendDst = null; 33680 this.currentBlendSrcAlpha = null; 33681 this.currentBlendDstAlpha = null; 33682 this.currentPremultipledAlpha = null; 33683 this.currentPolygonOffsetFactor = null; 33684 this.currentPolygonOffsetUnits = null; 33685 this.currentColorMask = null; 33686 this.currentDepthReversed = false; 33687 this.currentDepthFunc = null; 33688 this.currentDepthMask = null; 33689 this.currentStencilFunc = null; 33690 this.currentStencilRef = null; 33691 this.currentStencilFuncMask = null; 33692 this.currentStencilFail = null; 33693 this.currentStencilZFail = null; 33694 this.currentStencilZPass = null; 33695 this.currentStencilMask = null; 33696 this.currentLineWidth = null; 33697 this.currentClippingPlanes = 0; 33698 this.currentVAO = null; 33699 this.currentIndex = null; 33700 this.currentBoundFramebuffers = {}; 33701 this.currentDrawbuffers = /* @__PURE__ */ new WeakMap(); 33702 this.maxTextures = this.gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS); 33703 this.currentTextureSlot = null; 33704 this.currentBoundTextures = {}; 33705 this.currentBoundBufferBases = {}; 33706 this._init(); 33707 } 33708 /** 33709 * Inits the state of the utility. 33710 * 33711 * @private 33712 */ 33713 _init() { 33714 const gl = this.gl; 33715 equationToGL = { 33716 [AddEquation]: gl.FUNC_ADD, 33717 [SubtractEquation]: gl.FUNC_SUBTRACT, 33718 [ReverseSubtractEquation]: gl.FUNC_REVERSE_SUBTRACT 33719 }; 33720 factorToGL = { 33721 [ZeroFactor]: gl.ZERO, 33722 [OneFactor]: gl.ONE, 33723 [SrcColorFactor]: gl.SRC_COLOR, 33724 [SrcAlphaFactor]: gl.SRC_ALPHA, 33725 [SrcAlphaSaturateFactor]: gl.SRC_ALPHA_SATURATE, 33726 [DstColorFactor]: gl.DST_COLOR, 33727 [DstAlphaFactor]: gl.DST_ALPHA, 33728 [OneMinusSrcColorFactor]: gl.ONE_MINUS_SRC_COLOR, 33729 [OneMinusSrcAlphaFactor]: gl.ONE_MINUS_SRC_ALPHA, 33730 [OneMinusDstColorFactor]: gl.ONE_MINUS_DST_COLOR, 33731 [OneMinusDstAlphaFactor]: gl.ONE_MINUS_DST_ALPHA 33732 }; 33733 const scissorParam = gl.getParameter(gl.SCISSOR_BOX); 33734 const viewportParam = gl.getParameter(gl.VIEWPORT); 33735 this.currentScissor = new Vector4().fromArray(scissorParam); 33736 this.currentViewport = new Vector4().fromArray(viewportParam); 33737 this._tempVec4 = new Vector4(); 33738 } 33739 /** 33740 * Enables the given WebGL capability. 33741 * 33742 * This method caches the capability state so 33743 * `gl.enable()` is only called when necessary. 33744 * 33745 * @param {GLenum} id - The capability to enable. 33746 */ 33747 enable(id) { 33748 const { enabled } = this; 33749 if (enabled[id] !== true) { 33750 this.gl.enable(id); 33751 enabled[id] = true; 33752 } 33753 } 33754 /** 33755 * Disables the given WebGL capability. 33756 * 33757 * This method caches the capability state so 33758 * `gl.disable()` is only called when necessary. 33759 * 33760 * @param {GLenum} id - The capability to enable. 33761 */ 33762 disable(id) { 33763 const { enabled } = this; 33764 if (enabled[id] !== false) { 33765 this.gl.disable(id); 33766 enabled[id] = false; 33767 } 33768 } 33769 /** 33770 * Specifies whether polygons are front- or back-facing 33771 * by setting the winding orientation. 33772 * 33773 * This method caches the state so `gl.frontFace()` is only 33774 * called when necessary. 33775 * 33776 * @param {boolean} flipSided - Whether triangles flipped their sides or not. 33777 */ 33778 setFlipSided(flipSided) { 33779 if (this.currentFlipSided !== flipSided) { 33780 const { gl } = this; 33781 if (flipSided) { 33782 gl.frontFace(gl.CW); 33783 } else { 33784 gl.frontFace(gl.CCW); 33785 } 33786 this.currentFlipSided = flipSided; 33787 } 33788 } 33789 /** 33790 * Specifies whether or not front- and/or back-facing 33791 * polygons can be culled. 33792 * 33793 * This method caches the state so `gl.cullFace()` is only 33794 * called when necessary. 33795 * 33796 * @param {number} cullFace - Defines which polygons are candidates for culling. 33797 */ 33798 setCullFace(cullFace) { 33799 const { gl } = this; 33800 if (cullFace !== CullFaceNone) { 33801 this.enable(gl.CULL_FACE); 33802 if (cullFace !== this.currentCullFace) { 33803 if (cullFace === CullFaceBack) { 33804 gl.cullFace(gl.BACK); 33805 } else if (cullFace === CullFaceFront) { 33806 gl.cullFace(gl.FRONT); 33807 } else { 33808 gl.cullFace(gl.FRONT_AND_BACK); 33809 } 33810 } 33811 } else { 33812 this.disable(gl.CULL_FACE); 33813 } 33814 this.currentCullFace = cullFace; 33815 } 33816 /** 33817 * Specifies the width of line primitives. 33818 * 33819 * This method caches the state so `gl.lineWidth()` is only 33820 * called when necessary. 33821 * 33822 * @param {number} width - The line width. 33823 */ 33824 setLineWidth(width) { 33825 const { currentLineWidth, gl } = this; 33826 if (width !== currentLineWidth) { 33827 gl.lineWidth(width); 33828 this.currentLineWidth = width; 33829 } 33830 } 33831 setMRTBlending(textures, mrt3, material) { 33832 const gl = this.gl; 33833 const drawBuffersIndexedExt = this.backend.drawBuffersIndexedExt; 33834 if (!drawBuffersIndexedExt) { 33835 warnOnce("WebGPURenderer: Multiple Render Targets (MRT) blending configuration is not fully supported in compatibility mode. The material blending will be used for all render targets."); 33836 return; 33837 } 33838 for (let i = 0; i < textures.length; i++) { 33839 const texture3 = textures[i]; 33840 let blending = null; 33841 if (mrt3 !== null) { 33842 const blendMode = mrt3.getBlendMode(texture3.name); 33843 if (blendMode.blending === MaterialBlending) { 33844 blending = material; 33845 } else if (blendMode.blending !== NoBlending) { 33846 blending = blendMode; 33847 } 33848 } else { 33849 blending = material; 33850 } 33851 if (blending !== null) { 33852 this._setMRTBlendingIndex(i, blending); 33853 } else { 33854 drawBuffersIndexedExt.blendFuncSeparateiOES(i, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO); 33855 } 33856 } 33857 } 33858 /** 33859 * Applies blending configuration for a specific draw buffer index. 33860 * 33861 * @private 33862 * @param {number} index - The draw buffer index. 33863 * @param {Object} blending - The blending configuration (material or BlendMode). 33864 */ 33865 _setMRTBlendingIndex(index, blending) { 33866 const { gl } = this; 33867 const drawBuffersIndexedExt = this.backend.drawBuffersIndexedExt; 33868 const blendingType = blending.blending; 33869 const blendSrc = blending.blendSrc; 33870 const blendDst = blending.blendDst; 33871 const blendEquation = blending.blendEquation; 33872 const premultipliedAlpha = blending.premultipliedAlpha; 33873 if (blendingType === CustomBlending) { 33874 const blendSrcAlpha = blending.blendSrcAlpha !== null ? blending.blendSrcAlpha : blendSrc; 33875 const blendDstAlpha = blending.blendDstAlpha !== null ? blending.blendDstAlpha : blendDst; 33876 const blendEquationAlpha = blending.blendEquationAlpha !== null ? blending.blendEquationAlpha : blendEquation; 33877 drawBuffersIndexedExt.blendEquationSeparateiOES(index, equationToGL[blendEquation], equationToGL[blendEquationAlpha]); 33878 drawBuffersIndexedExt.blendFuncSeparateiOES(index, factorToGL[blendSrc], factorToGL[blendDst], factorToGL[blendSrcAlpha], factorToGL[blendDstAlpha]); 33879 } else { 33880 drawBuffersIndexedExt.blendEquationSeparateiOES(index, gl.FUNC_ADD, gl.FUNC_ADD); 33881 if (premultipliedAlpha) { 33882 switch (blendingType) { 33883 case NormalBlending: 33884 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33885 break; 33886 case AdditiveBlending: 33887 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.ONE, gl.ONE, gl.ONE, gl.ONE); 33888 break; 33889 case SubtractiveBlending: 33890 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 33891 break; 33892 case MultiplyBlending: 33893 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE); 33894 break; 33895 default: 33896 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33897 break; 33898 } 33899 } else { 33900 switch (blendingType) { 33901 case NormalBlending: 33902 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33903 break; 33904 case AdditiveBlending: 33905 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE); 33906 break; 33907 case SubtractiveBlending: 33908 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 33909 break; 33910 case MultiplyBlending: 33911 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE); 33912 break; 33913 default: 33914 drawBuffersIndexedExt.blendFuncSeparateiOES(index, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33915 break; 33916 } 33917 } 33918 } 33919 } 33920 /** 33921 * Defines the blending. 33922 * 33923 * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, 33924 * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. 33925 * 33926 * @param {number} blending - The blending type. 33927 * @param {number} blendEquation - The blending equation. 33928 * @param {number} blendSrc - Only relevant for custom blending. The RGB source blending factor. 33929 * @param {number} blendDst - Only relevant for custom blending. The RGB destination blending factor. 33930 * @param {number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. 33931 * @param {number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. 33932 * @param {number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. 33933 * @param {boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. 33934 */ 33935 setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha) { 33936 const { gl } = this; 33937 if (blending === NoBlending) { 33938 if (this.currentBlendingEnabled === true) { 33939 this.disable(gl.BLEND); 33940 this.currentBlendingEnabled = false; 33941 } 33942 return; 33943 } 33944 if (this.currentBlendingEnabled === false) { 33945 this.enable(gl.BLEND); 33946 this.currentBlendingEnabled = true; 33947 } 33948 if (blending !== CustomBlending) { 33949 if (blending !== this.currentBlending || premultipliedAlpha !== this.currentPremultipledAlpha) { 33950 if (this.currentBlendEquation !== AddEquation || this.currentBlendEquationAlpha !== AddEquation) { 33951 gl.blendEquation(gl.FUNC_ADD); 33952 this.currentBlendEquation = AddEquation; 33953 this.currentBlendEquationAlpha = AddEquation; 33954 } 33955 if (premultipliedAlpha) { 33956 switch (blending) { 33957 case NormalBlending: 33958 gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33959 break; 33960 case AdditiveBlending: 33961 gl.blendFunc(gl.ONE, gl.ONE); 33962 break; 33963 case SubtractiveBlending: 33964 gl.blendFuncSeparate(gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 33965 break; 33966 case MultiplyBlending: 33967 gl.blendFuncSeparate(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE); 33968 break; 33969 default: 33970 error("WebGLState: Invalid blending: ", blending); 33971 break; 33972 } 33973 } else { 33974 switch (blending) { 33975 case NormalBlending: 33976 gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 33977 break; 33978 case AdditiveBlending: 33979 gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE); 33980 break; 33981 case SubtractiveBlending: 33982 error("WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true"); 33983 break; 33984 case MultiplyBlending: 33985 error("WebGLState: MultiplyBlending requires material.premultipliedAlpha = true"); 33986 break; 33987 default: 33988 error("WebGLState: Invalid blending: ", blending); 33989 break; 33990 } 33991 } 33992 this.currentBlendSrc = null; 33993 this.currentBlendDst = null; 33994 this.currentBlendSrcAlpha = null; 33995 this.currentBlendDstAlpha = null; 33996 this.currentBlending = blending; 33997 this.currentPremultipledAlpha = premultipliedAlpha; 33998 } 33999 return; 34000 } 34001 blendEquationAlpha = blendEquationAlpha || blendEquation; 34002 blendSrcAlpha = blendSrcAlpha || blendSrc; 34003 blendDstAlpha = blendDstAlpha || blendDst; 34004 if (blendEquation !== this.currentBlendEquation || blendEquationAlpha !== this.currentBlendEquationAlpha) { 34005 gl.blendEquationSeparate(equationToGL[blendEquation], equationToGL[blendEquationAlpha]); 34006 this.currentBlendEquation = blendEquation; 34007 this.currentBlendEquationAlpha = blendEquationAlpha; 34008 } 34009 if (blendSrc !== this.currentBlendSrc || blendDst !== this.currentBlendDst || blendSrcAlpha !== this.currentBlendSrcAlpha || blendDstAlpha !== this.currentBlendDstAlpha) { 34010 gl.blendFuncSeparate(factorToGL[blendSrc], factorToGL[blendDst], factorToGL[blendSrcAlpha], factorToGL[blendDstAlpha]); 34011 this.currentBlendSrc = blendSrc; 34012 this.currentBlendDst = blendDst; 34013 this.currentBlendSrcAlpha = blendSrcAlpha; 34014 this.currentBlendDstAlpha = blendDstAlpha; 34015 } 34016 this.currentBlending = blending; 34017 this.currentPremultipledAlpha = false; 34018 } 34019 /** 34020 * Specifies whether colors can be written when rendering 34021 * into a framebuffer or not. 34022 * 34023 * This method caches the state so `gl.colorMask()` is only 34024 * called when necessary. 34025 * 34026 * @param {boolean} colorMask - The color mask. 34027 */ 34028 setColorMask(colorMask) { 34029 if (this.currentColorMask !== colorMask) { 34030 this.gl.colorMask(colorMask, colorMask, colorMask, colorMask); 34031 this.currentColorMask = colorMask; 34032 } 34033 } 34034 /** 34035 * Specifies whether the depth test is enabled or not. 34036 * 34037 * @param {boolean} depthTest - Whether the depth test is enabled or not. 34038 */ 34039 setDepthTest(depthTest) { 34040 const { gl } = this; 34041 if (depthTest) { 34042 this.enable(gl.DEPTH_TEST); 34043 } else { 34044 this.disable(gl.DEPTH_TEST); 34045 } 34046 } 34047 /** 34048 * Configures the WebGL state to use a reversed depth buffer. 34049 * 34050 * @param {boolean} reversed - Whether the depth buffer is reversed or not. 34051 */ 34052 setReversedDepth(reversed) { 34053 if (this.currentDepthReversed !== reversed) { 34054 const ext = this.backend.extensions.get("EXT_clip_control"); 34055 if (reversed) { 34056 ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT); 34057 } else { 34058 ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); 34059 } 34060 this.currentDepthReversed = reversed; 34061 } 34062 } 34063 /** 34064 * Specifies whether depth values can be written when rendering 34065 * into a framebuffer or not. 34066 * 34067 * This method caches the state so `gl.depthMask()` is only 34068 * called when necessary. 34069 * 34070 * @param {boolean} depthMask - The depth mask. 34071 */ 34072 setDepthMask(depthMask) { 34073 if (this.currentDepthMask !== depthMask) { 34074 this.gl.depthMask(depthMask); 34075 this.currentDepthMask = depthMask; 34076 } 34077 } 34078 /** 34079 * Specifies the depth compare function. 34080 * 34081 * This method caches the state so `gl.depthFunc()` is only 34082 * called when necessary. 34083 * 34084 * @param {number} depthFunc - The depth compare function. 34085 */ 34086 setDepthFunc(depthFunc) { 34087 if (this.currentDepthReversed) depthFunc = ReversedDepthFuncs[depthFunc]; 34088 if (this.currentDepthFunc !== depthFunc) { 34089 const { gl } = this; 34090 switch (depthFunc) { 34091 case NeverDepth: 34092 gl.depthFunc(gl.NEVER); 34093 break; 34094 case AlwaysDepth: 34095 gl.depthFunc(gl.ALWAYS); 34096 break; 34097 case LessDepth: 34098 gl.depthFunc(gl.LESS); 34099 break; 34100 case LessEqualDepth: 34101 gl.depthFunc(gl.LEQUAL); 34102 break; 34103 case EqualDepth: 34104 gl.depthFunc(gl.EQUAL); 34105 break; 34106 case GreaterEqualDepth: 34107 gl.depthFunc(gl.GEQUAL); 34108 break; 34109 case GreaterDepth: 34110 gl.depthFunc(gl.GREATER); 34111 break; 34112 case NotEqualDepth: 34113 gl.depthFunc(gl.NOTEQUAL); 34114 break; 34115 default: 34116 gl.depthFunc(gl.LEQUAL); 34117 } 34118 this.currentDepthFunc = depthFunc; 34119 } 34120 } 34121 /** 34122 * Specifies the scissor box. 34123 * 34124 * @param {number} x - The x-coordinate of the lower left corner of the viewport. 34125 * @param {number} y - The y-coordinate of the lower left corner of the viewport. 34126 * @param {number} width - The width of the viewport. 34127 * @param {number} height - The height of the viewport. 34128 * 34129 */ 34130 scissor(x, y, width, height) { 34131 const scissor = this._tempVec4.set(x, y, width, height); 34132 if (this.currentScissor.equals(scissor) === false) { 34133 const { gl } = this; 34134 gl.scissor(scissor.x, scissor.y, scissor.z, scissor.w); 34135 this.currentScissor.copy(scissor); 34136 } 34137 } 34138 /** 34139 * Specifies the viewport. 34140 * 34141 * @param {number} x - The x-coordinate of the lower left corner of the viewport. 34142 * @param {number} y - The y-coordinate of the lower left corner of the viewport. 34143 * @param {number} width - The width of the viewport. 34144 * @param {number} height - The height of the viewport. 34145 * 34146 */ 34147 viewport(x, y, width, height) { 34148 const viewport3 = this._tempVec4.set(x, y, width, height); 34149 if (this.currentViewport.equals(viewport3) === false) { 34150 const { gl } = this; 34151 gl.viewport(viewport3.x, viewport3.y, viewport3.z, viewport3.w); 34152 this.currentViewport.copy(viewport3); 34153 } 34154 } 34155 /** 34156 * Defines the scissor test. 34157 * 34158 * @param {boolean} boolean - Whether the scissor test should be enabled or not. 34159 */ 34160 setScissorTest(boolean) { 34161 const gl = this.gl; 34162 if (boolean) { 34163 this.enable(gl.SCISSOR_TEST); 34164 } else { 34165 this.disable(gl.SCISSOR_TEST); 34166 } 34167 } 34168 /** 34169 * Specifies whether the stencil test is enabled or not. 34170 * 34171 * @param {boolean} stencilTest - Whether the stencil test is enabled or not. 34172 */ 34173 setStencilTest(stencilTest) { 34174 const { gl } = this; 34175 if (stencilTest) { 34176 this.enable(gl.STENCIL_TEST); 34177 } else { 34178 this.disable(gl.STENCIL_TEST); 34179 } 34180 } 34181 /** 34182 * Specifies whether stencil values can be written when rendering 34183 * into a framebuffer or not. 34184 * 34185 * This method caches the state so `gl.stencilMask()` is only 34186 * called when necessary. 34187 * 34188 * @param {boolean} stencilMask - The stencil mask. 34189 */ 34190 setStencilMask(stencilMask) { 34191 if (this.currentStencilMask !== stencilMask) { 34192 this.gl.stencilMask(stencilMask); 34193 this.currentStencilMask = stencilMask; 34194 } 34195 } 34196 /** 34197 * Specifies whether the stencil test functions. 34198 * 34199 * This method caches the state so `gl.stencilFunc()` is only 34200 * called when necessary. 34201 * 34202 * @param {number} stencilFunc - The stencil compare function. 34203 * @param {number} stencilRef - The reference value for the stencil test. 34204 * @param {number} stencilMask - A bit-wise mask that is used to AND the reference value and the stored stencil value when the test is done. 34205 */ 34206 setStencilFunc(stencilFunc, stencilRef, stencilMask) { 34207 if (this.currentStencilFunc !== stencilFunc || this.currentStencilRef !== stencilRef || this.currentStencilFuncMask !== stencilMask) { 34208 this.gl.stencilFunc(stencilFunc, stencilRef, stencilMask); 34209 this.currentStencilFunc = stencilFunc; 34210 this.currentStencilRef = stencilRef; 34211 this.currentStencilFuncMask = stencilMask; 34212 } 34213 } 34214 /** 34215 * Specifies whether the stencil test operation. 34216 * 34217 * This method caches the state so `gl.stencilOp()` is only 34218 * called when necessary. 34219 * 34220 * @param {number} stencilFail - The function to use when the stencil test fails. 34221 * @param {number} stencilZFail - The function to use when the stencil test passes, but the depth test fail. 34222 * @param {number} stencilZPass - The function to use when both the stencil test and the depth test pass, 34223 * or when the stencil test passes and there is no depth buffer or depth testing is disabled. 34224 */ 34225 setStencilOp(stencilFail, stencilZFail, stencilZPass) { 34226 if (this.currentStencilFail !== stencilFail || this.currentStencilZFail !== stencilZFail || this.currentStencilZPass !== stencilZPass) { 34227 this.gl.stencilOp(stencilFail, stencilZFail, stencilZPass); 34228 this.currentStencilFail = stencilFail; 34229 this.currentStencilZFail = stencilZFail; 34230 this.currentStencilZPass = stencilZPass; 34231 } 34232 } 34233 /** 34234 * Configures the WebGL state for the given material. 34235 * 34236 * @param {Material} material - The material to configure the state for. 34237 * @param {number} frontFaceCW - Whether the front faces are counter-clockwise or not. 34238 * @param {number} hardwareClippingPlanes - The number of hardware clipping planes. 34239 */ 34240 setMaterial(material, frontFaceCW, hardwareClippingPlanes) { 34241 const { gl } = this; 34242 material.side === DoubleSide ? this.disable(gl.CULL_FACE) : this.enable(gl.CULL_FACE); 34243 let flipSided = material.side === BackSide; 34244 if (frontFaceCW) flipSided = !flipSided; 34245 this.setFlipSided(flipSided); 34246 material.blending === NormalBlending && material.transparent === false ? this.setBlending(NoBlending) : this.setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha); 34247 this.setDepthFunc(material.depthFunc); 34248 this.setDepthTest(material.depthTest); 34249 this.setDepthMask(material.depthWrite); 34250 this.setColorMask(material.colorWrite); 34251 const stencilWrite = material.stencilWrite; 34252 this.setStencilTest(stencilWrite); 34253 if (stencilWrite) { 34254 this.setStencilMask(material.stencilWriteMask); 34255 this.setStencilFunc(material.stencilFunc, material.stencilRef, material.stencilFuncMask); 34256 this.setStencilOp(material.stencilFail, material.stencilZFail, material.stencilZPass); 34257 } 34258 this.setPolygonOffset(material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits); 34259 material.alphaToCoverage === true && this.backend.renderer.currentSamples > 0 ? this.enable(gl.SAMPLE_ALPHA_TO_COVERAGE) : this.disable(gl.SAMPLE_ALPHA_TO_COVERAGE); 34260 if (hardwareClippingPlanes > 0) { 34261 if (this.currentClippingPlanes !== hardwareClippingPlanes) { 34262 const CLIP_DISTANCE0_WEBGL = 12288; 34263 for (let i = 0; i < 8; i++) { 34264 if (i < hardwareClippingPlanes) { 34265 this.enable(CLIP_DISTANCE0_WEBGL + i); 34266 } else { 34267 this.disable(CLIP_DISTANCE0_WEBGL + i); 34268 } 34269 } 34270 } 34271 } 34272 } 34273 /** 34274 * Specifies the polygon offset. 34275 * 34276 * This method caches the state so `gl.polygonOffset()` is only 34277 * called when necessary. 34278 * 34279 * @param {boolean} polygonOffset - Whether polygon offset is enabled or not. 34280 * @param {number} factor - The scale factor for the variable depth offset for each polygon. 34281 * @param {number} units - The multiplier by which an implementation-specific value is multiplied with to create a constant depth offset. 34282 */ 34283 setPolygonOffset(polygonOffset, factor, units) { 34284 const { gl } = this; 34285 if (polygonOffset) { 34286 this.enable(gl.POLYGON_OFFSET_FILL); 34287 if (this.currentPolygonOffsetFactor !== factor || this.currentPolygonOffsetUnits !== units) { 34288 gl.polygonOffset(factor, units); 34289 this.currentPolygonOffsetFactor = factor; 34290 this.currentPolygonOffsetUnits = units; 34291 } 34292 } else { 34293 this.disable(gl.POLYGON_OFFSET_FILL); 34294 } 34295 } 34296 /** 34297 * Defines the usage of the given WebGL program. 34298 * 34299 * This method caches the state so `gl.useProgram()` is only 34300 * called when necessary. 34301 * 34302 * @param {WebGLProgram} program - The WebGL program to use. 34303 * @return {boolean} Whether a program change has been executed or not. 34304 */ 34305 useProgram(program) { 34306 if (this.currentProgram !== program) { 34307 this.gl.useProgram(program); 34308 this.currentProgram = program; 34309 return true; 34310 } 34311 return false; 34312 } 34313 /** 34314 * Sets the vertex state by binding the given VAO and element buffer. 34315 * 34316 * @param {WebGLVertexArrayObject} vao - The VAO. 34317 * @param {?WebGLBuffer} indexBuffer - The index buffer. 34318 * @return {boolean} Whether a vertex state has been changed or not. 34319 */ 34320 setVertexState(vao, indexBuffer = null) { 34321 const gl = this.gl; 34322 if (this.currentVAO !== vao || this.currentIndex !== indexBuffer) { 34323 gl.bindVertexArray(vao); 34324 if (indexBuffer !== null) { 34325 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 34326 } 34327 this.currentVAO = vao; 34328 this.currentIndex = indexBuffer; 34329 return true; 34330 } 34331 return false; 34332 } 34333 /** 34334 * Resets the vertex array state by resetting the VAO and element buffer. 34335 */ 34336 resetVertexState() { 34337 const gl = this.gl; 34338 gl.bindVertexArray(null); 34339 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 34340 this.currentVAO = null; 34341 this.currentIndex = null; 34342 } 34343 // framebuffer 34344 /** 34345 * Binds the given framebuffer. 34346 * 34347 * This method caches the state so `gl.bindFramebuffer()` is only 34348 * called when necessary. 34349 * 34350 * @param {number} target - The binding point (target). 34351 * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer to bind. 34352 * @return {boolean} Whether a bind has been executed or not. 34353 */ 34354 bindFramebuffer(target, framebuffer) { 34355 const { gl, currentBoundFramebuffers } = this; 34356 if (currentBoundFramebuffers[target] !== framebuffer) { 34357 gl.bindFramebuffer(target, framebuffer); 34358 currentBoundFramebuffers[target] = framebuffer; 34359 if (target === gl.DRAW_FRAMEBUFFER) { 34360 currentBoundFramebuffers[gl.FRAMEBUFFER] = framebuffer; 34361 } 34362 if (target === gl.FRAMEBUFFER) { 34363 currentBoundFramebuffers[gl.DRAW_FRAMEBUFFER] = framebuffer; 34364 } 34365 return true; 34366 } 34367 return false; 34368 } 34369 /** 34370 * Defines draw buffers to which fragment colors are written into. 34371 * Configures the MRT setup of custom framebuffers. 34372 * 34373 * This method caches the state so `gl.drawBuffers()` is only 34374 * called when necessary. 34375 * 34376 * @param {RenderContext} renderContext - The render context. 34377 * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer. 34378 */ 34379 drawBuffers(renderContext, framebuffer) { 34380 const { gl } = this; 34381 let drawBuffers = []; 34382 let needsUpdate = false; 34383 if (renderContext.textures !== null) { 34384 drawBuffers = this.currentDrawbuffers.get(framebuffer); 34385 if (drawBuffers === void 0) { 34386 drawBuffers = []; 34387 this.currentDrawbuffers.set(framebuffer, drawBuffers); 34388 } 34389 const textures = renderContext.textures; 34390 if (drawBuffers.length !== textures.length || drawBuffers[0] !== gl.COLOR_ATTACHMENT0) { 34391 for (let i = 0, il = textures.length; i < il; i++) { 34392 drawBuffers[i] = gl.COLOR_ATTACHMENT0 + i; 34393 } 34394 drawBuffers.length = textures.length; 34395 needsUpdate = true; 34396 } 34397 } else { 34398 if (drawBuffers[0] !== gl.BACK) { 34399 drawBuffers[0] = gl.BACK; 34400 needsUpdate = true; 34401 } 34402 } 34403 if (needsUpdate) { 34404 gl.drawBuffers(drawBuffers); 34405 } 34406 } 34407 // texture 34408 /** 34409 * Makes the given texture unit active. 34410 * 34411 * This method caches the state so `gl.activeTexture()` is only 34412 * called when necessary. 34413 * 34414 * @param {number} webglSlot - The texture unit to make active. 34415 */ 34416 activeTexture(webglSlot) { 34417 const { gl, currentTextureSlot, maxTextures } = this; 34418 if (webglSlot === void 0) webglSlot = gl.TEXTURE0 + maxTextures - 1; 34419 if (currentTextureSlot !== webglSlot) { 34420 gl.activeTexture(webglSlot); 34421 this.currentTextureSlot = webglSlot; 34422 } 34423 } 34424 /** 34425 * Binds the given WebGL texture to a target. 34426 * 34427 * This method caches the state so `gl.bindTexture()` is only 34428 * called when necessary. 34429 * 34430 * @param {number} webglType - The binding point (target). 34431 * @param {WebGLTexture} webglTexture - The WebGL texture to bind. 34432 * @param {number} webglSlot - The texture. 34433 */ 34434 bindTexture(webglType, webglTexture, webglSlot) { 34435 const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this; 34436 if (webglSlot === void 0) { 34437 if (currentTextureSlot === null) { 34438 webglSlot = gl.TEXTURE0 + maxTextures - 1; 34439 } else { 34440 webglSlot = currentTextureSlot; 34441 } 34442 } 34443 let boundTexture = currentBoundTextures[webglSlot]; 34444 if (boundTexture === void 0) { 34445 boundTexture = { type: void 0, texture: void 0 }; 34446 currentBoundTextures[webglSlot] = boundTexture; 34447 } 34448 if (boundTexture.type !== webglType || boundTexture.texture !== webglTexture) { 34449 if (currentTextureSlot !== webglSlot) { 34450 gl.activeTexture(webglSlot); 34451 this.currentTextureSlot = webglSlot; 34452 } 34453 gl.bindTexture(webglType, webglTexture); 34454 boundTexture.type = webglType; 34455 boundTexture.texture = webglTexture; 34456 } 34457 } 34458 /** 34459 * Binds a given WebGL buffer to a given binding point (target) at a given index. 34460 * 34461 * This method caches the state so `gl.bindBufferBase()` is only 34462 * called when necessary. 34463 * 34464 * @param {number} target - The target for the bind operation. 34465 * @param {number} index - The index of the target. 34466 * @param {WebGLBuffer} buffer - The WebGL buffer. 34467 * @return {boolean} Whether a bind has been executed or not. 34468 */ 34469 bindBufferBase(target, index, buffer3) { 34470 const { gl } = this; 34471 const key = `${target}-${index}`; 34472 if (this.currentBoundBufferBases[key] !== buffer3) { 34473 gl.bindBufferBase(target, index, buffer3); 34474 this.currentBoundBufferBases[key] = buffer3; 34475 return true; 34476 } 34477 return false; 34478 } 34479 /** 34480 * Unbinds the current bound texture. 34481 * 34482 * This method caches the state so `gl.bindTexture()` is only 34483 * called when necessary. 34484 */ 34485 unbindTexture() { 34486 const { gl, currentTextureSlot, currentBoundTextures } = this; 34487 const boundTexture = currentBoundTextures[currentTextureSlot]; 34488 if (boundTexture !== void 0 && boundTexture.type !== void 0) { 34489 gl.bindTexture(boundTexture.type, null); 34490 boundTexture.type = void 0; 34491 boundTexture.texture = void 0; 34492 } 34493 } 34494 /** 34495 * Returns the value for the given parameter. 34496 * 34497 * @param {number} name - The paramter to get the value for. 34498 * @return {any} The value for the given parameter. 34499 */ 34500 getParameter(name) { 34501 const { gl, parameters } = this; 34502 if (parameters[name] !== void 0) { 34503 return parameters[name]; 34504 } else { 34505 return gl.getParameter(name); 34506 } 34507 } 34508 /** 34509 * Specifies a pixel storage mode. 34510 * 34511 * @param {number} name - The parameter to set. 34512 * @param {any} value - A value to set the parameter to. 34513 */ 34514 pixelStorei(name, value) { 34515 const { gl, parameters } = this; 34516 if (parameters[name] !== value) { 34517 gl.pixelStorei(name, value); 34518 parameters[name] = value; 34519 } 34520 } 34521}; 34522var WebGLUtils = class { 34523 /** 34524 * Constructs a new utility object. 34525 * 34526 * @param {WebGLBackend} backend - The WebGL 2 backend. 34527 */ 34528 constructor(backend) { 34529 this.backend = backend; 34530 this.gl = this.backend.gl; 34531 this.extensions = backend.extensions; 34532 } 34533 /** 34534 * Converts the given three.js constant into a WebGL constant. 34535 * The method currently supports the conversion of texture formats 34536 * and types. 34537 * 34538 * @param {number} p - The three.js constant. 34539 * @param {string} [colorSpace=NoColorSpace] - The color space. 34540 * @return {?number} The corresponding WebGL constant. 34541 */ 34542 convert(p, colorSpace = NoColorSpace) { 34543 const { gl, extensions } = this; 34544 let extension; 34545 const transfer = ColorManagement.getTransfer(colorSpace); 34546 if (p === UnsignedByteType) return gl.UNSIGNED_BYTE; 34547 if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4; 34548 if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1; 34549 if (p === UnsignedInt5999Type) return gl.UNSIGNED_INT_5_9_9_9_REV; 34550 if (p === UnsignedInt101111Type) return gl.UNSIGNED_INT_10F_11F_11F_REV; 34551 if (p === ByteType) return gl.BYTE; 34552 if (p === ShortType) return gl.SHORT; 34553 if (p === UnsignedShortType) return gl.UNSIGNED_SHORT; 34554 if (p === IntType) return gl.INT; 34555 if (p === UnsignedIntType) return gl.UNSIGNED_INT; 34556 if (p === FloatType) return gl.FLOAT; 34557 if (p === HalfFloatType) { 34558 return gl.HALF_FLOAT; 34559 } 34560 if (p === AlphaFormat) return gl.ALPHA; 34561 if (p === RGBFormat) return gl.RGB; 34562 if (p === RGBAFormat) return gl.RGBA; 34563 if (p === DepthFormat) return gl.DEPTH_COMPONENT; 34564 if (p === DepthStencilFormat) return gl.DEPTH_STENCIL; 34565 if (p === RedFormat) return gl.RED; 34566 if (p === RedIntegerFormat) return gl.RED_INTEGER; 34567 if (p === RGFormat) return gl.RG; 34568 if (p === RGIntegerFormat) return gl.RG_INTEGER; 34569 if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER; 34570 if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) { 34571 if (transfer === SRGBTransfer) { 34572 extension = extensions.get("WEBGL_compressed_texture_s3tc_srgb"); 34573 if (extension !== null) { 34574 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; 34575 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; 34576 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; 34577 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; 34578 } else { 34579 return null; 34580 } 34581 } else { 34582 extension = extensions.get("WEBGL_compressed_texture_s3tc"); 34583 if (extension !== null) { 34584 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 34585 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 34586 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 34587 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 34588 } else { 34589 return null; 34590 } 34591 } 34592 } 34593 if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) { 34594 extension = extensions.get("WEBGL_compressed_texture_pvrtc"); 34595 if (extension !== null) { 34596 if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 34597 if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 34598 if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 34599 if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 34600 } else { 34601 return null; 34602 } 34603 } 34604 if (p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format || p === R11_EAC_Format || p === SIGNED_R11_EAC_Format || p === RG11_EAC_Format || p === SIGNED_RG11_EAC_Format) { 34605 extension = extensions.get("WEBGL_compressed_texture_etc"); 34606 if (extension !== null) { 34607 if (p === RGB_ETC1_Format || p === RGB_ETC2_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; 34608 if (p === RGBA_ETC2_EAC_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; 34609 if (p === R11_EAC_Format) return extension.COMPRESSED_R11_EAC; 34610 if (p === SIGNED_R11_EAC_Format) return extension.COMPRESSED_SIGNED_R11_EAC; 34611 if (p === RG11_EAC_Format) return extension.COMPRESSED_RG11_EAC; 34612 if (p === SIGNED_RG11_EAC_Format) return extension.COMPRESSED_SIGNED_RG11_EAC; 34613 } else { 34614 return null; 34615 } 34616 } 34617 if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) { 34618 extension = extensions.get("WEBGL_compressed_texture_astc"); 34619 if (extension !== null) { 34620 if (p === RGBA_ASTC_4x4_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; 34621 if (p === RGBA_ASTC_5x4_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; 34622 if (p === RGBA_ASTC_5x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; 34623 if (p === RGBA_ASTC_6x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; 34624 if (p === RGBA_ASTC_6x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; 34625 if (p === RGBA_ASTC_8x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; 34626 if (p === RGBA_ASTC_8x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; 34627 if (p === RGBA_ASTC_8x8_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; 34628 if (p === RGBA_ASTC_10x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; 34629 if (p === RGBA_ASTC_10x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; 34630 if (p === RGBA_ASTC_10x8_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; 34631 if (p === RGBA_ASTC_10x10_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; 34632 if (p === RGBA_ASTC_12x10_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; 34633 if (p === RGBA_ASTC_12x12_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; 34634 } else { 34635 return null; 34636 } 34637 } 34638 if (p === RGBA_BPTC_Format) { 34639 extension = extensions.get("EXT_texture_compression_bptc"); 34640 if (extension !== null) { 34641 if (p === RGBA_BPTC_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; 34642 } else { 34643 return null; 34644 } 34645 } 34646 if (p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format) { 34647 extension = extensions.get("EXT_texture_compression_rgtc"); 34648 if (extension !== null) { 34649 if (p === RED_RGTC1_Format) return extension.COMPRESSED_RED_RGTC1_EXT; 34650 if (p === SIGNED_RED_RGTC1_Format) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; 34651 if (p === RED_GREEN_RGTC2_Format) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; 34652 if (p === SIGNED_RED_GREEN_RGTC2_Format) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; 34653 } else { 34654 return null; 34655 } 34656 } 34657 if (p === UnsignedInt248Type) { 34658 return gl.UNSIGNED_INT_24_8; 34659 } 34660 return gl[p] !== void 0 ? gl[p] : null; 34661 } 34662 /** 34663 * This method can be used to synchronize the CPU with the GPU by waiting until 34664 * ongoing GPU commands have been completed. 34665 * 34666 * @private 34667 * @return {Promise} A promise that resolves when all ongoing GPU commands have been completed. 34668 */ 34669 _clientWaitAsync() { 34670 const { gl } = this; 34671 const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0); 34672 gl.flush(); 34673 return new Promise((resolve, reject) => { 34674 function test() { 34675 const res = gl.clientWaitSync(sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0); 34676 if (res === gl.WAIT_FAILED) { 34677 gl.deleteSync(sync); 34678 reject(); 34679 return; 34680 } 34681 if (res === gl.TIMEOUT_EXPIRED) { 34682 requestAnimationFrame(test); 34683 return; 34684 } 34685 gl.deleteSync(sync); 34686 resolve(); 34687 } 34688 test(); 34689 }); 34690 } 34691}; 34692var initialized = false; 34693var wrappingToGL; 34694var filterToGL; 34695var compareToGL; 34696var WebGLTextureUtils = class { 34697 /** 34698 * Constructs a new utility object. 34699 * 34700 * @param {WebGLBackend} backend - The WebGL 2 backend. 34701 */ 34702 constructor(backend) { 34703 this.backend = backend; 34704 this.gl = backend.gl; 34705 this.extensions = backend.extensions; 34706 this.defaultTextures = {}; 34707 this._srcFramebuffer = null; 34708 this._dstFramebuffer = null; 34709 if (initialized === false) { 34710 this._init(); 34711 initialized = true; 34712 } 34713 } 34714 /** 34715 * Inits the state of the utility. 34716 * 34717 * @private 34718 */ 34719 _init() { 34720 const gl = this.gl; 34721 wrappingToGL = { 34722 [RepeatWrapping]: gl.REPEAT, 34723 [ClampToEdgeWrapping]: gl.CLAMP_TO_EDGE, 34724 [MirroredRepeatWrapping]: gl.MIRRORED_REPEAT 34725 }; 34726 filterToGL = { 34727 [NearestFilter]: gl.NEAREST, 34728 [NearestMipmapNearestFilter]: gl.NEAREST_MIPMAP_NEAREST, 34729 [NearestMipmapLinearFilter]: gl.NEAREST_MIPMAP_LINEAR, 34730 [LinearFilter]: gl.LINEAR, 34731 [LinearMipmapNearestFilter]: gl.LINEAR_MIPMAP_NEAREST, 34732 [LinearMipmapLinearFilter]: gl.LINEAR_MIPMAP_LINEAR 34733 }; 34734 compareToGL = { 34735 [NeverCompare]: gl.NEVER, 34736 [AlwaysCompare]: gl.ALWAYS, 34737 [LessCompare]: gl.LESS, 34738 [LessEqualCompare]: gl.LEQUAL, 34739 [EqualCompare]: gl.EQUAL, 34740 [GreaterEqualCompare]: gl.GEQUAL, 34741 [GreaterCompare]: gl.GREATER, 34742 [NotEqualCompare]: gl.NOTEQUAL 34743 }; 34744 } 34745 /** 34746 * Returns the native texture type for the given texture. 34747 * 34748 * @param {Texture} texture - The texture. 34749 * @return {GLenum} The native texture type. 34750 */ 34751 getGLTextureType(texture3) { 34752 const { gl } = this; 34753 let glTextureType; 34754 if (texture3.isCubeTexture === true) { 34755 glTextureType = gl.TEXTURE_CUBE_MAP; 34756 } else if (texture3.isArrayTexture === true || texture3.isDataArrayTexture === true || texture3.isCompressedArrayTexture === true) { 34757 glTextureType = gl.TEXTURE_2D_ARRAY; 34758 } else if (texture3.isData3DTexture === true) { 34759 glTextureType = gl.TEXTURE_3D; 34760 } else { 34761 glTextureType = gl.TEXTURE_2D; 34762 } 34763 return glTextureType; 34764 } 34765 /** 34766 * Returns the native texture type for the given texture. 34767 * 34768 * @param {?string} internalFormatName - The internal format name. When `null`, the internal format is derived from the subsequent parameters. 34769 * @param {GLenum} glFormat - The WebGL format. 34770 * @param {GLenum} glType - The WebGL type. 34771 * @param {string} colorSpace - The texture's color space. 34772 * @param {boolean} [forceLinearTransfer=false] - Whether to force a linear transfer or not. 34773 * @return {GLenum} The internal format. 34774 */ 34775 getInternalFormat(internalFormatName, glFormat, glType, normalized, colorSpace, forceLinearTransfer = false) { 34776 const { gl, extensions } = this; 34777 if (internalFormatName !== null) { 34778 if (gl[internalFormatName] !== void 0) return gl[internalFormatName]; 34779 warn("WebGLBackend: Attempt to use non-existing WebGL internal format '" + internalFormatName + "'"); 34780 } 34781 let extTextureNorm16 = null; 34782 if (normalized) { 34783 extTextureNorm16 = extensions.get("EXT_texture_norm16"); 34784 if (!extTextureNorm16) { 34785 warn("WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension"); 34786 } 34787 } 34788 let internalFormat = glFormat; 34789 if (glFormat === gl.RED) { 34790 if (glType === gl.FLOAT) internalFormat = gl.R32F; 34791 if (glType === gl.HALF_FLOAT) internalFormat = gl.R16F; 34792 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.R8; 34793 if (glType === gl.BYTE) internalFormat = gl.R8_SNORM; 34794 if (glType === gl.UNSIGNED_SHORT && extTextureNorm16) internalFormat = extTextureNorm16.R16_EXT; 34795 if (glType === gl.SHORT && extTextureNorm16) internalFormat = extTextureNorm16.R16_SNORM_EXT; 34796 } 34797 if (glFormat === gl.RED_INTEGER) { 34798 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.R8UI; 34799 if (glType === gl.UNSIGNED_SHORT) internalFormat = gl.R16UI; 34800 if (glType === gl.UNSIGNED_INT) internalFormat = gl.R32UI; 34801 if (glType === gl.BYTE) internalFormat = gl.R8I; 34802 if (glType === gl.SHORT) internalFormat = gl.R16I; 34803 if (glType === gl.INT) internalFormat = gl.R32I; 34804 } 34805 if (glFormat === gl.RG) { 34806 if (glType === gl.FLOAT) internalFormat = gl.RG32F; 34807 if (glType === gl.HALF_FLOAT) internalFormat = gl.RG16F; 34808 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RG8; 34809 if (glType === gl.BYTE) internalFormat = gl.RG8_SNORM; 34810 if (glType === gl.UNSIGNED_SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RG16_EXT; 34811 if (glType === gl.SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RG16_SNORM_EXT; 34812 } 34813 if (glFormat === gl.RG_INTEGER) { 34814 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RG8UI; 34815 if (glType === gl.UNSIGNED_SHORT) internalFormat = gl.RG16UI; 34816 if (glType === gl.UNSIGNED_INT) internalFormat = gl.RG32UI; 34817 if (glType === gl.BYTE) internalFormat = gl.RG8I; 34818 if (glType === gl.SHORT) internalFormat = gl.RG16I; 34819 if (glType === gl.INT) internalFormat = gl.RG32I; 34820 } 34821 if (glFormat === gl.RGB) { 34822 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer(colorSpace); 34823 if (glType === gl.FLOAT) internalFormat = gl.RGB32F; 34824 if (glType === gl.HALF_FLOAT) internalFormat = gl.RGB16F; 34825 if (glType === gl.UNSIGNED_BYTE) internalFormat = transfer === SRGBTransfer ? gl.SRGB8 : gl.RGB8; 34826 if (glType === gl.BYTE) internalFormat = gl.RGB8_SNORM; 34827 if (glType === gl.UNSIGNED_SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RGB16_EXT; 34828 if (glType === gl.SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RGB16_SNORM_EXT; 34829 if (glType === gl.UNSIGNED_SHORT_5_6_5) internalFormat = gl.RGB565; 34830 if (glType === gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = gl.RGB5_A1; 34831 if (glType === gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = gl.RGB4; 34832 if (glType === gl.UNSIGNED_INT_5_9_9_9_REV) internalFormat = gl.RGB9_E5; 34833 if (glType === gl.UNSIGNED_INT_10F_11F_11F_REV) internalFormat = gl.R11F_G11F_B10F; 34834 } 34835 if (glFormat === gl.RGB_INTEGER) { 34836 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RGB8UI; 34837 if (glType === gl.UNSIGNED_SHORT) internalFormat = gl.RGB16UI; 34838 if (glType === gl.UNSIGNED_INT) internalFormat = gl.RGB32UI; 34839 if (glType === gl.BYTE) internalFormat = gl.RGB8I; 34840 if (glType === gl.SHORT) internalFormat = gl.RGB16I; 34841 if (glType === gl.INT) internalFormat = gl.RGB32I; 34842 } 34843 if (glFormat === gl.RGBA) { 34844 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer(colorSpace); 34845 if (glType === gl.FLOAT) internalFormat = gl.RGBA32F; 34846 if (glType === gl.HALF_FLOAT) internalFormat = gl.RGBA16F; 34847 if (glType === gl.UNSIGNED_BYTE) internalFormat = transfer === SRGBTransfer ? gl.SRGB8_ALPHA8 : gl.RGBA8; 34848 if (glType === gl.BYTE) internalFormat = gl.RGBA8_SNORM; 34849 if (glType === gl.UNSIGNED_SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RGBA16_EXT; 34850 if (glType === gl.SHORT && extTextureNorm16) internalFormat = extTextureNorm16.RGBA16_SNORM_EXT; 34851 if (glType === gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = gl.RGBA4; 34852 if (glType === gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = gl.RGB5_A1; 34853 } 34854 if (glFormat === gl.RGBA_INTEGER) { 34855 if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RGBA8UI; 34856 if (glType === gl.UNSIGNED_SHORT) internalFormat = gl.RGBA16UI; 34857 if (glType === gl.UNSIGNED_INT) internalFormat = gl.RGBA32UI; 34858 if (glType === gl.BYTE) internalFormat = gl.RGBA8I; 34859 if (glType === gl.SHORT) internalFormat = gl.RGBA16I; 34860 if (glType === gl.INT) internalFormat = gl.RGBA32I; 34861 } 34862 if (glFormat === gl.DEPTH_COMPONENT) { 34863 if (glType === gl.UNSIGNED_SHORT) internalFormat = gl.DEPTH_COMPONENT16; 34864 if (glType === gl.UNSIGNED_INT) internalFormat = gl.DEPTH_COMPONENT24; 34865 if (glType === gl.FLOAT) internalFormat = gl.DEPTH_COMPONENT32F; 34866 } 34867 if (glFormat === gl.DEPTH_STENCIL) { 34868 if (glType === gl.UNSIGNED_INT_24_8) internalFormat = gl.DEPTH24_STENCIL8; 34869 } 34870 if (internalFormat === gl.R16F || internalFormat === gl.R32F || internalFormat === gl.RG16F || internalFormat === gl.RG32F || internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F) { 34871 extensions.get("EXT_color_buffer_float"); 34872 } 34873 return internalFormat; 34874 } 34875 /** 34876 * Sets the texture parameters for the given texture. 34877 * 34878 * @param {GLenum} textureType - The texture type. 34879 * @param {Texture} texture - The texture. 34880 */ 34881 setTextureParameters(textureType, texture3) { 34882 const { gl, extensions, backend } = this; 34883 const { state } = this.backend; 34884 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 34885 const texturePrimaries = texture3.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries(texture3.colorSpace); 34886 const unpackConversion = texture3.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? gl.NONE : gl.BROWSER_DEFAULT_WEBGL; 34887 state.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture3.flipY); 34888 state.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture3.premultiplyAlpha); 34889 state.pixelStorei(gl.UNPACK_ALIGNMENT, texture3.unpackAlignment); 34890 state.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion); 34891 gl.texParameteri(textureType, gl.TEXTURE_WRAP_S, wrappingToGL[texture3.wrapS]); 34892 gl.texParameteri(textureType, gl.TEXTURE_WRAP_T, wrappingToGL[texture3.wrapT]); 34893 if (textureType === gl.TEXTURE_3D || textureType === gl.TEXTURE_2D_ARRAY) { 34894 if (!texture3.isArrayTexture) { 34895 gl.texParameteri(textureType, gl.TEXTURE_WRAP_R, wrappingToGL[texture3.wrapR]); 34896 } 34897 } 34898 gl.texParameteri(textureType, gl.TEXTURE_MAG_FILTER, filterToGL[texture3.magFilter]); 34899 const hasMipmaps = texture3.mipmaps !== void 0 && texture3.mipmaps.length > 0; 34900 const minFilter = texture3.minFilter === LinearFilter && hasMipmaps ? LinearMipmapLinearFilter : texture3.minFilter; 34901 gl.texParameteri(textureType, gl.TEXTURE_MIN_FILTER, filterToGL[minFilter]); 34902 if (texture3.compareFunction) { 34903 gl.texParameteri(textureType, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE); 34904 gl.texParameteri(textureType, gl.TEXTURE_COMPARE_FUNC, compareToGL[texture3.compareFunction]); 34905 } 34906 if (extensions.has("EXT_texture_filter_anisotropic") === true) { 34907 if (texture3.magFilter === NearestFilter) return; 34908 if (texture3.minFilter !== NearestMipmapLinearFilter && texture3.minFilter !== LinearMipmapLinearFilter) return; 34909 if (texture3.type === FloatType && extensions.has("OES_texture_float_linear") === false) return; 34910 if (texture3.anisotropy > 1) { 34911 const extension = extensions.get("EXT_texture_filter_anisotropic"); 34912 gl.texParameterf(textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture3.anisotropy, backend.capabilities.getMaxAnisotropy())); 34913 } 34914 } 34915 } 34916 /** 34917 * Creates a default texture for the given texture that can be used 34918 * as a placeholder until the actual texture is ready for usage. 34919 * 34920 * @param {Texture} texture - The texture to create a default texture for. 34921 */ 34922 createDefaultTexture(texture3) { 34923 const { gl, backend, defaultTextures } = this; 34924 const glTextureType = this.getGLTextureType(texture3); 34925 let textureGPU = defaultTextures[glTextureType]; 34926 if (textureGPU === void 0) { 34927 textureGPU = gl.createTexture(); 34928 backend.state.bindTexture(glTextureType, textureGPU); 34929 gl.texParameteri(glTextureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 34930 gl.texParameteri(glTextureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 34931 defaultTextures[glTextureType] = textureGPU; 34932 } 34933 backend.set(texture3, { 34934 textureGPU, 34935 glTextureType 34936 }); 34937 } 34938 /** 34939 * Defines a texture on the GPU for the given texture object. 34940 * 34941 * @param {Texture} texture - The texture. 34942 * @param {Object} [options={}] - Optional configuration parameter. 34943 * @return {undefined} 34944 */ 34945 createTexture(texture3, options) { 34946 const { gl, backend } = this; 34947 const { levels, width, height, depth: depth3 } = options; 34948 const glFormat = backend.utils.convert(texture3.format, texture3.colorSpace); 34949 const glType = backend.utils.convert(texture3.type); 34950 const glInternalFormat = this.getInternalFormat(texture3.internalFormat, glFormat, glType, texture3.normalized, texture3.colorSpace, texture3.isVideoTexture); 34951 const textureGPU = gl.createTexture(); 34952 const glTextureType = this.getGLTextureType(texture3); 34953 backend.state.bindTexture(glTextureType, textureGPU); 34954 this.setTextureParameters(glTextureType, texture3); 34955 if (texture3.isArrayTexture || texture3.isDataArrayTexture || texture3.isCompressedArrayTexture) { 34956 gl.texStorage3D(gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth3); 34957 } else if (texture3.isData3DTexture) { 34958 gl.texStorage3D(gl.TEXTURE_3D, levels, glInternalFormat, width, height, depth3); 34959 } else if (!texture3.isVideoTexture) { 34960 gl.texStorage2D(glTextureType, levels, glInternalFormat, width, height); 34961 } 34962 backend.set(texture3, { 34963 textureGPU, 34964 glTextureType, 34965 glFormat, 34966 glType, 34967 glInternalFormat 34968 }); 34969 } 34970 /** 34971 * Uploads texture buffer data to the GPU memory. 34972 * 34973 * @param {WebGLBuffer} buffer - The buffer data. 34974 * @param {Texture} texture - The texture, 34975 */ 34976 copyBufferToTexture(buffer3, texture3) { 34977 const { gl, backend } = this; 34978 const { state } = backend; 34979 const { textureGPU, glTextureType, glFormat, glType } = backend.get(texture3); 34980 const { width, height } = texture3.source.data; 34981 gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, buffer3); 34982 backend.state.bindTexture(glTextureType, textureGPU); 34983 state.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); 34984 state.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); 34985 gl.texSubImage2D(glTextureType, 0, 0, 0, width, height, glFormat, glType, 0); 34986 gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null); 34987 backend.state.unbindTexture(); 34988 } 34989 /** 34990 * Uploads the updated texture data to the GPU. 34991 * 34992 * @param {Texture} texture - The texture. 34993 * @param {Object} [options={}] - Optional configuration parameter. 34994 */ 34995 updateTexture(texture3, options) { 34996 const { gl } = this; 34997 const { width, height } = options; 34998 const { textureGPU, glTextureType, glFormat, glType, glInternalFormat } = this.backend.get(texture3); 34999 if (texture3.isRenderTargetTexture || textureGPU === void 0) 35000 return; 35001 this.backend.state.bindTexture(glTextureType, textureGPU); 35002 this.setTextureParameters(glTextureType, texture3); 35003 if (texture3.isCompressedTexture) { 35004 const mipmaps = texture3.mipmaps; 35005 const image = options.image; 35006 for (let i = 0; i < mipmaps.length; i++) { 35007 const mipmap = mipmaps[i]; 35008 if (texture3.isCompressedArrayTexture) { 35009 if (texture3.format !== gl.RGBA) { 35010 if (glFormat !== null) { 35011 gl.compressedTexSubImage3D(gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data); 35012 } else { 35013 warn("WebGLBackend: Attempt to load unsupported compressed texture format in .uploadTexture()"); 35014 } 35015 } else { 35016 gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data); 35017 } 35018 } else { 35019 if (glFormat !== null) { 35020 gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); 35021 } else { 35022 warn("WebGLBackend: Unsupported compressed texture format"); 35023 } 35024 } 35025 } 35026 } else if (texture3.isCubeTexture) { 35027 const images = options.images; 35028 const mipmaps = texture3.mipmaps; 35029 for (let i = 0; i < 6; i++) { 35030 const image = getImage(images[i]); 35031 gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, width, height, glFormat, glType, image); 35032 for (let j = 0; j < mipmaps.length; j++) { 35033 const mipmap = mipmaps[j]; 35034 const image2 = getImage(mipmap.images[i]); 35035 gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, image2.width, image2.height, glFormat, glType, image2); 35036 } 35037 } 35038 } else if (texture3.isDataArrayTexture || texture3.isArrayTexture) { 35039 const image = options.image; 35040 if (texture3.layerUpdates.size > 0) { 35041 const layerByteLength = getByteLength(image.width, image.height, texture3.format, texture3.type); 35042 for (const layerIndex of texture3.layerUpdates) { 35043 const layerData = image.data.subarray( 35044 layerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT, 35045 (layerIndex + 1) * layerByteLength / image.data.BYTES_PER_ELEMENT 35046 ); 35047 gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData); 35048 } 35049 texture3.clearLayerUpdates(); 35050 } else { 35051 gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 35052 } 35053 } else if (texture3.isData3DTexture) { 35054 const image = options.image; 35055 gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 35056 } else if (texture3.isVideoTexture) { 35057 texture3.update(); 35058 gl.texImage2D(glTextureType, 0, glInternalFormat, glFormat, glType, options.image); 35059 } else if (texture3.isHTMLTexture) { 35060 if (typeof gl.texElementImage2D === "function") { 35061 gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.image); 35062 } 35063 } else { 35064 const mipmaps = texture3.mipmaps; 35065 if (mipmaps.length > 0) { 35066 for (let i = 0, il = mipmaps.length; i < il; i++) { 35067 const mipmap = mipmaps[i]; 35068 const image = getImage(mipmap); 35069 gl.texSubImage2D(glTextureType, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, image); 35070 } 35071 } else { 35072 const image = getImage(options.image); 35073 gl.texSubImage2D(glTextureType, 0, 0, 0, width, height, glFormat, glType, image); 35074 } 35075 } 35076 } 35077 /** 35078 * Generates mipmaps for the given texture. 35079 * 35080 * @param {Texture} texture - The texture. 35081 */ 35082 generateMipmaps(texture3) { 35083 const { gl, backend } = this; 35084 const { textureGPU, glTextureType } = backend.get(texture3); 35085 backend.state.bindTexture(glTextureType, textureGPU); 35086 gl.generateMipmap(glTextureType); 35087 } 35088 /** 35089 * Deallocates the render buffers of the given render target. 35090 * 35091 * @param {RenderTarget} renderTarget - The render target. 35092 */ 35093 deallocateRenderBuffers(renderTarget) { 35094 const { gl, backend } = this; 35095 if (renderTarget) { 35096 const renderContextData = backend.get(renderTarget); 35097 renderContextData.renderBufferStorageSetup = void 0; 35098 if (renderContextData.framebuffers) { 35099 for (const cacheKey in renderContextData.framebuffers) { 35100 gl.deleteFramebuffer(renderContextData.framebuffers[cacheKey]); 35101 } 35102 delete renderContextData.framebuffers; 35103 } 35104 if (renderContextData.depthRenderbuffer) { 35105 gl.deleteRenderbuffer(renderContextData.depthRenderbuffer); 35106 delete renderContextData.depthRenderbuffer; 35107 } 35108 if (renderContextData.stencilRenderbuffer) { 35109 gl.deleteRenderbuffer(renderContextData.stencilRenderbuffer); 35110 delete renderContextData.stencilRenderbuffer; 35111 } 35112 if (renderContextData.msaaFrameBuffer) { 35113 gl.deleteFramebuffer(renderContextData.msaaFrameBuffer); 35114 delete renderContextData.msaaFrameBuffer; 35115 } 35116 if (renderContextData.msaaRenderbuffers) { 35117 for (let i = 0; i < renderContextData.msaaRenderbuffers.length; i++) { 35118 gl.deleteRenderbuffer(renderContextData.msaaRenderbuffers[i]); 35119 } 35120 delete renderContextData.msaaRenderbuffers; 35121 } 35122 } 35123 } 35124 /** 35125 * Destroys the GPU data for the given texture object. 35126 * 35127 * @param {Texture} texture - The texture. 35128 * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. 35129 */ 35130 destroyTexture(texture3, isDefaultTexture = false) { 35131 const { gl, backend } = this; 35132 const { textureGPU, renderTarget } = backend.get(texture3); 35133 this.deallocateRenderBuffers(renderTarget); 35134 if (isDefaultTexture === false) { 35135 gl.deleteTexture(textureGPU); 35136 } 35137 backend.delete(texture3); 35138 } 35139 /** 35140 * Copies data of the given source texture to the given destination texture. 35141 * 35142 * @param {Texture} srcTexture - The source texture. 35143 * @param {Texture} dstTexture - The destination texture. 35144 * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy. 35145 * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy. 35146 * @param {number} [srcLevel=0] - The source mip level to copy from. 35147 * @param {number} [dstLevel=0] - The destination mip level to copy to. 35148 */ 35149 copyTextureToTexture(srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0) { 35150 const { gl, backend } = this; 35151 const { state } = this.backend; 35152 const { textureGPU: dstTextureGPU, glTextureType, glType, glFormat } = backend.get(dstTexture); 35153 state.bindTexture(glTextureType, dstTextureGPU); 35154 let width, height, depth3, minX, minY, minZ; 35155 let dstX, dstY, dstZ; 35156 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[dstLevel] : srcTexture.image; 35157 if (srcRegion !== null) { 35158 width = srcRegion.max.x - srcRegion.min.x; 35159 height = srcRegion.max.y - srcRegion.min.y; 35160 depth3 = srcRegion.isBox3 ? srcRegion.max.z - srcRegion.min.z : 1; 35161 minX = srcRegion.min.x; 35162 minY = srcRegion.min.y; 35163 minZ = srcRegion.isBox3 ? srcRegion.min.z : 0; 35164 } else { 35165 const levelScale = Math.pow(2, -srcLevel); 35166 width = Math.floor(image.width * levelScale); 35167 height = Math.floor(image.height * levelScale); 35168 if (srcTexture.isDataArrayTexture || srcTexture.isArrayTexture) { 35169 depth3 = image.depth; 35170 } else if (srcTexture.isData3DTexture) { 35171 depth3 = Math.floor(image.depth * levelScale); 35172 } else { 35173 depth3 = 1; 35174 } 35175 minX = 0; 35176 minY = 0; 35177 minZ = 0; 35178 } 35179 if (dstPosition !== null) { 35180 dstX = dstPosition.x; 35181 dstY = dstPosition.y; 35182 dstZ = dstPosition.z; 35183 } else { 35184 dstX = 0; 35185 dstY = 0; 35186 dstZ = 0; 35187 } 35188 state.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY); 35189 state.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha); 35190 state.pixelStorei(gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment); 35191 const currentUnpackRowLen = state.getParameter(gl.UNPACK_ROW_LENGTH); 35192 const currentUnpackImageHeight = state.getParameter(gl.UNPACK_IMAGE_HEIGHT); 35193 const currentUnpackSkipPixels = state.getParameter(gl.UNPACK_SKIP_PIXELS); 35194 const currentUnpackSkipRows = state.getParameter(gl.UNPACK_SKIP_ROWS); 35195 const currentUnpackSkipImages = state.getParameter(gl.UNPACK_SKIP_IMAGES); 35196 state.pixelStorei(gl.UNPACK_ROW_LENGTH, image.width); 35197 state.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, image.height); 35198 state.pixelStorei(gl.UNPACK_SKIP_PIXELS, minX); 35199 state.pixelStorei(gl.UNPACK_SKIP_ROWS, minY); 35200 state.pixelStorei(gl.UNPACK_SKIP_IMAGES, minZ); 35201 const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture || dstTexture.isArrayTexture; 35202 const isDst3D = dstTexture.isDataArrayTexture || dstTexture.isData3DTexture || dstTexture.isArrayTexture; 35203 if (srcTexture.isDepthTexture) { 35204 const srcTextureData = backend.get(srcTexture); 35205 const dstTextureData = backend.get(dstTexture); 35206 const srcRenderContextData = backend.get(srcTextureData.renderTarget); 35207 const dstRenderContextData = backend.get(dstTextureData.renderTarget); 35208 const srcFramebuffer = srcRenderContextData.framebuffers[srcTextureData.cacheKey]; 35209 const dstFramebuffer = dstRenderContextData.framebuffers[dstTextureData.cacheKey]; 35210 state.bindFramebuffer(gl.READ_FRAMEBUFFER, srcFramebuffer); 35211 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dstFramebuffer); 35212 for (let i = 0; i < depth3; i++) { 35213 if (isSrc3D) { 35214 gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, srcTextureData.textureGPU, srcLevel, minZ + i); 35215 gl.framebufferTextureLayer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, dstTextureGPU, dstLevel, dstZ + i); 35216 } 35217 gl.blitFramebuffer(minX, minY, width, height, dstX, dstY, width, height, gl.DEPTH_BUFFER_BIT, gl.NEAREST); 35218 } 35219 state.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 35220 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 35221 } else if (srcLevel !== 0 || srcTexture.isRenderTargetTexture || backend.has(srcTexture)) { 35222 const srcTextureData = backend.get(srcTexture); 35223 if (this._srcFramebuffer === null) this._srcFramebuffer = gl.createFramebuffer(); 35224 if (this._dstFramebuffer === null) this._dstFramebuffer = gl.createFramebuffer(); 35225 state.bindFramebuffer(gl.READ_FRAMEBUFFER, this._srcFramebuffer); 35226 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._dstFramebuffer); 35227 for (let i = 0; i < depth3; i++) { 35228 if (isSrc3D) { 35229 gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, srcTextureData.textureGPU, srcLevel, minZ + i); 35230 } else { 35231 gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, srcTextureData.textureGPU, srcLevel); 35232 } 35233 if (isDst3D) { 35234 gl.framebufferTextureLayer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, dstTextureGPU, dstLevel, dstZ + i); 35235 } else { 35236 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, dstTextureGPU, dstLevel); 35237 } 35238 if (srcLevel !== 0) { 35239 gl.blitFramebuffer(minX, minY, width, height, dstX, dstY, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST); 35240 } else if (isDst3D) { 35241 gl.copyTexSubImage3D(glTextureType, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height); 35242 } else { 35243 gl.copyTexSubImage2D(glTextureType, dstLevel, dstX, dstY, minX, minY, width, height); 35244 } 35245 } 35246 state.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 35247 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 35248 } else { 35249 if (isDst3D) { 35250 if (srcTexture.isDataTexture || srcTexture.isData3DTexture) { 35251 gl.texSubImage3D(glTextureType, dstLevel, dstX, dstY, dstZ, width, height, depth3, glFormat, glType, image.data); 35252 } else if (dstTexture.isCompressedArrayTexture) { 35253 gl.compressedTexSubImage3D(glTextureType, dstLevel, dstX, dstY, dstZ, width, height, depth3, glFormat, image.data); 35254 } else { 35255 gl.texSubImage3D(glTextureType, dstLevel, dstX, dstY, dstZ, width, height, depth3, glFormat, glType, image); 35256 } 35257 } else { 35258 if (srcTexture.isDataTexture) { 35259 gl.texSubImage2D(gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data); 35260 } else if (srcTexture.isCompressedTexture) { 35261 gl.compressedTexSubImage2D(gl.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data); 35262 } else { 35263 gl.texSubImage2D(gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image); 35264 } 35265 } 35266 } 35267 state.pixelStorei(gl.UNPACK_ROW_LENGTH, currentUnpackRowLen); 35268 state.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight); 35269 state.pixelStorei(gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels); 35270 state.pixelStorei(gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows); 35271 state.pixelStorei(gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages); 35272 if (dstLevel === 0 && dstTexture.generateMipmaps) { 35273 gl.generateMipmap(glTextureType); 35274 } 35275 state.unbindTexture(); 35276 } 35277 /** 35278 * Copies the current bound framebuffer to the given texture. 35279 * 35280 * @param {Texture} texture - The destination texture. 35281 * @param {RenderContext} renderContext - The render context. 35282 * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. 35283 */ 35284 copyFramebufferToTexture(texture3, renderContext, rectangle) { 35285 const { gl } = this; 35286 const { state } = this.backend; 35287 const { textureGPU } = this.backend.get(texture3); 35288 const { x, y, z: width, w: height } = rectangle; 35289 const requireDrawFrameBuffer = texture3.isDepthTexture === true || renderContext.renderTarget && renderContext.renderTarget.samples > 0; 35290 const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.getDrawingBufferSize().y; 35291 if (requireDrawFrameBuffer) { 35292 const partial = x !== 0 || y !== 0; 35293 let mask; 35294 let attachment; 35295 if (texture3.isDepthTexture === true) { 35296 mask = gl.DEPTH_BUFFER_BIT; 35297 attachment = gl.DEPTH_ATTACHMENT; 35298 if (renderContext.stencil) { 35299 mask |= gl.STENCIL_BUFFER_BIT; 35300 } 35301 } else { 35302 mask = gl.COLOR_BUFFER_BIT; 35303 attachment = gl.COLOR_ATTACHMENT0; 35304 } 35305 if (partial) { 35306 const renderTargetContextData = this.backend.get(renderContext.renderTarget); 35307 const fb = renderTargetContextData.framebuffers[renderContext.getCacheKey()]; 35308 const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer; 35309 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); 35310 state.bindFramebuffer(gl.READ_FRAMEBUFFER, msaaFrameBuffer); 35311 const flippedY = srcHeight - y - height; 35312 gl.blitFramebuffer(x, flippedY, x + width, flippedY + height, x, flippedY, x + width, flippedY + height, mask, gl.NEAREST); 35313 state.bindFramebuffer(gl.READ_FRAMEBUFFER, fb); 35314 state.bindTexture(gl.TEXTURE_2D, textureGPU); 35315 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, flippedY, width, height); 35316 state.unbindTexture(); 35317 } else { 35318 const fb = gl.createFramebuffer(); 35319 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); 35320 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0); 35321 gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST); 35322 gl.deleteFramebuffer(fb); 35323 } 35324 } else { 35325 state.bindTexture(gl.TEXTURE_2D, textureGPU); 35326 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, srcHeight - height - y, width, height); 35327 state.unbindTexture(); 35328 } 35329 if (texture3.generateMipmaps) this.generateMipmaps(texture3); 35330 this.backend._setFramebuffer(renderContext); 35331 } 35332 /** 35333 * SetupS storage for internal depth/stencil buffers and bind to correct framebuffer. 35334 * 35335 * @param {WebGLRenderbuffer} renderbuffer - The render buffer. 35336 * @param {RenderContext} renderContext - The render context. 35337 * @param {number} samples - The MSAA sample count. 35338 * @param {boolean} [useMultisampledRTT=false] - Whether to use WEBGL_multisampled_render_to_texture or not. 35339 */ 35340 setupRenderBufferStorage(renderbuffer, renderContext, samples, useMultisampledRTT = false) { 35341 const { gl } = this; 35342 const renderTarget = renderContext.renderTarget; 35343 const { depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget; 35344 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); 35345 if (depthBuffer && !stencilBuffer) { 35346 let glInternalFormat = gl.DEPTH_COMPONENT24; 35347 if (useMultisampledRTT === true) { 35348 const multisampledRTTExt = this.extensions.get("WEBGL_multisampled_render_to_texture"); 35349 multisampledRTTExt.renderbufferStorageMultisampleEXT(gl.RENDERBUFFER, renderTarget.samples, glInternalFormat, width, height); 35350 } else if (samples > 0) { 35351 if (depthTexture && depthTexture.isDepthTexture) { 35352 if (depthTexture.type === gl.FLOAT) { 35353 glInternalFormat = gl.DEPTH_COMPONENT32F; 35354 } 35355 } 35356 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, glInternalFormat, width, height); 35357 } else { 35358 gl.renderbufferStorage(gl.RENDERBUFFER, glInternalFormat, width, height); 35359 } 35360 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); 35361 } else if (depthBuffer && stencilBuffer) { 35362 if (samples > 0) { 35363 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height); 35364 } else { 35365 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height); 35366 } 35367 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); 35368 } 35369 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 35370 } 35371 /** 35372 * Returns texture data as a typed array. 35373 * 35374 * @async 35375 * @param {Texture} texture - The texture to copy. 35376 * @param {number} x - The x coordinate of the copy origin. 35377 * @param {number} y - The y coordinate of the copy origin. 35378 * @param {number} width - The width of the copy. 35379 * @param {number} height - The height of the copy. 35380 * @param {number} faceIndex - The face index. 35381 * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished. 35382 */ 35383 async copyTextureToBuffer(texture3, x, y, width, height, faceIndex) { 35384 const { backend, gl } = this; 35385 const { textureGPU, glFormat, glType } = this.backend.get(texture3); 35386 const fb = gl.createFramebuffer(); 35387 backend.state.bindFramebuffer(gl.READ_FRAMEBUFFER, fb); 35388 const target = texture3.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; 35389 gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0); 35390 const typedArrayType = this._getTypedArrayType(glType); 35391 const bytesPerTexel = this._getBytesPerTexel(glType, glFormat); 35392 const elementCount = width * height; 35393 const byteLength = elementCount * bytesPerTexel; 35394 const buffer3 = gl.createBuffer(); 35395 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer3); 35396 gl.bufferData(gl.PIXEL_PACK_BUFFER, byteLength, gl.STREAM_READ); 35397 gl.readPixels(x, y, width, height, glFormat, glType, 0); 35398 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); 35399 await backend.utils._clientWaitAsync(); 35400 const dstBuffer = new typedArrayType(byteLength / typedArrayType.BYTES_PER_ELEMENT); 35401 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer3); 35402 gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, dstBuffer); 35403 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); 35404 backend.state.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 35405 gl.deleteFramebuffer(fb); 35406 return dstBuffer; 35407 } 35408 /** 35409 * Returns the corresponding typed array type for the given WebGL data type. 35410 * 35411 * @private 35412 * @param {GLenum} glType - The WebGL data type. 35413 * @return {TypedArray.constructor} The typed array type. 35414 */ 35415 _getTypedArrayType(glType) { 35416 const { gl } = this; 35417 if (glType === gl.UNSIGNED_BYTE) return Uint8Array; 35418 if (glType === gl.UNSIGNED_SHORT_4_4_4_4) return Uint16Array; 35419 if (glType === gl.UNSIGNED_SHORT_5_5_5_1) return Uint16Array; 35420 if (glType === gl.UNSIGNED_SHORT_5_6_5) return Uint16Array; 35421 if (glType === gl.UNSIGNED_SHORT) return Uint16Array; 35422 if (glType === gl.UNSIGNED_INT) return Uint32Array; 35423 if (glType === gl.HALF_FLOAT) return Uint16Array; 35424 if (glType === gl.FLOAT) return Float32Array; 35425 throw new Error(`Unsupported WebGL type: ${glType}`); 35426 } 35427 /** 35428 * Returns the bytes-per-texel value for the given WebGL data type and texture format. 35429 * 35430 * @private 35431 * @param {GLenum} glType - The WebGL data type. 35432 * @param {GLenum} glFormat - The WebGL texture format. 35433 * @return {number} The bytes-per-texel. 35434 */ 35435 _getBytesPerTexel(glType, glFormat) { 35436 const { gl } = this; 35437 let bytesPerComponent = 0; 35438 if (glType === gl.UNSIGNED_BYTE) bytesPerComponent = 1; 35439 if (glType === gl.UNSIGNED_SHORT_4_4_4_4 || glType === gl.UNSIGNED_SHORT_5_5_5_1 || glType === gl.UNSIGNED_SHORT_5_6_5 || glType === gl.UNSIGNED_SHORT || glType === gl.HALF_FLOAT) bytesPerComponent = 2; 35440 if (glType === gl.UNSIGNED_INT || glType === gl.FLOAT) bytesPerComponent = 4; 35441 if (glFormat === gl.RGBA) return bytesPerComponent * 4; 35442 if (glFormat === gl.RGB) return bytesPerComponent * 3; 35443 if (glFormat === gl.ALPHA) return bytesPerComponent; 35444 } 35445 /** 35446 * Frees the internal resources. 35447 */ 35448 dispose() { 35449 const { gl } = this; 35450 if (this._srcFramebuffer !== null) gl.deleteFramebuffer(this._srcFramebuffer); 35451 if (this._dstFramebuffer !== null) gl.deleteFramebuffer(this._dstFramebuffer); 35452 } 35453}; 35454function getImage(source) { 35455 if (source.isDataTexture) { 35456 return source.image.data; 35457 } else if (typeof HTMLImageElement !== "undefined" && source instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && source instanceof HTMLCanvasElement || typeof ImageBitmap !== "undefined" && source instanceof ImageBitmap || typeof OffscreenCanvas !== "undefined" && source instanceof OffscreenCanvas) { 35458 return source; 35459 } 35460 return source.data; 35461} 35462var WebGLExtensions = class { 35463 /** 35464 * Constructs a new utility object. 35465 * 35466 * @param {WebGLBackend} backend - The WebGL 2 backend. 35467 */ 35468 constructor(backend) { 35469 this.backend = backend; 35470 this.gl = this.backend.gl; 35471 this.availableExtensions = this.gl.getSupportedExtensions(); 35472 this.extensions = {}; 35473 } 35474 /** 35475 * Returns the extension object for the given extension name. 35476 * 35477 * @param {string} name - The extension name. 35478 * @return {Object} The extension object. 35479 */ 35480 get(name) { 35481 let extension = this.extensions[name]; 35482 if (extension === void 0) { 35483 extension = this.gl.getExtension(name); 35484 this.extensions[name] = extension; 35485 } 35486 return extension; 35487 } 35488 /** 35489 * Returns `true` if the requested extension is available. 35490 * 35491 * @param {string} name - The extension name. 35492 * @return {boolean} Whether the given extension is available or not. 35493 */ 35494 has(name) { 35495 return this.availableExtensions.includes(name); 35496 } 35497}; 35498var WebGLCapabilities = class { 35499 /** 35500 * Constructs a new utility object. 35501 * 35502 * @param {WebGLBackend} backend - The WebGL 2 backend. 35503 */ 35504 constructor(backend) { 35505 this.backend = backend; 35506 this.maxAnisotropy = null; 35507 this.maxUniformBlockSize = null; 35508 } 35509 /** 35510 * Returns the maximum anisotropy texture filtering value. This value 35511 * depends on the device and is reported by the `EXT_texture_filter_anisotropic` 35512 * WebGL extension. 35513 * 35514 * @return {number} The maximum anisotropy texture filtering value. 35515 */ 35516 getMaxAnisotropy() { 35517 if (this.maxAnisotropy !== null) return this.maxAnisotropy; 35518 const gl = this.backend.gl; 35519 const extensions = this.backend.extensions; 35520 if (extensions.has("EXT_texture_filter_anisotropic") === true) { 35521 const extension = extensions.get("EXT_texture_filter_anisotropic"); 35522 this.maxAnisotropy = gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT); 35523 } else { 35524 this.maxAnisotropy = 0; 35525 } 35526 return this.maxAnisotropy; 35527 } 35528 /** 35529 * Returns the maximum number of bytes available for uniform buffers. 35530 * 35531 * @return {number} The maximum number of bytes available for uniform buffers. 35532 */ 35533 getUniformBufferLimit() { 35534 if (this.maxUniformBlockSize !== null) return this.maxUniformBlockSize; 35535 const gl = this.backend.gl; 35536 this.maxUniformBlockSize = gl.getParameter(gl.MAX_UNIFORM_BLOCK_SIZE); 35537 return this.maxUniformBlockSize; 35538 } 35539}; 35540var GLFeatureName = { 35541 "WEBGL_multi_draw": "WEBGL_multi_draw", 35542 "WEBGL_compressed_texture_astc": "texture-compression-astc", 35543 "WEBGL_compressed_texture_etc": "texture-compression-etc2", 35544 "WEBGL_compressed_texture_etc1": "texture-compression-etc1", 35545 "WEBGL_compressed_texture_pvrtc": "texture-compression-pvrtc", 35546 "WEBGL_compressed_texture_s3tc": "texture-compression-s3tc", 35547 "EXT_texture_compression_bptc": "texture-compression-bc", 35548 "EXT_disjoint_timer_query_webgl2": "timestamp-query", 35549 "OVR_multiview2": "OVR_multiview2" 35550}; 35551var WebGLBufferRenderer = class { 35552 constructor(backend) { 35553 this.gl = backend.gl; 35554 this.extensions = backend.extensions; 35555 this.info = backend.renderer.info; 35556 this.mode = null; 35557 this.index = 0; 35558 this.type = null; 35559 this.object = null; 35560 } 35561 render(start, count) { 35562 const { gl, mode, object, type, info, index } = this; 35563 if (index !== 0) { 35564 gl.drawElements(mode, count, type, start); 35565 } else { 35566 gl.drawArrays(mode, start, count); 35567 } 35568 info.update(object, count, 1); 35569 } 35570 renderInstances(start, count, primcount) { 35571 const { gl, mode, type, index, object, info } = this; 35572 if (primcount === 0) return; 35573 if (index !== 0) { 35574 gl.drawElementsInstanced(mode, count, type, start, primcount); 35575 } else { 35576 gl.drawArraysInstanced(mode, start, count, primcount); 35577 } 35578 info.update(object, count, primcount); 35579 } 35580 renderMultiDraw(starts, counts, drawCount) { 35581 const { extensions, mode, object, info } = this; 35582 if (drawCount === 0) return; 35583 const extension = extensions.get("WEBGL_multi_draw"); 35584 if (extension === null) { 35585 for (let i = 0; i < drawCount; i++) { 35586 this.render(starts[i], counts[i]); 35587 } 35588 } else { 35589 if (this.index !== 0) { 35590 extension.multiDrawElementsWEBGL(mode, counts, 0, this.type, starts, 0, drawCount); 35591 } else { 35592 extension.multiDrawArraysWEBGL(mode, starts, 0, counts, 0, drawCount); 35593 } 35594 let elementCount = 0; 35595 for (let i = 0; i < drawCount; i++) { 35596 elementCount += counts[i]; 35597 } 35598 info.update(object, elementCount, 1); 35599 } 35600 } 35601 // 35602}; 35603var TimestampQueryPool = class { 35604 /** 35605 * Creates a new timestamp query pool. 35606 * 35607 * @param {number} [maxQueries=256] - Maximum number of queries this pool can hold. 35608 */ 35609 constructor(maxQueries = 256) { 35610 this.trackTimestamp = true; 35611 this.maxQueries = maxQueries; 35612 this.currentQueryIndex = 0; 35613 this.queryOffsets = /* @__PURE__ */ new Map(); 35614 this.isDisposed = false; 35615 this.lastValue = 0; 35616 this.frames = []; 35617 this.pendingResolve = false; 35618 this.timestamps = /* @__PURE__ */ new Map(); 35619 } 35620 /** 35621 * Returns all timestamp frames. 35622 * 35623 * @return {Array<number>} The timestamp frames. 35624 */ 35625 getTimestampFrames() { 35626 return this.frames; 35627 } 35628 /** 35629 * Returns the timestamp for a given render context. 35630 * 35631 * @param {string} uid - A unique identifier for the render context. 35632 * @return {?number} The timestamp, or undefined if not available. 35633 */ 35634 getTimestamp(uid) { 35635 let timestamp = this.timestamps.get(uid); 35636 if (timestamp === void 0) { 35637 warn(`TimestampQueryPool: No timestamp available for uid ${uid}.`); 35638 timestamp = 0; 35639 } 35640 return timestamp; 35641 } 35642 /** 35643 * Returns whether a timestamp is available for a given render context. 35644 * 35645 * @param {string} uid - A unique identifier for the render context. 35646 * @return {boolean} True if a timestamp is available, false otherwise. 35647 */ 35648 hasTimestamp(uid) { 35649 return this.timestamps.has(uid); 35650 } 35651 /** 35652 * Allocate queries for a specific uid. 35653 * 35654 * @abstract 35655 * @param {string} uid - A unique identifier for the render context. 35656 * @param {number} frameId - The current frame identifier. 35657 * @returns {?number} 35658 */ 35659 allocateQueriesForContext() { 35660 } 35661 /** 35662 * Resolve all timestamps and return data (or process them). 35663 * 35664 * @abstract 35665 * @async 35666 * @returns {Promise<number>|number} The resolved timestamp value. 35667 */ 35668 async resolveQueriesAsync() { 35669 } 35670 /** 35671 * Dispose of the query pool. 35672 * 35673 * @abstract 35674 */ 35675 dispose() { 35676 } 35677}; 35678var WebGLTimestampQueryPool = class extends TimestampQueryPool { 35679 /** 35680 * Creates a new WebGL timestamp query pool. 35681 * 35682 * @param {WebGLRenderingContext|WebGL2RenderingContext} gl - The WebGL context. 35683 * @param {string} type - The type identifier for this query pool. 35684 * @param {number} [maxQueries=2048] - Maximum number of queries this pool can hold. 35685 */ 35686 constructor(gl, type, maxQueries = 2048) { 35687 super(maxQueries); 35688 this.gl = gl; 35689 this.type = type; 35690 this.ext = gl.getExtension("EXT_disjoint_timer_query_webgl2") || gl.getExtension("EXT_disjoint_timer_query"); 35691 if (!this.ext) { 35692 warn("EXT_disjoint_timer_query not supported; timestamps will be disabled."); 35693 this.trackTimestamp = false; 35694 return; 35695 } 35696 this.queries = []; 35697 for (let i = 0; i < this.maxQueries; i++) { 35698 this.queries.push(gl.createQuery()); 35699 } 35700 this.activeQuery = null; 35701 this.queryStates = /* @__PURE__ */ new Map(); 35702 } 35703 /** 35704 * Allocates a pair of queries for a given render context. 35705 * 35706 * @param {string} uid - A unique identifier for the render context. 35707 * @returns {?number} The base offset for the allocated queries, or null if allocation failed. 35708 */ 35709 allocateQueriesForContext(uid) { 35710 if (!this.trackTimestamp) return null; 35711 if (this.currentQueryIndex + 2 > this.maxQueries) { 35712 warnOnce(`WebGLTimestampQueryPool [${this.type}]: Maximum number of queries exceeded, when using trackTimestamp it is necessary to resolves the queries via renderer.resolveTimestampsAsync( THREE.TimestampQuery.${this.type.toUpperCase()} ).`); 35713 return null; 35714 } 35715 const baseOffset = this.currentQueryIndex; 35716 this.currentQueryIndex += 2; 35717 this.queryStates.set(baseOffset, "inactive"); 35718 this.queryOffsets.set(uid, baseOffset); 35719 return baseOffset; 35720 } 35721 /** 35722 * Begins a timestamp query for the specified render context. 35723 * 35724 * @param {string} uid - A unique identifier for the render context. 35725 */ 35726 beginQuery(uid) { 35727 if (!this.trackTimestamp || this.isDisposed) { 35728 return; 35729 } 35730 const baseOffset = this.queryOffsets.get(uid); 35731 if (baseOffset == null) { 35732 return; 35733 } 35734 if (this.activeQuery !== null) { 35735 return; 35736 } 35737 const query = this.queries[baseOffset]; 35738 if (!query) { 35739 return; 35740 } 35741 try { 35742 if (this.queryStates.get(baseOffset) === "inactive") { 35743 this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, query); 35744 this.activeQuery = baseOffset; 35745 this.queryStates.set(baseOffset, "started"); 35746 } 35747 } catch (e) { 35748 error("Error in beginQuery:", e); 35749 this.activeQuery = null; 35750 this.queryStates.set(baseOffset, "inactive"); 35751 } 35752 } 35753 /** 35754 * Ends the active timestamp query for the specified render context. 35755 * 35756 * @param {string} uid - A unique identifier for the render context. 35757 */ 35758 endQuery(uid) { 35759 if (!this.trackTimestamp || this.isDisposed) { 35760 return; 35761 } 35762 const baseOffset = this.queryOffsets.get(uid); 35763 if (baseOffset == null) { 35764 return; 35765 } 35766 if (this.activeQuery !== baseOffset) { 35767 return; 35768 } 35769 try { 35770 this.gl.endQuery(this.ext.TIME_ELAPSED_EXT); 35771 this.queryStates.set(baseOffset, "ended"); 35772 this.activeQuery = null; 35773 } catch (e) { 35774 error("Error in endQuery:", e); 35775 this.queryStates.set(baseOffset, "inactive"); 35776 this.activeQuery = null; 35777 } 35778 } 35779 /** 35780 * Asynchronously resolves all completed queries and returns the total duration. 35781 * 35782 * @async 35783 * @returns {Promise<number>} The total duration in milliseconds, or the last valid value if resolution fails. 35784 */ 35785 async resolveQueriesAsync() { 35786 if (!this.trackTimestamp || this.pendingResolve) { 35787 return this.lastValue; 35788 } 35789 this.pendingResolve = true; 35790 try { 35791 const resolvePromises = /* @__PURE__ */ new Map(); 35792 for (const [uid, baseOffset] of this.queryOffsets) { 35793 const state = this.queryStates.get(baseOffset); 35794 if (state === "ended") { 35795 const query = this.queries[baseOffset]; 35796 resolvePromises.set(uid, this.resolveQuery(query)); 35797 } 35798 } 35799 if (resolvePromises.size === 0) { 35800 return this.lastValue; 35801 } 35802 const framesDuration = {}; 35803 const frames = []; 35804 for (const [uid, promise] of resolvePromises) { 35805 const match = uid.match(/^(.*):f(\d+)$/); 35806 const frame = parseInt(match[2]); 35807 if (frames.includes(frame) === false) { 35808 frames.push(frame); 35809 } 35810 if (framesDuration[frame] === void 0) framesDuration[frame] = 0; 35811 const duration = await promise; 35812 this.timestamps.set(uid, duration); 35813 framesDuration[frame] += duration; 35814 } 35815 const totalDuration = framesDuration[frames[frames.length - 1]]; 35816 this.lastValue = totalDuration; 35817 this.frames = frames; 35818 this.currentQueryIndex = 0; 35819 this.queryOffsets.clear(); 35820 this.queryStates.clear(); 35821 this.activeQuery = null; 35822 return totalDuration; 35823 } catch (e) { 35824 error("Error resolving queries:", e); 35825 return this.lastValue; 35826 } finally { 35827 this.pendingResolve = false; 35828 } 35829 } 35830 /** 35831 * Resolves a single query, checking for completion and disjoint operation. 35832 * 35833 * @async 35834 * @param {WebGLQuery} query - The query object to resolve. 35835 * @returns {Promise<number>} The elapsed time in milliseconds. 35836 */ 35837 async resolveQuery(query) { 35838 return new Promise((resolve) => { 35839 if (this.isDisposed) { 35840 resolve(this.lastValue); 35841 return; 35842 } 35843 let timeoutId; 35844 let isResolved = false; 35845 const cleanup = () => { 35846 if (timeoutId) { 35847 clearTimeout(timeoutId); 35848 timeoutId = null; 35849 } 35850 }; 35851 const finalizeResolution = (value) => { 35852 if (!isResolved) { 35853 isResolved = true; 35854 cleanup(); 35855 resolve(value); 35856 } 35857 }; 35858 const checkQuery = () => { 35859 if (this.isDisposed) { 35860 finalizeResolution(this.lastValue); 35861 return; 35862 } 35863 try { 35864 const disjoint = this.gl.getParameter(this.ext.GPU_DISJOINT_EXT); 35865 if (disjoint) { 35866 finalizeResolution(this.lastValue); 35867 return; 35868 } 35869 const available = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT_AVAILABLE); 35870 if (!available) { 35871 timeoutId = setTimeout(checkQuery, 1); 35872 return; 35873 } 35874 const elapsed = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT); 35875 resolve(Number(elapsed) / 1e6); 35876 } catch (e) { 35877 error("Error checking query:", e); 35878 resolve(this.lastValue); 35879 } 35880 }; 35881 checkQuery(); 35882 }); 35883 } 35884 /** 35885 * Releases all resources held by this query pool. 35886 * This includes deleting all query objects and clearing internal state. 35887 */ 35888 dispose() { 35889 if (this.isDisposed) { 35890 return; 35891 } 35892 this.isDisposed = true; 35893 if (!this.trackTimestamp) return; 35894 for (const query of this.queries) { 35895 this.gl.deleteQuery(query); 35896 } 35897 this.queries = []; 35898 this.queryStates.clear(); 35899 this.queryOffsets.clear(); 35900 this.lastValue = 0; 35901 this.activeQuery = null; 35902 } 35903}; 35904var WebGLBackend = class extends Backend { 35905 /** 35906 * WebGLBackend options. 35907 * 35908 * @typedef {Object} WebGLBackend~Options 35909 * @property {boolean} [logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. 35910 * @property {boolean} [reversedDepthBuffer=false] - Whether reversed depth buffer is enabled or not. 35911 * @property {boolean} [alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. 35912 * @property {boolean} [depth=true] - Whether the default framebuffer should have a depth buffer or not. 35913 * @property {boolean} [stencil=false] - Whether the default framebuffer should have a stencil buffer or not. 35914 * @property {boolean} [antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. 35915 * @property {number} [samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. 35916 * @property {boolean} [forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. 35917 * @property {WebGL2RenderingContext} [context=undefined] - A WebGL 2 rendering context. 35918 */ 35919 /** 35920 * Constructs a new WebGPU backend. 35921 * 35922 * @param {WebGLBackend~Options} [parameters] - The configuration parameter. 35923 */ 35924 constructor(parameters = {}) { 35925 super(parameters); 35926 this.isWebGLBackend = true; 35927 this.attributeUtils = null; 35928 this.extensions = null; 35929 this.capabilities = null; 35930 this.textureUtils = null; 35931 this.bufferRenderer = null; 35932 this.gl = null; 35933 this.state = null; 35934 this.utils = null; 35935 this.vaoCache = {}; 35936 this.transformFeedbackCache = {}; 35937 this.discard = false; 35938 this.disjoint = null; 35939 this.parallel = null; 35940 this._currentContext = null; 35941 this._knownBindings = /* @__PURE__ */ new WeakSet(); 35942 this._supportsInvalidateFramebuffer = typeof navigator === "undefined" ? false : /OculusBrowser/g.test(navigator.userAgent); 35943 this._xrFramebuffer = null; 35944 } 35945 /** 35946 * Initializes the backend so it is ready for usage. 35947 * 35948 * @param {Renderer} renderer - The renderer. 35949 */ 35950 init(renderer) { 35951 super.init(renderer); 35952 const parameters = this.parameters; 35953 const contextAttributes = { 35954 antialias: renderer.currentSamples > 0, 35955 alpha: true, 35956 // always true for performance reasons 35957 depth: renderer.depth, 35958 stencil: renderer.stencil 35959 }; 35960 const glContext = parameters.context !== void 0 ? parameters.context : renderer.domElement.getContext("webgl2", contextAttributes); 35961 function onContextLost(event) { 35962 event.preventDefault(); 35963 const contextLossInfo = { 35964 api: "WebGL", 35965 message: event.statusMessage || "Unknown reason", 35966 reason: null, 35967 originalEvent: event 35968 }; 35969 renderer.onDeviceLost(contextLossInfo); 35970 } 35971 this._onContextLost = onContextLost; 35972 renderer.domElement.addEventListener("webglcontextlost", onContextLost, false); 35973 this.gl = glContext; 35974 this.extensions = new WebGLExtensions(this); 35975 this.capabilities = new WebGLCapabilities(this); 35976 this.attributeUtils = new WebGLAttributeUtils(this); 35977 this.textureUtils = new WebGLTextureUtils(this); 35978 this.bufferRenderer = new WebGLBufferRenderer(this); 35979 this.state = new WebGLState(this); 35980 this.utils = new WebGLUtils(this); 35981 this.extensions.get("EXT_color_buffer_float"); 35982 this.extensions.get("WEBGL_clip_cull_distance"); 35983 this.extensions.get("OES_texture_float_linear"); 35984 this.extensions.get("EXT_color_buffer_half_float"); 35985 this.extensions.get("WEBGL_multisampled_render_to_texture"); 35986 this.extensions.get("WEBGL_render_shared_exponent"); 35987 this.extensions.get("WEBGL_multi_draw"); 35988 this.extensions.get("OVR_multiview2"); 35989 this.extensions.get("EXT_clip_control"); 35990 this.disjoint = this.extensions.get("EXT_disjoint_timer_query_webgl2"); 35991 this.parallel = this.extensions.get("KHR_parallel_shader_compile"); 35992 this.drawBuffersIndexedExt = this.extensions.get("OES_draw_buffers_indexed"); 35993 if (parameters.reversedDepthBuffer) { 35994 if (this.extensions.has("EXT_clip_control")) { 35995 renderer.reversedDepthBuffer = true; 35996 } else { 35997 warn("WebGPURenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer."); 35998 renderer.reversedDepthBuffer = false; 35999 } 36000 } 36001 if (renderer.reversedDepthBuffer) { 36002 this.state.setReversedDepth(true); 36003 } 36004 } 36005 /** 36006 * The coordinate system of the backend. 36007 * 36008 * @type {number} 36009 * @readonly 36010 */ 36011 get coordinateSystem() { 36012 return WebGLCoordinateSystem; 36013 } 36014 /** 36015 * This method performs a readback operation by moving buffer data from 36016 * a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can 36017 * be used to retain and reuse handles to the intermediate buffers and prevent 36018 * new allocation. 36019 * 36020 * @async 36021 * @param {BufferAttribute} attribute - The storage buffer attribute to read frm. 36022 * @param {ReadbackBuffer|ArrayBuffer} target - The storage buffer attribute. 36023 * @param {number} offset - The storage buffer attribute. 36024 * @param {number} count - The offset from which to start reading the 36025 * @return {Promise<ArrayBuffer|ReadbackBuffer>} A promise that resolves with the buffer data when the data are ready. 36026 */ 36027 async getArrayBufferAsync(attribute3, target = null, offset3 = 0, count = -1) { 36028 return await this.attributeUtils.getArrayBufferAsync(attribute3, target, offset3, count); 36029 } 36030 /** 36031 * Ensures the backend is XR compatible. 36032 * 36033 * @async 36034 * @return {Promise} A Promise that resolve when the renderer is XR compatible. 36035 */ 36036 async makeXRCompatible() { 36037 const attributes = this.gl.getContextAttributes(); 36038 if (attributes.xrCompatible !== true) { 36039 await this.gl.makeXRCompatible(); 36040 } 36041 } 36042 /** 36043 * Sets the XR rendering destination. 36044 * 36045 * @param {WebGLFramebuffer} xrFramebuffer - The XR framebuffer. 36046 */ 36047 setXRTarget(xrFramebuffer) { 36048 this._xrFramebuffer = xrFramebuffer; 36049 } 36050 /** 36051 * Configures the given XR render target with external textures. 36052 * 36053 * This method is only relevant when using the WebXR Layers API. 36054 * 36055 * @param {XRRenderTarget} renderTarget - The XR render target. 36056 * @param {WebGLTexture} colorTexture - A native color texture. 36057 * @param {?WebGLTexture} [depthTexture=null] - A native depth texture. 36058 */ 36059 setXRRenderTargetTextures(renderTarget, colorTexture, depthTexture = null) { 36060 const gl = this.gl; 36061 this.set(renderTarget.texture, { textureGPU: colorTexture, glInternalFormat: gl.RGBA8 }); 36062 if (depthTexture !== null) { 36063 const glInternalFormat = renderTarget.stencilBuffer ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 36064 this.set(renderTarget.depthTexture, { textureGPU: depthTexture, glInternalFormat }); 36065 if (this.extensions.has("WEBGL_multisampled_render_to_texture") === true && renderTarget._autoAllocateDepthBuffer === true && renderTarget.multiview === false) { 36066 warn("WebGLBackend: Render-to-texture extension was disabled because an external texture was provided"); 36067 } 36068 renderTarget._autoAllocateDepthBuffer = false; 36069 } 36070 } 36071 /** 36072 * Inits a time stamp query for the given render context. 36073 * 36074 * @param {string} type - The type of the timestamp query. 36075 * @param {string} uid - A unique identifier for the timestamp query. 36076 */ 36077 initTimestampQuery(type, uid) { 36078 if (!this.disjoint || !this.trackTimestamp) return; 36079 if (!this.timestampQueryPool[type]) { 36080 this.timestampQueryPool[type] = new WebGLTimestampQueryPool(this.gl, type, 2048); 36081 } 36082 const timestampQueryPool = this.timestampQueryPool[type]; 36083 const baseOffset = timestampQueryPool.allocateQueriesForContext(uid); 36084 if (baseOffset !== null) { 36085 timestampQueryPool.beginQuery(uid); 36086 } 36087 } 36088 // timestamp utils 36089 /** 36090 * Prepares the timestamp buffer. 36091 * 36092 * @param {string} type - The type of the timestamp query. 36093 * @param {string} uid - A unique identifier for the timestamp query. 36094 */ 36095 prepareTimestampBuffer(type, uid) { 36096 if (!this.disjoint || !this.trackTimestamp) return; 36097 const timestampQueryPool = this.timestampQueryPool[type]; 36098 timestampQueryPool.endQuery(uid); 36099 } 36100 /** 36101 * Returns the backend's rendering context. 36102 * 36103 * @return {WebGL2RenderingContext} The rendering context. 36104 */ 36105 getContext() { 36106 return this.gl; 36107 } 36108 /** 36109 * This method is executed at the beginning of a render call and prepares 36110 * the WebGL state for upcoming render calls 36111 * 36112 * @param {RenderContext} renderContext - The render context. 36113 */ 36114 beginRender(renderContext) { 36115 const { state } = this; 36116 const renderContextData = this.get(renderContext); 36117 if (renderContext.viewport) { 36118 this.updateViewport(renderContext); 36119 } else { 36120 const { width, height } = this.getDrawingBufferSize(); 36121 state.viewport(0, 0, width, height); 36122 } 36123 if (renderContext.scissor) { 36124 this.updateScissor(renderContext); 36125 } else { 36126 const { width, height } = this.getDrawingBufferSize(); 36127 state.scissor(0, 0, width, height); 36128 } 36129 this.initTimestampQuery(TimestampQuery.RENDER, this.getTimestampUID(renderContext)); 36130 renderContextData.previousContext = this._currentContext; 36131 this._currentContext = renderContext; 36132 this._setFramebuffer(renderContext); 36133 this.clear(renderContext.clearColor, renderContext.clearDepth, renderContext.clearStencil, renderContext, false); 36134 const occlusionQueryCount = renderContext.occlusionQueryCount; 36135 if (occlusionQueryCount > 0) { 36136 renderContextData.currentOcclusionQueries = renderContextData.occlusionQueries; 36137 renderContextData.currentOcclusionQueryObjects = renderContextData.occlusionQueryObjects; 36138 renderContextData.lastOcclusionObject = null; 36139 renderContextData.occlusionQueries = new Array(occlusionQueryCount); 36140 renderContextData.occlusionQueryObjects = new Array(occlusionQueryCount); 36141 renderContextData.occlusionQueryIndex = 0; 36142 } 36143 } 36144 /** 36145 * This method is executed at the end of a render call and finalizes work 36146 * after draw calls. 36147 * 36148 * @param {RenderContext} renderContext - The render context. 36149 */ 36150 finishRender(renderContext) { 36151 const { gl, state } = this; 36152 const renderContextData = this.get(renderContext); 36153 const previousContext = renderContextData.previousContext; 36154 state.resetVertexState(); 36155 const occlusionQueryCount = renderContext.occlusionQueryCount; 36156 if (occlusionQueryCount > 0) { 36157 if (occlusionQueryCount > renderContextData.occlusionQueryIndex) { 36158 gl.endQuery(gl.ANY_SAMPLES_PASSED); 36159 } 36160 this.resolveOccludedAsync(renderContext); 36161 } 36162 const textures = renderContext.textures; 36163 if (textures !== null) { 36164 for (let i = 0; i < textures.length; i++) { 36165 const texture3 = textures[i]; 36166 if (texture3.generateMipmaps) { 36167 this.generateMipmaps(texture3); 36168 } 36169 } 36170 } 36171 this._currentContext = previousContext; 36172 this._resolveRenderTarget(renderContext); 36173 if (previousContext !== null) { 36174 this._setFramebuffer(previousContext); 36175 if (previousContext.viewport) { 36176 this.updateViewport(previousContext); 36177 } else { 36178 const { width, height } = this.getDrawingBufferSize(); 36179 state.viewport(0, 0, width, height); 36180 } 36181 if (previousContext.scissor) { 36182 this.updateScissor(previousContext); 36183 } else { 36184 const { width, height } = this.getDrawingBufferSize(); 36185 state.scissor(0, 0, width, height); 36186 } 36187 } 36188 this.prepareTimestampBuffer(TimestampQuery.RENDER, this.getTimestampUID(renderContext)); 36189 } 36190 /** 36191 * This method processes the result of occlusion queries and writes it 36192 * into render context data. 36193 * 36194 * @async 36195 * @param {RenderContext} renderContext - The render context. 36196 */ 36197 resolveOccludedAsync(renderContext) { 36198 const renderContextData = this.get(renderContext); 36199 const { currentOcclusionQueries, currentOcclusionQueryObjects } = renderContextData; 36200 if (currentOcclusionQueries && currentOcclusionQueryObjects) { 36201 const occluded = /* @__PURE__ */ new WeakSet(); 36202 const { gl } = this; 36203 renderContextData.currentOcclusionQueryObjects = null; 36204 renderContextData.currentOcclusionQueries = null; 36205 const check = () => { 36206 let completed = 0; 36207 for (let i = 0; i < currentOcclusionQueries.length; i++) { 36208 const query = currentOcclusionQueries[i]; 36209 if (query === null) continue; 36210 if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) { 36211 if (gl.getQueryParameter(query, gl.QUERY_RESULT) === 0) occluded.add(currentOcclusionQueryObjects[i]); 36212 currentOcclusionQueries[i] = null; 36213 gl.deleteQuery(query); 36214 completed++; 36215 } 36216 } 36217 if (completed < currentOcclusionQueries.length) { 36218 requestAnimationFrame(check); 36219 } else { 36220 renderContextData.occluded = occluded; 36221 } 36222 }; 36223 check(); 36224 } 36225 } 36226 /** 36227 * Returns `true` if the given 3D object is fully occluded by other 36228 * 3D objects in the scene. 36229 * 36230 * @param {RenderContext} renderContext - The render context. 36231 * @param {Object3D} object - The 3D object to test. 36232 * @return {boolean} Whether the 3D object is fully occluded or not. 36233 */ 36234 isOccluded(renderContext, object) { 36235 const renderContextData = this.get(renderContext); 36236 return renderContextData.occluded && renderContextData.occluded.has(object); 36237 } 36238 /** 36239 * Updates the viewport with the values from the given render context. 36240 * 36241 * @param {RenderContext} renderContext - The render context. 36242 */ 36243 updateViewport(renderContext) { 36244 const { state } = this; 36245 const { x, y, width, height } = renderContext.viewportValue; 36246 state.viewport(x, renderContext.height - height - y, width, height); 36247 } 36248 /** 36249 * Updates the scissor with the values from the given render context. 36250 * 36251 * @param {RenderContext} renderContext - The render context. 36252 */ 36253 updateScissor(renderContext) { 36254 const { state } = this; 36255 const { x, y, width, height } = renderContext.scissorValue; 36256 state.scissor(x, renderContext.height - height - y, width, height); 36257 } 36258 /** 36259 * Defines the scissor test. 36260 * 36261 * @param {boolean} boolean - Whether the scissor test should be enabled or not. 36262 */ 36263 setScissorTest(boolean) { 36264 const state = this.state; 36265 state.setScissorTest(boolean); 36266 } 36267 /** 36268 * Returns the clear color and alpha into a single 36269 * color object. 36270 * 36271 * @return {Color4} The clear color. 36272 */ 36273 getClearColor() { 36274 const clearColor = super.getClearColor(); 36275 clearColor.r *= clearColor.a; 36276 clearColor.g *= clearColor.a; 36277 clearColor.b *= clearColor.a; 36278 return clearColor; 36279 } 36280 /** 36281 * Performs a clear operation. 36282 * 36283 * @param {boolean} color - Whether the color buffer should be cleared or not. 36284 * @param {boolean} depth - Whether the depth buffer should be cleared or not. 36285 * @param {boolean} stencil - Whether the stencil buffer should be cleared or not. 36286 * @param {?Object} [descriptor=null] - The render context of the current set render target. 36287 * @param {boolean} [setFrameBuffer=true] - Controls whether the intermediate framebuffer should be set or not. 36288 * @param {boolean} [resolveRenderTarget=true] - Controls whether an active render target should be resolved 36289 * or not. Only relevant for explicit clears. 36290 */ 36291 clear(color3, depth3, stencil, descriptor = null, setFrameBuffer = true, resolveRenderTarget = true) { 36292 const { gl, renderer } = this; 36293 if (descriptor === null) { 36294 const clearColor = this.getClearColor(); 36295 descriptor = { 36296 textures: null, 36297 clearColorValue: clearColor 36298 }; 36299 } 36300 let clear = 0; 36301 if (color3) clear |= gl.COLOR_BUFFER_BIT; 36302 if (depth3) clear |= gl.DEPTH_BUFFER_BIT; 36303 if (stencil) clear |= gl.STENCIL_BUFFER_BIT; 36304 if (clear !== 0) { 36305 let clearColor; 36306 if (descriptor.clearColorValue) { 36307 clearColor = descriptor.clearColorValue; 36308 } else { 36309 clearColor = this.getClearColor(); 36310 } 36311 const clearDepth = renderer.getClearDepth(); 36312 const clearStencil = renderer.getClearStencil(); 36313 if (depth3) this.state.setDepthMask(true); 36314 if (descriptor.textures === null) { 36315 gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); 36316 gl.clear(clear); 36317 } else { 36318 if (setFrameBuffer) this._setFramebuffer(descriptor); 36319 if (color3) { 36320 for (let i = 0; i < descriptor.textures.length; i++) { 36321 if (i === 0) { 36322 gl.clearBufferfv(gl.COLOR, i, [clearColor.r, clearColor.g, clearColor.b, clearColor.a]); 36323 } else { 36324 gl.clearBufferfv(gl.COLOR, i, [0, 0, 0, 1]); 36325 } 36326 } 36327 } 36328 if (depth3 && stencil) { 36329 gl.clearBufferfi(gl.DEPTH_STENCIL, 0, clearDepth, clearStencil); 36330 } else if (depth3) { 36331 gl.clearBufferfv(gl.DEPTH, 0, [clearDepth]); 36332 } else if (stencil) { 36333 gl.clearBufferiv(gl.STENCIL, 0, [clearStencil]); 36334 } 36335 if (setFrameBuffer && resolveRenderTarget) this._resolveRenderTarget(descriptor); 36336 } 36337 } 36338 } 36339 /** 36340 * This method is executed at the beginning of a compute call and 36341 * prepares the state for upcoming compute tasks. 36342 * 36343 * @param {Node|Array<Node>} computeGroup - The compute node(s). 36344 */ 36345 beginCompute(computeGroup) { 36346 const { state, gl } = this; 36347 state.bindFramebuffer(gl.FRAMEBUFFER, null); 36348 this.initTimestampQuery(TimestampQuery.COMPUTE, this.getTimestampUID(computeGroup)); 36349 } 36350 /** 36351 * Executes a compute command for the given compute node. 36352 * 36353 * @param {Node|Array<Node>} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. 36354 * @param {Node} computeNode - The compute node. 36355 * @param {Array<BindGroup>} bindings - The bindings. 36356 * @param {ComputePipeline} pipeline - The compute pipeline. 36357 * @param {?number} [count=null] - The count of compute invocations. If `null`, the count is determined by the compute node. 36358 */ 36359 compute(computeGroup, computeNode, bindings, pipeline, count = null) { 36360 const { state, gl } = this; 36361 if (this.discard === false) { 36362 state.enable(gl.RASTERIZER_DISCARD); 36363 this.discard = true; 36364 } 36365 const { programGPU, transformBuffers, attributes } = this.get(pipeline); 36366 const vaoKey = this._getVaoKey(attributes); 36367 const vaoGPU = this.vaoCache[vaoKey]; 36368 if (vaoGPU === void 0) { 36369 this.vaoCache[vaoKey] = this._createVao(attributes); 36370 } else { 36371 state.setVertexState(vaoGPU); 36372 } 36373 state.useProgram(programGPU); 36374 this._bindUniforms(bindings); 36375 const transformFeedbackGPU = this._getTransformFeedback(transformBuffers); 36376 gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transformFeedbackGPU); 36377 gl.beginTransformFeedback(gl.POINTS); 36378 count = count !== null ? count : computeNode.count; 36379 if (Array.isArray(count)) { 36380 warnOnce("WebGLBackend.compute(): The count parameter must be a single number, not an array."); 36381 count = count[0]; 36382 } else if (count && typeof count === "object" && count.isIndirectStorageBufferAttribute) { 36383 warnOnce("WebGLBackend.compute(): The count parameter must be a single number, not IndirectStorageBufferAttribute"); 36384 count = computeNode.count; 36385 } 36386 if (attributes[0].isStorageInstancedBufferAttribute) { 36387 gl.drawArraysInstanced(gl.POINTS, 0, 1, count); 36388 } else { 36389 gl.drawArrays(gl.POINTS, 0, count); 36390 } 36391 gl.endTransformFeedback(); 36392 gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null); 36393 for (let i = 0; i < transformBuffers.length; i++) { 36394 const dualAttributeData = transformBuffers[i]; 36395 if (dualAttributeData.pbo && this.has(dualAttributeData.pbo)) { 36396 this.textureUtils.copyBufferToTexture(dualAttributeData.transformBuffer, dualAttributeData.pbo); 36397 } 36398 dualAttributeData.switchBuffers(); 36399 } 36400 } 36401 /** 36402 * This method is executed at the end of a compute call and 36403 * finalizes work after compute tasks. 36404 * 36405 * @param {Node|Array<Node>} computeGroup - The compute node(s). 36406 */ 36407 finishCompute(computeGroup) { 36408 const { state, gl } = this; 36409 this.discard = false; 36410 state.disable(gl.RASTERIZER_DISCARD); 36411 this.prepareTimestampBuffer(TimestampQuery.COMPUTE, this.getTimestampUID(computeGroup)); 36412 if (this._currentContext) { 36413 this._setFramebuffer(this._currentContext); 36414 } 36415 } 36416 /** 36417 * Internal to determine if the current render target is a render target array with depth 2D array texture. 36418 * 36419 * @param {RenderContext} renderContext - The render context. 36420 * @return {boolean} Whether the render target is a render target array with depth 2D array texture. 36421 * 36422 * @private 36423 */ 36424 _isRenderCameraDepthArray(renderContext) { 36425 return renderContext.depthTexture && renderContext.depthTexture.isArrayTexture && renderContext.camera.isArrayCamera; 36426 } 36427 /** 36428 * Internal draw function. 36429 * 36430 * @private 36431 * @param {Object3D} object - The object to render. 36432 * @param {WebGLBufferRenderer} renderer - The internal renderer. 36433 * @param {number} firstVertex - The first vertex to render. 36434 * @param {number} vertexCount - The vertex count. 36435 * @param {number} instanceCount - The intance count. 36436 * @param {WebGLProgram} programGPU - The raw WebGL shader program. 36437 */ 36438 _draw(object, renderer, firstVertex, vertexCount, instanceCount, programGPU) { 36439 if (object.isBatchedMesh) { 36440 if (this.hasFeature("WEBGL_multi_draw") === false) { 36441 const { gl } = this; 36442 const drawIdLocation = gl.getUniformLocation(programGPU, "nodeUniformDrawId"); 36443 const starts = object._multiDrawStarts; 36444 const counts = object._multiDrawCounts; 36445 const drawCount = object._multiDrawCount; 36446 for (let i = 0; i < drawCount; i++) { 36447 gl.uniform1ui(drawIdLocation, i); 36448 renderer.render(starts[i], counts[i]); 36449 } 36450 } else { 36451 renderer.renderMultiDraw(object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount); 36452 } 36453 } else if (instanceCount > 1) { 36454 renderer.renderInstances(firstVertex, vertexCount, instanceCount); 36455 } else { 36456 renderer.render(firstVertex, vertexCount); 36457 } 36458 } 36459 /** 36460 * Executes a draw command for the given render object. 36461 * 36462 * @param {RenderObject} renderObject - The render object to draw. 36463 * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. 36464 */ 36465 draw(renderObject) { 36466 const { object, pipeline, material, context: context3, hardwareClippingPlanes } = renderObject; 36467 const { programGPU } = this.get(pipeline); 36468 const { gl, state } = this; 36469 const contextData = this.get(context3); 36470 const drawParams = renderObject.getDrawParameters(); 36471 if (drawParams === null) return; 36472 this._bindUniforms(renderObject.getBindings()); 36473 const frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0; 36474 state.setMaterial(material, frontFaceCW, hardwareClippingPlanes); 36475 if (context3.mrt !== null && context3.textures !== null) { 36476 state.setMRTBlending(context3.textures, context3.mrt, material); 36477 } 36478 state.useProgram(programGPU); 36479 const attributes = renderObject.getAttributes(); 36480 const attributesData = this.get(attributes); 36481 let vaoGPU = attributesData.vaoGPU; 36482 if (vaoGPU === void 0) { 36483 const vaoKey = this._getVaoKey(attributes); 36484 vaoGPU = this.vaoCache[vaoKey]; 36485 if (vaoGPU === void 0) { 36486 vaoGPU = this._createVao(attributes); 36487 this.vaoCache[vaoKey] = vaoGPU; 36488 attributesData.vaoGPU = vaoGPU; 36489 } 36490 } 36491 const index = renderObject.getIndex(); 36492 const indexGPU = index !== null ? this.get(index).bufferGPU : null; 36493 state.setVertexState(vaoGPU, indexGPU); 36494 const lastObject = contextData.lastOcclusionObject; 36495 if (lastObject !== object && lastObject !== void 0) { 36496 if (lastObject !== null && lastObject.occlusionTest === true) { 36497 gl.endQuery(gl.ANY_SAMPLES_PASSED); 36498 contextData.occlusionQueryIndex++; 36499 } 36500 if (object.occlusionTest === true) { 36501 const query = gl.createQuery(); 36502 gl.beginQuery(gl.ANY_SAMPLES_PASSED, query); 36503 contextData.occlusionQueries[contextData.occlusionQueryIndex] = query; 36504 contextData.occlusionQueryObjects[contextData.occlusionQueryIndex] = object; 36505 } 36506 contextData.lastOcclusionObject = object; 36507 } 36508 const renderer = this.bufferRenderer; 36509 if (object.isPoints) renderer.mode = gl.POINTS; 36510 else if (object.isLineSegments) renderer.mode = gl.LINES; 36511 else if (object.isLine) renderer.mode = gl.LINE_STRIP; 36512 else if (object.isLineLoop) renderer.mode = gl.LINE_LOOP; 36513 else { 36514 if (material.wireframe === true) { 36515 state.setLineWidth(material.wireframeLinewidth * this.renderer.getPixelRatio()); 36516 renderer.mode = gl.LINES; 36517 } else { 36518 renderer.mode = gl.TRIANGLES; 36519 } 36520 } 36521 const { vertexCount, instanceCount } = drawParams; 36522 let { firstVertex } = drawParams; 36523 renderer.object = object; 36524 if (index !== null) { 36525 firstVertex *= index.array.BYTES_PER_ELEMENT; 36526 const indexData = this.get(index); 36527 renderer.index = index.count; 36528 renderer.type = indexData.type; 36529 } else { 36530 renderer.index = 0; 36531 } 36532 if (renderObject.camera.isArrayCamera === true && renderObject.camera.cameras.length > 0 && renderObject.camera.isMultiViewCamera === false) { 36533 const cameraData = this.get(renderObject.camera); 36534 const cameras = renderObject.camera.cameras; 36535 const cameraIndex3 = renderObject.getBindingGroup("cameraIndex").bindings[0]; 36536 if (cameraData.indexesGPU === void 0 || cameraData.indexesGPU.length !== cameras.length) { 36537 const data = new Uint32Array([0, 0, 0, 0]); 36538 const indexesGPU = []; 36539 for (let i = 0, len = cameras.length; i < len; i++) { 36540 const bufferGPU = gl.createBuffer(); 36541 data[0] = i; 36542 gl.bindBuffer(gl.UNIFORM_BUFFER, bufferGPU); 36543 gl.bufferData(gl.UNIFORM_BUFFER, data, gl.STATIC_DRAW); 36544 indexesGPU.push(bufferGPU); 36545 } 36546 cameraData.indexesGPU = indexesGPU; 36547 } 36548 let cameraIndexBufferIndex = 0; 36549 bindingsSearch: for (const bindGroup of renderObject.getBindings()) { 36550 for (const binding of bindGroup.bindings) { 36551 if (binding === cameraIndex3) break bindingsSearch; 36552 if (binding.isUniformsGroup || binding.isUniformBuffer) cameraIndexBufferIndex++; 36553 } 36554 } 36555 const pixelRatio = this.renderer.getPixelRatio(); 36556 const renderTarget = this._currentContext.renderTarget; 36557 const isRenderCameraDepthArray = this._isRenderCameraDepthArray(this._currentContext); 36558 const prevActiveCubeFace = this._currentContext.activeCubeFace; 36559 if (isRenderCameraDepthArray) { 36560 const textureData = this.get(renderTarget.depthTexture); 36561 if (textureData.clearedRenderId !== this.renderer._nodes.nodeFrame.renderId) { 36562 textureData.clearedRenderId = this.renderer._nodes.nodeFrame.renderId; 36563 const { stencilBuffer } = renderTarget; 36564 for (let i = 0, len = cameras.length; i < len; i++) { 36565 this.renderer._activeCubeFace = i; 36566 this._currentContext.activeCubeFace = i; 36567 this._setFramebuffer(this._currentContext); 36568 this.clear(false, true, stencilBuffer, this._currentContext, false, false); 36569 } 36570 this.renderer._activeCubeFace = prevActiveCubeFace; 36571 this._currentContext.activeCubeFace = prevActiveCubeFace; 36572 } 36573 } 36574 for (let i = 0, len = cameras.length; i < len; i++) { 36575 const subCamera = cameras[i]; 36576 if (object.layers.test(subCamera.layers)) { 36577 if (isRenderCameraDepthArray) { 36578 this.renderer._activeCubeFace = i; 36579 this._currentContext.activeCubeFace = i; 36580 this._setFramebuffer(this._currentContext); 36581 } 36582 const vp = subCamera.viewport; 36583 if (vp !== void 0) { 36584 const x = vp.x * pixelRatio; 36585 const y = vp.y * pixelRatio; 36586 const width = vp.width * pixelRatio; 36587 const height = vp.height * pixelRatio; 36588 state.viewport( 36589 Math.floor(x), 36590 Math.floor(renderObject.context.height - height - y), 36591 Math.floor(width), 36592 Math.floor(height) 36593 ); 36594 } 36595 state.bindBufferBase(gl.UNIFORM_BUFFER, cameraIndexBufferIndex, cameraData.indexesGPU[i]); 36596 this._draw(object, renderer, firstVertex, vertexCount, instanceCount, programGPU); 36597 } 36598 this._currentContext.activeCubeFace = prevActiveCubeFace; 36599 this.renderer._activeCubeFace = prevActiveCubeFace; 36600 } 36601 } else { 36602 this._draw(object, renderer, firstVertex, vertexCount, instanceCount, programGPU); 36603 } 36604 } 36605 /** 36606 * Explain why always null is returned. 36607 * 36608 * @param {RenderObject} renderObject - The render object. 36609 * @return {boolean} Whether the render pipeline requires an update or not. 36610 */ 36611 needsRenderUpdate() { 36612 return false; 36613 } 36614 /** 36615 * Explain why no cache key is computed. 36616 * 36617 * @param {RenderObject} renderObject - The render object. 36618 * @return {string} The cache key. 36619 */ 36620 getRenderCacheKey() { 36621 return ""; 36622 } 36623 // textures 36624 /** 36625 * Creates a default texture for the given texture that can be used 36626 * as a placeholder until the actual texture is ready for usage. 36627 * 36628 * @param {Texture} texture - The texture to create a default texture for. 36629 */ 36630 createDefaultTexture(texture3) { 36631 this.textureUtils.createDefaultTexture(texture3); 36632 } 36633 /** 36634 * Defines a texture on the GPU for the given texture object. 36635 * 36636 * @param {Texture} texture - The texture. 36637 * @param {Object} [options={}] - Optional configuration parameter. 36638 */ 36639 createTexture(texture3, options) { 36640 this.textureUtils.createTexture(texture3, options); 36641 } 36642 /** 36643 * Uploads the updated texture data to the GPU. 36644 * 36645 * @param {Texture} texture - The texture. 36646 * @param {Object} [options={}] - Optional configuration parameter. 36647 */ 36648 updateTexture(texture3, options) { 36649 this.textureUtils.updateTexture(texture3, options); 36650 } 36651 /** 36652 * Generates mipmaps for the given texture. 36653 * 36654 * @param {Texture} texture - The texture. 36655 */ 36656 generateMipmaps(texture3) { 36657 this.textureUtils.generateMipmaps(texture3); 36658 } 36659 /** 36660 * Destroys the GPU data for the given texture object. 36661 * 36662 * @param {Texture} texture - The texture. 36663 * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. 36664 */ 36665 destroyTexture(texture3, isDefaultTexture = false) { 36666 this.textureUtils.destroyTexture(texture3, isDefaultTexture); 36667 } 36668 /** 36669 * Returns texture data as a typed array. 36670 * 36671 * @async 36672 * @param {Texture} texture - The texture to copy. 36673 * @param {number} x - The x coordinate of the copy origin. 36674 * @param {number} y - The y coordinate of the copy origin. 36675 * @param {number} width - The width of the copy. 36676 * @param {number} height - The height of the copy. 36677 * @param {number} faceIndex - The face index. 36678 * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished. 36679 */ 36680 async copyTextureToBuffer(texture3, x, y, width, height, faceIndex) { 36681 return this.textureUtils.copyTextureToBuffer(texture3, x, y, width, height, faceIndex); 36682 } 36683 /** 36684 * This method does nothing since WebGL 2 has no concept of samplers. 36685 * 36686 * @param {Texture} texture - The texture to update the sampler for. 36687 * @return {string} The current sampler key. 36688 */ 36689 updateSampler() { 36690 return ""; 36691 } 36692 // node builder 36693 /** 36694 * Returns a node builder for the given render object. 36695 * 36696 * @param {RenderObject} object - The render object. 36697 * @param {Renderer} renderer - The renderer. 36698 * @return {GLSLNodeBuilder} The node builder. 36699 */ 36700 createNodeBuilder(object, renderer) { 36701 return new GLSLNodeBuilder(object, renderer); 36702 } 36703 // program 36704 /** 36705 * Creates a shader program from the given programmable stage. 36706 * 36707 * @param {ProgrammableStage} program - The programmable stage. 36708 */ 36709 createProgram(program) { 36710 const gl = this.gl; 36711 const { stage, code: code3 } = program; 36712 const shader = stage === "fragment" ? gl.createShader(gl.FRAGMENT_SHADER) : gl.createShader(gl.VERTEX_SHADER); 36713 gl.shaderSource(shader, code3); 36714 gl.compileShader(shader); 36715 this.set(program, { 36716 shaderGPU: shader 36717 }); 36718 } 36719 /** 36720 * Destroys the shader program of the given programmable stage. 36721 * 36722 * @param {ProgrammableStage} program - The programmable stage. 36723 */ 36724 destroyProgram(program) { 36725 this.delete(program); 36726 } 36727 /** 36728 * Creates a render pipeline for the given render object. 36729 * 36730 * @param {RenderObject} renderObject - The render object. 36731 * @param {Array<Promise>} promises - An array of compilation promises which are used in `compileAsync()`. 36732 */ 36733 createRenderPipeline(renderObject, promises) { 36734 const gl = this.gl; 36735 const pipeline = renderObject.pipeline; 36736 const { fragmentProgram, vertexProgram } = pipeline; 36737 const programGPU = gl.createProgram(); 36738 const fragmentShader = this.get(fragmentProgram).shaderGPU; 36739 const vertexShader = this.get(vertexProgram).shaderGPU; 36740 gl.attachShader(programGPU, fragmentShader); 36741 gl.attachShader(programGPU, vertexShader); 36742 gl.linkProgram(programGPU); 36743 this.set(pipeline, { 36744 programGPU, 36745 fragmentShader, 36746 vertexShader 36747 }); 36748 if (promises !== null && this.parallel) { 36749 const p = new Promise((resolve) => { 36750 const parallel = this.parallel; 36751 const checkStatus = () => { 36752 if (gl.getProgramParameter(programGPU, parallel.COMPLETION_STATUS_KHR)) { 36753 this._completeCompile(renderObject, pipeline); 36754 resolve(); 36755 } else { 36756 requestAnimationFrame(checkStatus); 36757 } 36758 }; 36759 checkStatus(); 36760 }); 36761 promises.push(p); 36762 return; 36763 } 36764 this._completeCompile(renderObject, pipeline); 36765 } 36766 /** 36767 * Formats the source code of error messages. 36768 * 36769 * @private 36770 * @param {string} string - The code. 36771 * @param {number} errorLine - The error line. 36772 * @return {string} The formatted code. 36773 */ 36774 _handleSource(string3, errorLine) { 36775 const lines = string3.split("\n"); 36776 const lines2 = []; 36777 const from = Math.max(errorLine - 6, 0); 36778 const to = Math.min(errorLine + 6, lines.length); 36779 for (let i = from; i < to; i++) { 36780 const line = i + 1; 36781 lines2.push(`${line === errorLine ? ">" : " "} ${line}: ${lines[i]}`); 36782 } 36783 return lines2.join("\n"); 36784 } 36785 /** 36786 * Gets the shader compilation errors from the info log. 36787 * 36788 * @private 36789 * @param {WebGL2RenderingContext} gl - The rendering context. 36790 * @param {WebGLShader} shader - The WebGL shader object. 36791 * @param {string} type - The shader type. 36792 * @return {string} The shader errors. 36793 */ 36794 _getShaderErrors(gl, shader, type) { 36795 const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 36796 const shaderInfoLog = gl.getShaderInfoLog(shader) || ""; 36797 const errors = shaderInfoLog.trim(); 36798 if (status && errors === "") return ""; 36799 const errorMatches = /ERROR: 0:(\d+)/.exec(errors); 36800 if (errorMatches) { 36801 const errorLine = parseInt(errorMatches[1]); 36802 return type.toUpperCase() + "\n\n" + errors + "\n\n" + this._handleSource(gl.getShaderSource(shader), errorLine); 36803 } else { 36804 return errors; 36805 } 36806 } 36807 /** 36808 * Logs shader compilation errors. 36809 * 36810 * @private 36811 * @param {WebGLProgram} programGPU - The WebGL program. 36812 * @param {WebGLShader} glFragmentShader - The fragment shader as a native WebGL shader object. 36813 * @param {WebGLShader} glVertexShader - The vertex shader as a native WebGL shader object. 36814 */ 36815 _logProgramError(programGPU, glFragmentShader, glVertexShader) { 36816 if (this.renderer.debug.checkShaderErrors) { 36817 const gl = this.gl; 36818 const programInfoLog = gl.getProgramInfoLog(programGPU) || ""; 36819 const programLog = programInfoLog.trim(); 36820 if (gl.getProgramParameter(programGPU, gl.LINK_STATUS) === false) { 36821 if (typeof this.renderer.debug.onShaderError === "function") { 36822 this.renderer.debug.onShaderError(gl, programGPU, glVertexShader, glFragmentShader); 36823 } else { 36824 const vertexErrors = this._getShaderErrors(gl, glVertexShader, "vertex"); 36825 const fragmentErrors = this._getShaderErrors(gl, glFragmentShader, "fragment"); 36826 error( 36827 "THREE.WebGLProgram: Shader Error " + gl.getError() + " - VALIDATE_STATUS " + gl.getProgramParameter(programGPU, gl.VALIDATE_STATUS) + "\n\nProgram Info Log: " + programLog + "\n" + vertexErrors + "\n" + fragmentErrors 36828 ); 36829 } 36830 } else if (programLog !== "") { 36831 warn("WebGLProgram: Program Info Log:", programLog); 36832 } 36833 } 36834 } 36835 /** 36836 * Completes the shader program setup for the given render object. 36837 * 36838 * @private 36839 * @param {RenderObject} renderObject - The render object. 36840 * @param {RenderPipeline} pipeline - The render pipeline. 36841 */ 36842 _completeCompile(renderObject, pipeline) { 36843 const { state, gl } = this; 36844 const pipelineData = this.get(pipeline); 36845 const { programGPU, fragmentShader, vertexShader } = pipelineData; 36846 if (gl.getProgramParameter(programGPU, gl.LINK_STATUS) === false) { 36847 this._logProgramError(programGPU, fragmentShader, vertexShader); 36848 } 36849 state.useProgram(programGPU); 36850 const bindings = renderObject.getBindings(); 36851 this._setupBindings(bindings, programGPU); 36852 this.set(pipeline, { 36853 programGPU, 36854 pipeline: programGPU 36855 }); 36856 } 36857 /** 36858 * Creates a compute pipeline for the given compute node. 36859 * 36860 * @param {ComputePipeline} computePipeline - The compute pipeline. 36861 * @param {Array<BindGroup>} bindings - The bindings. 36862 */ 36863 createComputePipeline(computePipeline, bindings) { 36864 const { state, gl } = this; 36865 const fragmentProgram = { 36866 stage: "fragment", 36867 code: "#version 300 es\nprecision highp float;\nvoid main() {}" 36868 }; 36869 this.createProgram(fragmentProgram); 36870 const { computeProgram } = computePipeline; 36871 const programGPU = gl.createProgram(); 36872 const fragmentShader = this.get(fragmentProgram).shaderGPU; 36873 const vertexShader = this.get(computeProgram).shaderGPU; 36874 const transforms = computeProgram.transforms; 36875 const transformVaryingNames = []; 36876 const transformAttributeNodes = []; 36877 for (let i = 0; i < transforms.length; i++) { 36878 const transform = transforms[i]; 36879 transformVaryingNames.push(transform.varyingName); 36880 transformAttributeNodes.push(transform.attributeNode); 36881 } 36882 gl.attachShader(programGPU, fragmentShader); 36883 gl.attachShader(programGPU, vertexShader); 36884 gl.transformFeedbackVaryings( 36885 programGPU, 36886 transformVaryingNames, 36887 gl.SEPARATE_ATTRIBS 36888 ); 36889 gl.linkProgram(programGPU); 36890 if (gl.getProgramParameter(programGPU, gl.LINK_STATUS) === false) { 36891 this._logProgramError(programGPU, fragmentShader, vertexShader); 36892 } 36893 state.useProgram(programGPU); 36894 this._setupBindings(bindings, programGPU); 36895 const attributeNodes = computeProgram.attributes; 36896 const attributes = []; 36897 const transformBuffers = []; 36898 for (let i = 0; i < attributeNodes.length; i++) { 36899 const attribute3 = attributeNodes[i].node.attribute; 36900 attributes.push(attribute3); 36901 if (!this.has(attribute3)) this.attributeUtils.createAttribute(attribute3, gl.ARRAY_BUFFER); 36902 } 36903 for (let i = 0; i < transformAttributeNodes.length; i++) { 36904 const attribute3 = transformAttributeNodes[i].attribute; 36905 if (!this.has(attribute3)) this.attributeUtils.createAttribute(attribute3, gl.ARRAY_BUFFER); 36906 const attributeData = this.get(attribute3); 36907 transformBuffers.push(attributeData); 36908 } 36909 this.set(computePipeline, { 36910 programGPU, 36911 transformBuffers, 36912 attributes 36913 }); 36914 } 36915 /** 36916 * Creates bindings from the given bind group definition. 36917 * 36918 * @param {BindGroup} bindGroup - The bind group. 36919 * @param {Array<BindGroup>} bindings - Array of bind groups. 36920 * @param {number} cacheIndex - The cache index. 36921 * @param {number} version - The version. 36922 */ 36923 createBindings(bindGroup, bindings) { 36924 if (this._knownBindings.has(bindings) === false) { 36925 this._knownBindings.add(bindings); 36926 let uniformBuffers = 0; 36927 let textures = 0; 36928 for (const bindGroup2 of bindings) { 36929 this.set(bindGroup2, { 36930 textures, 36931 uniformBuffers 36932 }); 36933 for (const binding of bindGroup2.bindings) { 36934 if (binding.isUniformBuffer) uniformBuffers++; 36935 if (binding.isSampledTexture) textures++; 36936 } 36937 } 36938 } 36939 this.updateBindings(bindGroup, bindings); 36940 } 36941 /** 36942 * Updates the given bind group definition. 36943 * 36944 * @param {BindGroup} bindGroup - The bind group. 36945 * @param {Array<BindGroup>} bindings - Array of bind groups. 36946 * @param {number} cacheIndex - The cache index. 36947 * @param {number} version - The version. 36948 */ 36949 updateBindings(bindGroup) { 36950 const { gl } = this; 36951 for (const binding of bindGroup.bindings) { 36952 const map = this.get(binding); 36953 if (binding.isUniformsGroup || binding.isUniformBuffer) { 36954 const array3 = binding.buffer; 36955 let { bufferGPU } = this.get(array3); 36956 if (bufferGPU === void 0) { 36957 bufferGPU = gl.createBuffer(); 36958 gl.bindBuffer(gl.UNIFORM_BUFFER, bufferGPU); 36959 gl.bufferData(gl.UNIFORM_BUFFER, array3.byteLength, gl.DYNAMIC_DRAW); 36960 this.set(array3, { bufferGPU }); 36961 } else { 36962 gl.bindBuffer(gl.UNIFORM_BUFFER, bufferGPU); 36963 } 36964 const updateRanges = binding.updateRanges; 36965 gl.bindBuffer(gl.UNIFORM_BUFFER, bufferGPU); 36966 if (updateRanges.length === 0) { 36967 gl.bufferData(gl.UNIFORM_BUFFER, array3, gl.DYNAMIC_DRAW); 36968 } else { 36969 const isTyped = isTypedArray(array3); 36970 const byteOffsetFactor = isTyped ? 1 : array3.BYTES_PER_ELEMENT; 36971 for (let i = 0, l = updateRanges.length; i < l; i++) { 36972 const range3 = updateRanges[i]; 36973 const dataOffset = range3.start * byteOffsetFactor; 36974 const size3 = range3.count * byteOffsetFactor; 36975 const bufferOffset = dataOffset * (isTyped ? array3.BYTES_PER_ELEMENT : 1); 36976 gl.bufferSubData(gl.UNIFORM_BUFFER, bufferOffset, array3, dataOffset, size3); 36977 } 36978 } 36979 map.bufferGPU = bufferGPU; 36980 this.set(binding, map); 36981 } else if (binding.isSampledTexture) { 36982 const { textureGPU, glTextureType } = this.get(binding.texture); 36983 map.textureGPU = textureGPU; 36984 map.glTextureType = glTextureType; 36985 this.set(binding, map); 36986 } 36987 } 36988 } 36989 /** 36990 * Updates a buffer binding. 36991 * 36992 * @param {Buffer} binding - The buffer binding to update. 36993 */ 36994 updateBinding(binding) { 36995 const gl = this.gl; 36996 if (binding.isUniformsGroup || binding.isUniformBuffer) { 36997 const bindingData = this.get(binding); 36998 const bufferGPU = bindingData.bufferGPU; 36999 const array3 = binding.buffer; 37000 const updateRanges = binding.updateRanges; 37001 gl.bindBuffer(gl.UNIFORM_BUFFER, bufferGPU); 37002 if (updateRanges.length === 0) { 37003 gl.bufferData(gl.UNIFORM_BUFFER, array3, gl.DYNAMIC_DRAW); 37004 } else { 37005 const isTyped = isTypedArray(array3); 37006 const byteOffsetFactor = isTyped ? 1 : array3.BYTES_PER_ELEMENT; 37007 for (let i = 0, l = updateRanges.length; i < l; i++) { 37008 const range3 = updateRanges[i]; 37009 const dataOffset = range3.start * byteOffsetFactor; 37010 const size3 = range3.count * byteOffsetFactor; 37011 const bufferOffset = dataOffset * (isTyped ? array3.BYTES_PER_ELEMENT : 1); 37012 gl.bufferSubData(gl.UNIFORM_BUFFER, bufferOffset, array3, dataOffset, size3); 37013 } 37014 } 37015 } 37016 } 37017 // attributes 37018 /** 37019 * Creates the GPU buffer of an indexed shader attribute. 37020 * 37021 * @param {BufferAttribute} attribute - The indexed buffer attribute. 37022 */ 37023 createIndexAttribute(attribute3) { 37024 const gl = this.gl; 37025 this.attributeUtils.createAttribute(attribute3, gl.ELEMENT_ARRAY_BUFFER); 37026 } 37027 /** 37028 * Creates the GPU buffer of a shader attribute. 37029 * 37030 * @param {BufferAttribute} attribute - The buffer attribute. 37031 */ 37032 createAttribute(attribute3) { 37033 if (this.has(attribute3)) return; 37034 const gl = this.gl; 37035 this.attributeUtils.createAttribute(attribute3, gl.ARRAY_BUFFER); 37036 } 37037 /** 37038 * Creates the GPU buffer of a storage attribute. 37039 * 37040 * @param {BufferAttribute} attribute - The buffer attribute. 37041 */ 37042 createStorageAttribute(attribute3) { 37043 if (this.has(attribute3)) return; 37044 const gl = this.gl; 37045 this.attributeUtils.createAttribute(attribute3, gl.ARRAY_BUFFER); 37046 } 37047 /** 37048 * Updates the GPU buffer of a shader attribute. 37049 * 37050 * @param {BufferAttribute} attribute - The buffer attribute to update. 37051 */ 37052 updateAttribute(attribute3) { 37053 this.attributeUtils.updateAttribute(attribute3); 37054 } 37055 /** 37056 * Destroys the GPU buffer of a shader attribute. 37057 * 37058 * @param {BufferAttribute} attribute - The buffer attribute to destroy. 37059 */ 37060 destroyAttribute(attribute3) { 37061 this.attributeUtils.destroyAttribute(attribute3); 37062 } 37063 /** 37064 * Checks if the given feature is supported by the backend. 37065 * 37066 * @param {string} name - The feature's name. 37067 * @return {boolean} Whether the feature is supported or not. 37068 */ 37069 hasFeature(name) { 37070 const keysMatching = Object.keys(GLFeatureName).filter((key) => GLFeatureName[key] === name); 37071 const extensions = this.extensions; 37072 for (let i = 0; i < keysMatching.length; i++) { 37073 if (extensions.has(keysMatching[i])) return true; 37074 } 37075 return false; 37076 } 37077 /** 37078 * Copies data of the given source texture to the given destination texture. 37079 * 37080 * @param {Texture} srcTexture - The source texture. 37081 * @param {Texture} dstTexture - The destination texture. 37082 * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy. 37083 * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy. 37084 * @param {number} [srcLevel=0] - The source mip level to copy from. 37085 * @param {number} [dstLevel=0] - The destination mip level to copy to. 37086 */ 37087 copyTextureToTexture(srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0) { 37088 this.textureUtils.copyTextureToTexture(srcTexture, dstTexture, srcRegion, dstPosition, srcLevel, dstLevel); 37089 } 37090 /** 37091 * Copies the current bound framebuffer to the given texture. 37092 * 37093 * @param {Texture} texture - The destination texture. 37094 * @param {RenderContext} renderContext - The render context. 37095 * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. 37096 */ 37097 copyFramebufferToTexture(texture3, renderContext, rectangle) { 37098 this.textureUtils.copyFramebufferToTexture(texture3, renderContext, rectangle); 37099 } 37100 /** 37101 * Checks if the given compatibility is supported by the backend. 37102 * 37103 * @param {string} name - The compatibility name. 37104 * @return {boolean} Whether the compatibility is supported or not. 37105 */ 37106 hasCompatibility(name) { 37107 if (name === Compatibility.TEXTURE_COMPARE) return true; 37108 return super.hasCompatibility(name); 37109 } 37110 /** 37111 * Initializes the render target defined in the given render context. 37112 * 37113 * @param {RenderContext} renderContext - The render context. 37114 */ 37115 initRenderTarget(renderContext) { 37116 const { gl, state } = this; 37117 this._setFramebuffer(renderContext); 37118 state.bindFramebuffer(gl.FRAMEBUFFER, null); 37119 } 37120 /** 37121 * Configures the active framebuffer from the given render context. 37122 * 37123 * @private 37124 * @param {RenderContext} descriptor - The render context. 37125 */ 37126 _setFramebuffer(descriptor) { 37127 const { gl, state } = this; 37128 let currentFrameBuffer = null; 37129 if (descriptor.textures !== null) { 37130 const renderTarget = descriptor.renderTarget; 37131 const renderTargetContextData = this.get(renderTarget); 37132 const { samples, depthBuffer, stencilBuffer } = renderTarget; 37133 const isCube = renderTarget.isCubeRenderTarget === true; 37134 const isRenderTarget3D = renderTarget.isRenderTarget3D === true; 37135 const isRenderTargetArray = renderTarget.depth > 1; 37136 const isXRRenderTarget = renderTarget.isXRRenderTarget === true; 37137 const _hasExternalTextures = isXRRenderTarget === true && renderTarget._hasExternalTextures === true; 37138 let msaaFb = renderTargetContextData.msaaFrameBuffer; 37139 let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; 37140 const multisampledRTTExt = this.extensions.get("WEBGL_multisampled_render_to_texture"); 37141 const multiviewExt = this.extensions.get("OVR_multiview2"); 37142 const useMultisampledRTT = this._useMultisampledExtension(renderTarget); 37143 const cacheKey = getCacheKey(descriptor); 37144 let fb; 37145 if (isCube) { 37146 renderTargetContextData.cubeFramebuffers || (renderTargetContextData.cubeFramebuffers = {}); 37147 fb = renderTargetContextData.cubeFramebuffers[cacheKey]; 37148 } else if (isXRRenderTarget && _hasExternalTextures === false) { 37149 fb = this._xrFramebuffer; 37150 } else { 37151 renderTargetContextData.framebuffers || (renderTargetContextData.framebuffers = {}); 37152 fb = renderTargetContextData.framebuffers[cacheKey]; 37153 } 37154 if (fb === void 0) { 37155 fb = gl.createFramebuffer(); 37156 state.bindFramebuffer(gl.FRAMEBUFFER, fb); 37157 const textures = descriptor.textures; 37158 const depthInvalidationArray = []; 37159 if (isCube) { 37160 renderTargetContextData.cubeFramebuffers[cacheKey] = fb; 37161 const { textureGPU } = this.get(textures[0]); 37162 const cubeFace = this.renderer._activeCubeFace; 37163 const mipLevel = this.renderer._activeMipmapLevel; 37164 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + cubeFace, textureGPU, mipLevel); 37165 } else { 37166 renderTargetContextData.framebuffers[cacheKey] = fb; 37167 for (let i = 0; i < textures.length; i++) { 37168 const texture3 = textures[i]; 37169 const textureData = this.get(texture3); 37170 textureData.renderTarget = descriptor.renderTarget; 37171 textureData.cacheKey = cacheKey; 37172 const attachment = gl.COLOR_ATTACHMENT0 + i; 37173 if (renderTarget.multiview) { 37174 multiviewExt.framebufferTextureMultisampleMultiviewOVR(gl.FRAMEBUFFER, attachment, textureData.textureGPU, 0, samples, 0, 2); 37175 } else if (isRenderTarget3D || isRenderTargetArray) { 37176 const layer = this.renderer._activeCubeFace; 37177 const mipLevel = this.renderer._activeMipmapLevel; 37178 gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, textureData.textureGPU, mipLevel, layer); 37179 } else { 37180 if (useMultisampledRTT) { 37181 multisampledRTTExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0, samples); 37182 } else { 37183 const mipLevel = this.renderer._activeMipmapLevel; 37184 gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, mipLevel); 37185 } 37186 } 37187 } 37188 } 37189 const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; 37190 if (renderTarget._autoAllocateDepthBuffer === true) { 37191 const renderbuffer = gl.createRenderbuffer(); 37192 this.textureUtils.setupRenderBufferStorage(renderbuffer, descriptor, 0, useMultisampledRTT); 37193 renderTargetContextData.xrDepthRenderbuffer = renderbuffer; 37194 depthInvalidationArray.push(stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT); 37195 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); 37196 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, depthStyle, gl.RENDERBUFFER, renderbuffer); 37197 } else { 37198 if (descriptor.depthTexture !== null) { 37199 depthInvalidationArray.push(stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT); 37200 const textureData = this.get(descriptor.depthTexture); 37201 textureData.renderTarget = descriptor.renderTarget; 37202 textureData.cacheKey = cacheKey; 37203 if (renderTarget.multiview) { 37204 multiviewExt.framebufferTextureMultisampleMultiviewOVR(gl.FRAMEBUFFER, depthStyle, textureData.textureGPU, 0, samples, 0, 2); 37205 } else if (_hasExternalTextures && useMultisampledRTT) { 37206 multisampledRTTExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData.textureGPU, 0, samples); 37207 } else { 37208 if (descriptor.depthTexture.isArrayTexture) { 37209 const layer = this.renderer._activeCubeFace; 37210 gl.framebufferTextureLayer(gl.FRAMEBUFFER, depthStyle, textureData.textureGPU, 0, layer); 37211 } else if (descriptor.depthTexture.isCubeTexture) { 37212 const cubeFace = this.renderer._activeCubeFace; 37213 gl.framebufferTexture2D(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_CUBE_MAP_POSITIVE_X + cubeFace, textureData.textureGPU, 0); 37214 } else { 37215 gl.framebufferTexture2D(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData.textureGPU, 0); 37216 } 37217 } 37218 } 37219 } 37220 renderTargetContextData.depthInvalidationArray = depthInvalidationArray; 37221 } else { 37222 const isRenderCameraDepthArray = this._isRenderCameraDepthArray(descriptor); 37223 if (isRenderCameraDepthArray) { 37224 state.bindFramebuffer(gl.FRAMEBUFFER, fb); 37225 const layer = this.renderer._activeCubeFace; 37226 const depthData = this.get(descriptor.depthTexture); 37227 const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; 37228 gl.framebufferTextureLayer( 37229 gl.FRAMEBUFFER, 37230 depthStyle, 37231 depthData.textureGPU, 37232 0, 37233 layer 37234 ); 37235 } 37236 if ((isXRRenderTarget || useMultisampledRTT || renderTarget.multiview) && renderTarget._isOpaqueFramebuffer !== true) { 37237 state.bindFramebuffer(gl.FRAMEBUFFER, fb); 37238 const textureData = this.get(descriptor.textures[0]); 37239 if (renderTarget.multiview) { 37240 multiviewExt.framebufferTextureMultisampleMultiviewOVR(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, textureData.textureGPU, 0, samples, 0, 2); 37241 } else if (useMultisampledRTT) { 37242 multisampledRTTExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureData.textureGPU, 0, samples); 37243 } else { 37244 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureData.textureGPU, 0); 37245 } 37246 const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; 37247 if (renderTarget._autoAllocateDepthBuffer === true) { 37248 const renderbuffer = renderTargetContextData.xrDepthRenderbuffer; 37249 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); 37250 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, depthStyle, gl.RENDERBUFFER, renderbuffer); 37251 } else { 37252 const textureData2 = this.get(descriptor.depthTexture); 37253 if (renderTarget.multiview) { 37254 multiviewExt.framebufferTextureMultisampleMultiviewOVR(gl.FRAMEBUFFER, depthStyle, textureData2.textureGPU, 0, samples, 0, 2); 37255 } else if (useMultisampledRTT) { 37256 multisampledRTTExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData2.textureGPU, 0, samples); 37257 } else { 37258 gl.framebufferTexture2D(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData2.textureGPU, 0); 37259 } 37260 } 37261 } 37262 } 37263 if (samples > 0 && useMultisampledRTT === false && !renderTarget.multiview) { 37264 if (msaaFb === void 0) { 37265 const invalidationArray = []; 37266 msaaFb = gl.createFramebuffer(); 37267 state.bindFramebuffer(gl.FRAMEBUFFER, msaaFb); 37268 const msaaRenderbuffers = []; 37269 const textures = descriptor.textures; 37270 for (let i = 0; i < textures.length; i++) { 37271 msaaRenderbuffers[i] = gl.createRenderbuffer(); 37272 gl.bindRenderbuffer(gl.RENDERBUFFER, msaaRenderbuffers[i]); 37273 invalidationArray.push(gl.COLOR_ATTACHMENT0 + i); 37274 const texture3 = descriptor.textures[i]; 37275 const textureData = this.get(texture3); 37276 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, textureData.glInternalFormat, descriptor.width, descriptor.height); 37277 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, msaaRenderbuffers[i]); 37278 } 37279 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 37280 renderTargetContextData.msaaFrameBuffer = msaaFb; 37281 renderTargetContextData.msaaRenderbuffers = msaaRenderbuffers; 37282 if (depthBuffer && depthRenderbuffer === void 0) { 37283 depthRenderbuffer = gl.createRenderbuffer(); 37284 this.textureUtils.setupRenderBufferStorage(depthRenderbuffer, descriptor, samples); 37285 renderTargetContextData.depthRenderbuffer = depthRenderbuffer; 37286 const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT; 37287 invalidationArray.push(depthStyle); 37288 } 37289 renderTargetContextData.invalidationArray = invalidationArray; 37290 } 37291 currentFrameBuffer = renderTargetContextData.msaaFrameBuffer; 37292 } else { 37293 currentFrameBuffer = fb; 37294 } 37295 state.drawBuffers(descriptor, fb); 37296 } 37297 state.bindFramebuffer(gl.FRAMEBUFFER, currentFrameBuffer); 37298 } 37299 /** 37300 * Computes the VAO key for the given index and attributes. 37301 * 37302 * @private 37303 * @param {Array<BufferAttribute>} attributes - An array of buffer attributes. 37304 * @return {string} The VAO key. 37305 */ 37306 _getVaoKey(attributes) { 37307 let key = ""; 37308 for (let i = 0; i < attributes.length; i++) { 37309 const attributeData = this.get(attributes[i]); 37310 key += ":" + attributeData.id; 37311 } 37312 return key; 37313 } 37314 /** 37315 * Creates a VAO from the index and attributes. 37316 * 37317 * @private 37318 * @param {Array<BufferAttribute>} attributes - An array of buffer attributes. 37319 * @return {Object} The VAO data. 37320 */ 37321 _createVao(attributes) { 37322 const { gl } = this; 37323 const vaoGPU = gl.createVertexArray(); 37324 gl.bindVertexArray(vaoGPU); 37325 for (let i = 0; i < attributes.length; i++) { 37326 const attribute3 = attributes[i]; 37327 const attributeData = this.get(attribute3); 37328 gl.bindBuffer(gl.ARRAY_BUFFER, attributeData.bufferGPU); 37329 gl.enableVertexAttribArray(i); 37330 let stride, offset3; 37331 if (attribute3.isInterleavedBufferAttribute === true) { 37332 stride = attribute3.data.stride * attributeData.bytesPerElement; 37333 offset3 = attribute3.offset * attributeData.bytesPerElement; 37334 } else { 37335 stride = 0; 37336 offset3 = 0; 37337 } 37338 if (attributeData.isInteger) { 37339 gl.vertexAttribIPointer(i, attribute3.itemSize, attributeData.type, stride, offset3); 37340 } else { 37341 gl.vertexAttribPointer(i, attribute3.itemSize, attributeData.type, attribute3.normalized, stride, offset3); 37342 } 37343 if (attribute3.isInstancedBufferAttribute && !attribute3.isInterleavedBufferAttribute) { 37344 gl.vertexAttribDivisor(i, attribute3.meshPerAttribute); 37345 } else if (attribute3.isInterleavedBufferAttribute && attribute3.data.isInstancedInterleavedBuffer) { 37346 gl.vertexAttribDivisor(i, attribute3.data.meshPerAttribute); 37347 } 37348 } 37349 gl.bindBuffer(gl.ARRAY_BUFFER, null); 37350 return vaoGPU; 37351 } 37352 /** 37353 * Creates a transform feedback from the given transform buffers. 37354 * 37355 * @private 37356 * @param {Array<DualAttributeData>} transformBuffers - The transform buffers. 37357 * @return {WebGLTransformFeedback} The transform feedback. 37358 */ 37359 _getTransformFeedback(transformBuffers) { 37360 let key = ""; 37361 for (let i = 0; i < transformBuffers.length; i++) { 37362 key += ":" + transformBuffers[i].id; 37363 } 37364 let transformFeedbackGPU = this.transformFeedbackCache[key]; 37365 if (transformFeedbackGPU !== void 0) { 37366 return transformFeedbackGPU; 37367 } 37368 const { gl } = this; 37369 transformFeedbackGPU = gl.createTransformFeedback(); 37370 gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transformFeedbackGPU); 37371 for (let i = 0; i < transformBuffers.length; i++) { 37372 const attributeData = transformBuffers[i]; 37373 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, i, attributeData.transformBuffer); 37374 } 37375 gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null); 37376 this.transformFeedbackCache[key] = transformFeedbackGPU; 37377 return transformFeedbackGPU; 37378 } 37379 /** 37380 * Setups the given bindings. 37381 * 37382 * @private 37383 * @param {Array<BindGroup>} bindings - The bindings. 37384 * @param {WebGLProgram} programGPU - The WebGL program. 37385 */ 37386 _setupBindings(bindings, programGPU) { 37387 const gl = this.gl; 37388 let uniformBuffers = 0; 37389 let textures = 0; 37390 for (const bindGroup of bindings) { 37391 for (const binding of bindGroup.bindings) { 37392 if (binding.isUniformsGroup || binding.isUniformBuffer) { 37393 const index = uniformBuffers++; 37394 const location = gl.getUniformBlockIndex(programGPU, binding.name); 37395 gl.uniformBlockBinding(programGPU, location, index); 37396 } else if (binding.isSampledTexture) { 37397 const index = textures++; 37398 const location = gl.getUniformLocation(programGPU, binding.name); 37399 gl.uniform1i(location, index); 37400 } 37401 } 37402 } 37403 } 37404 /** 37405 * Binds the given uniforms. 37406 * 37407 * @private 37408 * @param {Array<BindGroup>} bindings - The bindings. 37409 */ 37410 _bindUniforms(bindings) { 37411 const { gl, state } = this; 37412 let uniformBuffers = 0; 37413 let textures = 0; 37414 for (const bindGroup of bindings) { 37415 for (const binding of bindGroup.bindings) { 37416 const bindingData = this.get(binding); 37417 if (binding.isUniformsGroup || binding.isUniformBuffer) { 37418 const index = uniformBuffers++; 37419 state.bindBufferBase(gl.UNIFORM_BUFFER, index, bindingData.bufferGPU); 37420 } else if (binding.isSampledTexture) { 37421 const index = textures++; 37422 state.bindTexture(bindingData.glTextureType, bindingData.textureGPU, gl.TEXTURE0 + index); 37423 } 37424 } 37425 } 37426 } 37427 /** 37428 * The method ensures multisampled render targets are resolved. 37429 * 37430 * @private 37431 * @param {RenderContext} renderContext - The render context. 37432 */ 37433 _resolveRenderTarget(renderContext) { 37434 const { gl, state } = this; 37435 const renderTarget = renderContext.renderTarget; 37436 if (renderContext.textures !== null && renderTarget) { 37437 const renderTargetContextData = this.get(renderTarget); 37438 if (renderTarget.samples > 0 && this._useMultisampledExtension(renderTarget) === false) { 37439 const fb = renderTargetContextData.framebuffers[renderContext.getCacheKey()]; 37440 let mask = gl.COLOR_BUFFER_BIT; 37441 if (renderTarget.resolveDepthBuffer) { 37442 if (renderTarget.depthBuffer) mask |= gl.DEPTH_BUFFER_BIT; 37443 if (renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer) mask |= gl.STENCIL_BUFFER_BIT; 37444 } 37445 const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer; 37446 const msaaRenderbuffers = renderTargetContextData.msaaRenderbuffers; 37447 const textures = renderContext.textures; 37448 const isMRT = textures.length > 1; 37449 state.bindFramebuffer(gl.READ_FRAMEBUFFER, msaaFrameBuffer); 37450 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); 37451 if (isMRT) { 37452 for (let i = 0; i < textures.length; i++) { 37453 gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, null); 37454 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, null, 0); 37455 } 37456 } 37457 for (let i = 0; i < textures.length; i++) { 37458 if (isMRT) { 37459 const { textureGPU } = this.get(textures[i]); 37460 gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaRenderbuffers[i]); 37461 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureGPU, 0); 37462 } 37463 if (renderContext.scissor) { 37464 const { x, y, width, height } = renderContext.scissorValue; 37465 const viewY = renderContext.height - height - y; 37466 gl.blitFramebuffer(x, viewY, x + width, viewY + height, x, viewY, x + width, viewY + height, mask, gl.NEAREST); 37467 } else { 37468 gl.blitFramebuffer(0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, mask, gl.NEAREST); 37469 } 37470 } 37471 if (isMRT) { 37472 for (let i = 0; i < textures.length; i++) { 37473 const { textureGPU } = this.get(textures[i]); 37474 gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, msaaRenderbuffers[i]); 37475 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, textureGPU, 0); 37476 } 37477 } 37478 if (this._supportsInvalidateFramebuffer === true) { 37479 gl.invalidateFramebuffer(gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray); 37480 } 37481 } else if (renderTarget.resolveDepthBuffer === false && renderTargetContextData.framebuffers) { 37482 const fb = renderTargetContextData.framebuffers[renderContext.getCacheKey()]; 37483 state.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); 37484 gl.invalidateFramebuffer(gl.DRAW_FRAMEBUFFER, renderTargetContextData.depthInvalidationArray); 37485 } 37486 } 37487 } 37488 /** 37489 * Returns `true` if the `WEBGL_multisampled_render_to_texture` extension 37490 * should be used when MSAA is enabled. 37491 * 37492 * @private 37493 * @param {RenderTarget} renderTarget - The render target that should be multisampled. 37494 * @return {boolean} Whether to use the `WEBGL_multisampled_render_to_texture` extension for MSAA or not. 37495 */ 37496 _useMultisampledExtension(renderTarget) { 37497 if (renderTarget.multiview === true) { 37498 return true; 37499 } 37500 return renderTarget.samples > 0 && this.extensions.has("WEBGL_multisampled_render_to_texture") === true && renderTarget._autoAllocateDepthBuffer !== false; 37501 } 37502 /** 37503 * Frees internal resources. 37504 */ 37505 dispose() { 37506 if (this.textureUtils !== null) this.textureUtils.dispose(); 37507 const extension = this.extensions.get("WEBGL_lose_context"); 37508 if (extension) extension.loseContext(); 37509 this.renderer.domElement.removeEventListener("webglcontextlost", this._onContextLost); 37510 } 37511}; 37512var GPUPrimitiveTopology = { 37513 PointList: "point-list", 37514 LineList: "line-list", 37515 LineStrip: "line-strip", 37516 TriangleList: "triangle-list" 37517}; 37518var GPUShaderStage = typeof self !== "undefined" && self.GPUShaderStage ? self.GPUShaderStage : { VERTEX: 1, FRAGMENT: 2, COMPUTE: 4 }; 37519var GPUCompareFunction = { 37520 Never: "never", 37521 Less: "less", 37522 Equal: "equal", 37523 LessEqual: "less-equal", 37524 Greater: "greater", 37525 NotEqual: "not-equal", 37526 GreaterEqual: "greater-equal", 37527 Always: "always" 37528}; 37529var GPUStoreOp = { 37530 Store: "store" 37531}; 37532var GPULoadOp = { 37533 Load: "load", 37534 Clear: "clear" 37535}; 37536var GPUFrontFace = { 37537 CCW: "ccw", 37538 CW: "cw" 37539}; 37540var GPUCullMode = { 37541 None: "none", 37542 Back: "back" 37543}; 37544var GPUIndexFormat = { 37545 Uint16: "uint16", 37546 Uint32: "uint32" 37547}; 37548var GPUTextureFormat = { 37549 // 8-bit formats 37550 R8Unorm: "r8unorm", 37551 R8Snorm: "r8snorm", 37552 R8Uint: "r8uint", 37553 R8Sint: "r8sint", 37554 // 16-bit formats 37555 R16Uint: "r16uint", 37556 R16Sint: "r16sint", 37557 R16Float: "r16float", 37558 RG8Unorm: "rg8unorm", 37559 RG8Snorm: "rg8snorm", 37560 RG8Uint: "rg8uint", 37561 RG8Sint: "rg8sint", 37562 R16Unorm: "r16unorm", 37563 R16Snorm: "r16snorm", 37564 // 32-bit formats 37565 R32Uint: "r32uint", 37566 R32Sint: "r32sint", 37567 R32Float: "r32float", 37568 RG16Uint: "rg16uint", 37569 RG16Sint: "rg16sint", 37570 RG16Float: "rg16float", 37571 RGBA8Unorm: "rgba8unorm", 37572 RGBA8UnormSRGB: "rgba8unorm-srgb", 37573 RGBA8Snorm: "rgba8snorm", 37574 RGBA8Uint: "rgba8uint", 37575 RGBA8Sint: "rgba8sint", 37576 BGRA8Unorm: "bgra8unorm", 37577 BGRA8UnormSRGB: "bgra8unorm-srgb", 37578 RG16Unorm: "rg16unorm", 37579 RG16Snorm: "rg16snorm", 37580 // Packed 32-bit formats 37581 RGB9E5UFloat: "rgb9e5ufloat", 37582 RGB10A2Unorm: "rgb10a2unorm", 37583 RG11B10UFloat: "rg11b10ufloat", 37584 // 64-bit formats 37585 RG32Uint: "rg32uint", 37586 RG32Sint: "rg32sint", 37587 RG32Float: "rg32float", 37588 RGBA16Uint: "rgba16uint", 37589 RGBA16Sint: "rgba16sint", 37590 RGBA16Float: "rgba16float", 37591 RGBA16Unorm: "rgba16unorm", 37592 RGBA16Snorm: "rgba16snorm", 37593 // 128-bit formats 37594 RGBA32Uint: "rgba32uint", 37595 RGBA32Sint: "rgba32sint", 37596 RGBA32Float: "rgba32float", 37597 Depth16Unorm: "depth16unorm", 37598 Depth24Plus: "depth24plus", 37599 Depth24PlusStencil8: "depth24plus-stencil8", 37600 Depth32Float: "depth32float", 37601 // 'depth32float-stencil8' extension 37602 Depth32FloatStencil8: "depth32float-stencil8", 37603 // BC compressed formats usable if 'texture-compression-bc' is both 37604 // supported by the device/user agent and enabled in requestDevice. 37605 BC1RGBAUnorm: "bc1-rgba-unorm", 37606 BC1RGBAUnormSRGB: "bc1-rgba-unorm-srgb", 37607 BC2RGBAUnorm: "bc2-rgba-unorm", 37608 BC2RGBAUnormSRGB: "bc2-rgba-unorm-srgb", 37609 BC3RGBAUnorm: "bc3-rgba-unorm", 37610 BC3RGBAUnormSRGB: "bc3-rgba-unorm-srgb", 37611 BC4RUnorm: "bc4-r-unorm", 37612 BC4RSnorm: "bc4-r-snorm", 37613 BC5RGUnorm: "bc5-rg-unorm", 37614 BC5RGSnorm: "bc5-rg-snorm", 37615 BC6HRGBUFloat: "bc6h-rgb-ufloat", 37616 BC6HRGBFloat: "bc6h-rgb-float", 37617 BC7RGBAUnorm: "bc7-rgba-unorm", 37618 BC7RGBAUnormSRGB: "bc7-rgba-unorm-srgb", 37619 // ETC2 compressed formats usable if 'texture-compression-etc2' is both 37620 // supported by the device/user agent and enabled in requestDevice. 37621 ETC2RGB8Unorm: "etc2-rgb8unorm", 37622 ETC2RGB8UnormSRGB: "etc2-rgb8unorm-srgb", 37623 ETC2RGB8A1Unorm: "etc2-rgb8a1unorm", 37624 ETC2RGB8A1UnormSRGB: "etc2-rgb8a1unorm-srgb", 37625 ETC2RGBA8Unorm: "etc2-rgba8unorm", 37626 ETC2RGBA8UnormSRGB: "etc2-rgba8unorm-srgb", 37627 EACR11Unorm: "eac-r11unorm", 37628 EACR11Snorm: "eac-r11snorm", 37629 EACRG11Unorm: "eac-rg11unorm", 37630 EACRG11Snorm: "eac-rg11snorm", 37631 // ASTC compressed formats usable if 'texture-compression-astc' is both 37632 // supported by the device/user agent and enabled in requestDevice. 37633 ASTC4x4Unorm: "astc-4x4-unorm", 37634 ASTC4x4UnormSRGB: "astc-4x4-unorm-srgb", 37635 ASTC5x4Unorm: "astc-5x4-unorm", 37636 ASTC5x4UnormSRGB: "astc-5x4-unorm-srgb", 37637 ASTC5x5Unorm: "astc-5x5-unorm", 37638 ASTC5x5UnormSRGB: "astc-5x5-unorm-srgb", 37639 ASTC6x5Unorm: "astc-6x5-unorm", 37640 ASTC6x5UnormSRGB: "astc-6x5-unorm-srgb", 37641 ASTC6x6Unorm: "astc-6x6-unorm", 37642 ASTC6x6UnormSRGB: "astc-6x6-unorm-srgb", 37643 ASTC8x5Unorm: "astc-8x5-unorm", 37644 ASTC8x5UnormSRGB: "astc-8x5-unorm-srgb", 37645 ASTC8x6Unorm: "astc-8x6-unorm", 37646 ASTC8x6UnormSRGB: "astc-8x6-unorm-srgb", 37647 ASTC8x8Unorm: "astc-8x8-unorm", 37648 ASTC8x8UnormSRGB: "astc-8x8-unorm-srgb", 37649 ASTC10x5Unorm: "astc-10x5-unorm", 37650 ASTC10x5UnormSRGB: "astc-10x5-unorm-srgb", 37651 ASTC10x6Unorm: "astc-10x6-unorm", 37652 ASTC10x6UnormSRGB: "astc-10x6-unorm-srgb", 37653 ASTC10x8Unorm: "astc-10x8-unorm", 37654 ASTC10x8UnormSRGB: "astc-10x8-unorm-srgb", 37655 ASTC10x10Unorm: "astc-10x10-unorm", 37656 ASTC10x10UnormSRGB: "astc-10x10-unorm-srgb", 37657 ASTC12x10Unorm: "astc-12x10-unorm", 37658 ASTC12x10UnormSRGB: "astc-12x10-unorm-srgb", 37659 ASTC12x12Unorm: "astc-12x12-unorm", 37660 ASTC12x12UnormSRGB: "astc-12x12-unorm-srgb" 37661}; 37662var GPUAddressMode = { 37663 ClampToEdge: "clamp-to-edge", 37664 Repeat: "repeat", 37665 MirrorRepeat: "mirror-repeat" 37666}; 37667var GPUFilterMode = { 37668 Linear: "linear", 37669 Nearest: "nearest" 37670}; 37671var GPUBlendFactor = { 37672 Zero: "zero", 37673 One: "one", 37674 Src: "src", 37675 OneMinusSrc: "one-minus-src", 37676 SrcAlpha: "src-alpha", 37677 OneMinusSrcAlpha: "one-minus-src-alpha", 37678 Dst: "dst", 37679 OneMinusDst: "one-minus-dst", 37680 DstAlpha: "dst-alpha", 37681 OneMinusDstAlpha: "one-minus-dst-alpha", 37682 SrcAlphaSaturated: "src-alpha-saturated", 37683 Constant: "constant", 37684 OneMinusConstant: "one-minus-constant" 37685}; 37686var GPUBlendOperation = { 37687 Add: "add", 37688 Subtract: "subtract", 37689 ReverseSubtract: "reverse-subtract", 37690 Min: "min", 37691 Max: "max" 37692}; 37693var GPUColorWriteFlags = { 37694 None: 0, 37695 All: 15 37696}; 37697var GPUStencilOperation = { 37698 Keep: "keep", 37699 Zero: "zero", 37700 Replace: "replace", 37701 Invert: "invert", 37702 IncrementClamp: "increment-clamp", 37703 DecrementClamp: "decrement-clamp", 37704 IncrementWrap: "increment-wrap", 37705 DecrementWrap: "decrement-wrap" 37706}; 37707var GPUBufferBindingType = { 37708 Storage: "storage", 37709 ReadOnlyStorage: "read-only-storage" 37710}; 37711var GPUStorageTextureAccess = { 37712 WriteOnly: "write-only", 37713 ReadOnly: "read-only", 37714 ReadWrite: "read-write" 37715}; 37716var GPUSamplerBindingType = { 37717 NonFiltering: "non-filtering", 37718 Comparison: "comparison" 37719}; 37720var GPUTextureSampleType = { 37721 Float: "float", 37722 UnfilterableFloat: "unfilterable-float", 37723 Depth: "depth", 37724 SInt: "sint", 37725 UInt: "uint" 37726}; 37727var GPUTextureDimension = { 37728 TwoD: "2d", 37729 ThreeD: "3d" 37730}; 37731var GPUTextureViewDimension = { 37732 TwoD: "2d", 37733 TwoDArray: "2d-array", 37734 Cube: "cube", 37735 ThreeD: "3d" 37736}; 37737var GPUTextureAspect = { 37738 All: "all" 37739}; 37740var GPUInputStepMode = { 37741 Vertex: "vertex", 37742 Instance: "instance" 37743}; 37744var GPUFeatureName = { 37745 CoreFeaturesAndLimits: "core-features-and-limits", 37746 DepthClipControl: "depth-clip-control", 37747 Depth32FloatStencil8: "depth32float-stencil8", 37748 TextureCompressionBC: "texture-compression-bc", 37749 TextureCompressionBCSliced3D: "texture-compression-bc-sliced-3d", 37750 TextureCompressionETC2: "texture-compression-etc2", 37751 TextureCompressionASTC: "texture-compression-astc", 37752 TextureCompressionASTCSliced3D: "texture-compression-astc-sliced-3d", 37753 TimestampQuery: "timestamp-query", 37754 IndirectFirstInstance: "indirect-first-instance", 37755 ShaderF16: "shader-f16", 37756 RG11B10UFloat: "rg11b10ufloat-renderable", 37757 BGRA8UNormStorage: "bgra8unorm-storage", 37758 Float32Filterable: "float32-filterable", 37759 Float32Blendable: "float32-blendable", 37760 ClipDistances: "clip-distances", 37761 DualSourceBlending: "dual-source-blending", 37762 Subgroups: "subgroups", 37763 TextureFormatsTier1: "texture-formats-tier1", 37764 TextureFormatsTier2: "texture-formats-tier2" 37765}; 37766var GPUFeatureMap = { 37767 "texture-compression-s3tc": "texture-compression-bc", 37768 "texture-compression-etc1": "texture-compression-etc2" 37769}; 37770var NodeSampler = class extends Sampler { 37771 /** 37772 * Constructs a new node-based sampler. 37773 * 37774 * @param {string} name - The samplers's name. 37775 * @param {TextureNode} textureNode - The texture node. 37776 * @param {UniformGroupNode} groupNode - The uniform group node. 37777 */ 37778 constructor(name, textureNode, groupNode) { 37779 super(name, textureNode ? textureNode.value : null); 37780 this.textureNode = textureNode; 37781 this.groupNode = groupNode; 37782 } 37783 /** 37784 * Updates the texture value of this sampler. 37785 * 37786 * @return {boolean} Whether the sampler needs an update or not. 37787 */ 37788 update() { 37789 const { textureNode } = this; 37790 if (this.texture !== textureNode.value) { 37791 this.texture = textureNode.value; 37792 return true; 37793 } 37794 return super.update(); 37795 } 37796}; 37797var StorageBuffer = class extends Buffer { 37798 /** 37799 * Constructs a new uniform buffer. 37800 * 37801 * @param {string} name - The buffer's name. 37802 * @param {BufferAttribute} attribute - The buffer attribute. 37803 */ 37804 constructor(name, attribute3) { 37805 super(name, attribute3 ? attribute3.array : null); 37806 this._attribute = attribute3; 37807 this.isStorageBuffer = true; 37808 } 37809 /** 37810 * The storage buffer attribute. 37811 * 37812 * @type {BufferAttribute} 37813 */ 37814 get attribute() { 37815 return this._attribute; 37816 } 37817}; 37818var _id = 0; 37819var NodeStorageBuffer = class extends StorageBuffer { 37820 /** 37821 * Constructs a new node-based storage buffer. 37822 * 37823 * @param {StorageBufferNode} nodeUniform - The storage buffer node. 37824 * @param {UniformGroupNode} groupNode - The uniform group node. 37825 */ 37826 constructor(nodeUniform, groupNode) { 37827 super("StorageBuffer_" + _id++, nodeUniform ? nodeUniform.value : null); 37828 this.nodeUniform = nodeUniform; 37829 this.access = nodeUniform ? nodeUniform.access : NodeAccess.READ_WRITE; 37830 this.groupNode = groupNode; 37831 } 37832 /** 37833 * The storage buffer attribute node. 37834 * 37835 * @type {StorageBufferAttribute} 37836 */ 37837 get attribute() { 37838 return this.nodeUniform.value; 37839 } 37840 /** 37841 * The storage buffer. 37842 * 37843 * @type {Float32Array} 37844 */ 37845 get buffer() { 37846 return this.nodeUniform.value.array; 37847 } 37848}; 37849var WebGPUTexturePassUtils = class extends DataMap { 37850 /** 37851 * Constructs a new utility object. 37852 * 37853 * @param {GPUDevice} device - The WebGPU device. 37854 */ 37855 constructor(device) { 37856 super(); 37857 this.device = device; 37858 const mipmapSource = ` 37859struct VarysStruct { 37860 @builtin( position ) Position: vec4f, 37861 @location( 0 ) vTex : vec2f, 37862 @location( 1 ) @interpolate(flat, either) vBaseArrayLayer: u32, 37863}; 37864 37865@group( 0 ) @binding ( 2 ) 37866var<uniform> flipY: u32; 37867 37868@vertex 37869fn mainVS( 37870 @builtin( vertex_index ) vertexIndex : u32, 37871 @builtin( instance_index ) instanceIndex : u32 ) -> VarysStruct { 37872 37873 var Varys : VarysStruct; 37874 37875 var pos = array( 37876 vec2f( -1, -1 ), 37877 vec2f( -1, 3 ), 37878 vec2f( 3, -1 ), 37879 ); 37880 37881 let p = pos[ vertexIndex ]; 37882 let mult = select( vec2f( 0.5, -0.5 ), vec2f( 0.5, 0.5 ), flipY != 0 ); 37883 Varys.vTex = p * mult + vec2f( 0.5 ); 37884 Varys.Position = vec4f( p, 0, 1 ); 37885 Varys.vBaseArrayLayer = instanceIndex; 37886 37887 return Varys; 37888 37889} 37890 37891@group( 0 ) @binding( 0 ) 37892var imgSampler : sampler; 37893 37894@group( 0 ) @binding( 1 ) 37895var img2d : texture_2d<f32>; 37896 37897@fragment 37898fn main_2d( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> { 37899 37900 return textureSample( img2d, imgSampler, Varys.vTex ); 37901 37902} 37903 37904@group( 0 ) @binding( 1 ) 37905var img2dArray : texture_2d_array<f32>; 37906 37907@fragment 37908fn main_2d_array( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> { 37909 37910 return textureSample( img2dArray, imgSampler, Varys.vTex, Varys.vBaseArrayLayer ); 37911 37912} 37913 37914const faceMat = array( 37915 mat3x3f( 0, 0, -2, 0, -2, 0, 1, 1, 1 ), // pos-x 37916 mat3x3f( 0, 0, 2, 0, -2, 0, -1, 1, -1 ), // neg-x 37917 mat3x3f( 2, 0, 0, 0, 0, 2, -1, 1, -1 ), // pos-y 37918 mat3x3f( 2, 0, 0, 0, 0, -2, -1, -1, 1 ), // neg-y 37919 mat3x3f( 2, 0, 0, 0, -2, 0, -1, 1, 1 ), // pos-z 37920 mat3x3f( -2, 0, 0, 0, -2, 0, 1, 1, -1 ), // neg-z 37921); 37922 37923@group( 0 ) @binding( 1 ) 37924var imgCube : texture_cube<f32>; 37925 37926@fragment 37927fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> { 37928 37929 return textureSample( imgCube, imgSampler, faceMat[ Varys.vBaseArrayLayer ] * vec3f( fract( Varys.vTex ), 1 ) ); 37930 37931} 37932`; 37933 this.mipmapSampler = device.createSampler({ minFilter: GPUFilterMode.Linear }); 37934 this.flipYSampler = device.createSampler({ minFilter: GPUFilterMode.Nearest }); 37935 this.flipUniformBuffer = device.createBuffer({ 37936 size: 4, 37937 usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST 37938 }); 37939 device.queue.writeBuffer(this.flipUniformBuffer, 0, new Uint32Array([1])); 37940 this.noFlipUniformBuffer = device.createBuffer({ 37941 size: 4, 37942 usage: GPUBufferUsage.UNIFORM 37943 }); 37944 this.transferPipelines = {}; 37945 this.mipmapShaderModule = device.createShaderModule({ 37946 label: "mipmap", 37947 code: mipmapSource 37948 }); 37949 } 37950 /** 37951 * Returns a render pipeline for the internal copy render pass. The pass 37952 * requires a unique render pipeline for each texture format. 37953 * 37954 * @param {string} format - The GPU texture format 37955 * @param {string?} textureBindingViewDimension - The GPU texture binding view dimension 37956 * @return {GPURenderPipeline} The GPU render pipeline. 37957 */ 37958 getTransferPipeline(format, textureBindingViewDimension) { 37959 textureBindingViewDimension = textureBindingViewDimension || "2d-array"; 37960 const key = `${format}-${textureBindingViewDimension}`; 37961 let pipeline = this.transferPipelines[key]; 37962 if (pipeline === void 0) { 37963 pipeline = this.device.createRenderPipeline({ 37964 label: `mipmap-${format}-${textureBindingViewDimension}`, 37965 vertex: { 37966 module: this.mipmapShaderModule 37967 }, 37968 fragment: { 37969 module: this.mipmapShaderModule, 37970 entryPoint: `main_${textureBindingViewDimension.replace("-", "_")}`, 37971 targets: [{ format }] 37972 }, 37973 layout: "auto" 37974 }); 37975 this.transferPipelines[key] = pipeline; 37976 } 37977 return pipeline; 37978 } 37979 /** 37980 * Flip the contents of the given GPU texture along its vertical axis. 37981 * 37982 * @param {GPUTexture} textureGPU - The GPU texture object. 37983 * @param {Object} textureGPUDescriptor - The texture descriptor. 37984 * @param {number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. 37985 */ 37986 flipY(textureGPU, textureGPUDescriptor, baseArrayLayer = 0) { 37987 const format = textureGPUDescriptor.format; 37988 const { width, height } = textureGPUDescriptor.size; 37989 const tempTexture = this.device.createTexture({ 37990 size: { width, height }, 37991 format, 37992 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING 37993 }); 37994 const copyTransferPipeline = this.getTransferPipeline(format, textureGPU.textureBindingViewDimension); 37995 const flipTransferPipeline = this.getTransferPipeline(format, tempTexture.textureBindingViewDimension); 37996 const commandEncoder = this.device.createCommandEncoder({}); 37997 const pass3 = (pipeline, sourceTexture, sourceArrayLayer, destinationTexture, destinationArrayLayer, flipY) => { 37998 const bindGroupLayout = pipeline.getBindGroupLayout(0); 37999 const bindGroup = this.device.createBindGroup({ 38000 layout: bindGroupLayout, 38001 entries: [{ 38002 binding: 0, 38003 resource: this.flipYSampler 38004 }, { 38005 binding: 1, 38006 resource: sourceTexture.createView({ 38007 dimension: sourceTexture.textureBindingViewDimension || "2d-array", 38008 baseMipLevel: 0, 38009 mipLevelCount: 1 38010 }) 38011 }, { 38012 binding: 2, 38013 resource: { buffer: flipY ? this.flipUniformBuffer : this.noFlipUniformBuffer } 38014 }] 38015 }); 38016 const passEncoder = commandEncoder.beginRenderPass({ 38017 colorAttachments: [{ 38018 view: destinationTexture.createView({ 38019 dimension: "2d", 38020 baseMipLevel: 0, 38021 mipLevelCount: 1, 38022 baseArrayLayer: destinationArrayLayer, 38023 arrayLayerCount: 1 38024 }), 38025 loadOp: GPULoadOp.Clear, 38026 storeOp: GPUStoreOp.Store 38027 }] 38028 }); 38029 passEncoder.setPipeline(pipeline); 38030 passEncoder.setBindGroup(0, bindGroup); 38031 passEncoder.draw(3, 1, 0, sourceArrayLayer); 38032 passEncoder.end(); 38033 }; 38034 pass3(copyTransferPipeline, textureGPU, baseArrayLayer, tempTexture, 0, false); 38035 pass3(flipTransferPipeline, tempTexture, 0, textureGPU, baseArrayLayer, true); 38036 this.device.queue.submit([commandEncoder.finish()]); 38037 tempTexture.destroy(); 38038 } 38039 /** 38040 * Generates mipmaps for the given GPU texture. 38041 * 38042 * @param {GPUTexture} textureGPU - The GPU texture object. 38043 * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. 38044 */ 38045 generateMipmaps(textureGPU, encoder = null) { 38046 const textureData = this.get(textureGPU); 38047 const passes = textureData.layers || this._mipmapCreateBundles(textureGPU); 38048 const commandEncoder = encoder || this.device.createCommandEncoder({ label: "mipmapEncoder" }); 38049 this._mipmapRunBundles(commandEncoder, passes); 38050 if (encoder === null) this.device.queue.submit([commandEncoder.finish()]); 38051 textureData.layers = passes; 38052 } 38053 /** 38054 * Since multiple copy render passes are required to generate mipmaps, the passes 38055 * are managed as render bundles to improve performance. 38056 * 38057 * @param {GPUTexture} textureGPU - The GPU texture object. 38058 * @return {Array<Object>} An array of render bundles. 38059 */ 38060 _mipmapCreateBundles(textureGPU) { 38061 const textureBindingViewDimension = textureGPU.textureBindingViewDimension || "2d-array"; 38062 const pipeline = this.getTransferPipeline(textureGPU.format, textureBindingViewDimension); 38063 const bindGroupLayout = pipeline.getBindGroupLayout(0); 38064 const passes = []; 38065 for (let baseMipLevel = 1; baseMipLevel < textureGPU.mipLevelCount; baseMipLevel++) { 38066 for (let baseArrayLayer = 0; baseArrayLayer < textureGPU.depthOrArrayLayers; baseArrayLayer++) { 38067 const bindGroup = this.device.createBindGroup({ 38068 layout: bindGroupLayout, 38069 entries: [{ 38070 binding: 0, 38071 resource: this.mipmapSampler 38072 }, { 38073 binding: 1, 38074 resource: textureGPU.createView({ 38075 dimension: textureBindingViewDimension, 38076 baseMipLevel: baseMipLevel - 1, 38077 mipLevelCount: 1 38078 }) 38079 }, { 38080 binding: 2, 38081 resource: { buffer: this.noFlipUniformBuffer } 38082 }] 38083 }); 38084 const passDescriptor = { 38085 colorAttachments: [{ 38086 view: textureGPU.createView({ 38087 dimension: "2d", 38088 baseMipLevel, 38089 mipLevelCount: 1, 38090 baseArrayLayer, 38091 arrayLayerCount: 1 38092 }), 38093 loadOp: GPULoadOp.Clear, 38094 storeOp: GPUStoreOp.Store 38095 }] 38096 }; 38097 const passEncoder = this.device.createRenderBundleEncoder({ 38098 colorFormats: [textureGPU.format] 38099 }); 38100 passEncoder.setPipeline(pipeline); 38101 passEncoder.setBindGroup(0, bindGroup); 38102 passEncoder.draw(3, 1, 0, baseArrayLayer); 38103 passes.push({ 38104 renderBundles: [passEncoder.finish()], 38105 passDescriptor 38106 }); 38107 } 38108 } 38109 return passes; 38110 } 38111 /** 38112 * Executes the render bundles. 38113 * 38114 * @param {GPUCommandEncoder} commandEncoder - The GPU command encoder. 38115 * @param {Array<Object>} passes - An array of render bundles. 38116 */ 38117 _mipmapRunBundles(commandEncoder, passes) { 38118 const levels = passes.length; 38119 for (let i = 0; i < levels; i++) { 38120 const pass3 = passes[i]; 38121 const passEncoder = commandEncoder.beginRenderPass(pass3.passDescriptor); 38122 passEncoder.executeBundles(pass3.renderBundles); 38123 passEncoder.end(); 38124 } 38125 } 38126}; 38127var _compareToWebGPU = { 38128 [NeverCompare]: "never", 38129 [LessCompare]: "less", 38130 [EqualCompare]: "equal", 38131 [LessEqualCompare]: "less-equal", 38132 [GreaterCompare]: "greater", 38133 [GreaterEqualCompare]: "greater-equal", 38134 [AlwaysCompare]: "always", 38135 [NotEqualCompare]: "not-equal" 38136}; 38137var _flipMap = [0, 1, 3, 2, 4, 5]; 38138var WebGPUTextureUtils = class { 38139 /** 38140 * Constructs a new utility object. 38141 * 38142 * @param {WebGPUBackend} backend - The WebGPU backend. 38143 */ 38144 constructor(backend) { 38145 this.backend = backend; 38146 this._passUtils = null; 38147 this.defaultTexture = {}; 38148 this.defaultCubeTexture = {}; 38149 this.defaultVideoFrame = null; 38150 this._samplerCache = /* @__PURE__ */ new Map(); 38151 } 38152 /** 38153 * Creates a GPU sampler for the given texture. 38154 * 38155 * @param {Texture} texture - The texture to create the sampler for. 38156 * @return {string} The current sampler key. 38157 */ 38158 updateSampler(texture3) { 38159 const backend = this.backend; 38160 const samplerKey = texture3.minFilter + "-" + texture3.magFilter + "-" + texture3.wrapS + "-" + texture3.wrapT + "-" + (texture3.wrapR || "0") + "-" + texture3.anisotropy + "-" + (texture3.compareFunction || 0); 38161 let samplerData = this._samplerCache.get(samplerKey); 38162 if (samplerData === void 0) { 38163 const samplerDescriptorGPU = { 38164 addressModeU: this._convertAddressMode(texture3.wrapS), 38165 addressModeV: this._convertAddressMode(texture3.wrapT), 38166 addressModeW: this._convertAddressMode(texture3.wrapR), 38167 magFilter: this._convertFilterMode(texture3.magFilter), 38168 minFilter: this._convertFilterMode(texture3.minFilter), 38169 mipmapFilter: this._convertFilterMode(texture3.minFilter), 38170 maxAnisotropy: 1 38171 }; 38172 if (texture3.isDepthTexture && texture3.compareFunction === null) { 38173 samplerDescriptorGPU.magFilter = GPUFilterMode.Nearest; 38174 samplerDescriptorGPU.minFilter = GPUFilterMode.Nearest; 38175 samplerDescriptorGPU.mipmapFilter = GPUFilterMode.Nearest; 38176 } 38177 if (samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear) { 38178 samplerDescriptorGPU.maxAnisotropy = texture3.anisotropy; 38179 } 38180 if (texture3.isDepthTexture && texture3.compareFunction !== null && backend.hasCompatibility(Compatibility.TEXTURE_COMPARE)) { 38181 samplerDescriptorGPU.compare = _compareToWebGPU[texture3.compareFunction]; 38182 } 38183 const sampler3 = backend.device.createSampler(samplerDescriptorGPU); 38184 samplerData = { sampler: sampler3, usedTimes: 0 }; 38185 this._samplerCache.set(samplerKey, samplerData); 38186 } 38187 const textureData = backend.get(texture3); 38188 if (textureData.sampler !== samplerData.sampler) { 38189 if (textureData.sampler !== void 0) { 38190 const oldSamplerData = this._samplerCache.get(textureData.samplerKey); 38191 oldSamplerData.usedTimes--; 38192 if (oldSamplerData.usedTimes === 0) { 38193 this._samplerCache.delete(textureData.samplerKey); 38194 } 38195 } 38196 textureData.samplerKey = samplerKey; 38197 textureData.sampler = samplerData.sampler; 38198 samplerData.usedTimes++; 38199 } 38200 return samplerKey; 38201 } 38202 /** 38203 * Creates a default texture for the given texture that can be used 38204 * as a placeholder until the actual texture is ready for usage. 38205 * 38206 * @param {Texture} texture - The texture to create a default texture for. 38207 */ 38208 createDefaultTexture(texture3) { 38209 let textureGPU; 38210 const format = getFormat(texture3, this.backend.device); 38211 if (texture3.isCubeTexture) { 38212 textureGPU = this._getDefaultCubeTextureGPU(format); 38213 } else { 38214 textureGPU = this._getDefaultTextureGPU(format); 38215 } 38216 this.backend.get(texture3).texture = textureGPU; 38217 } 38218 /** 38219 * Defines a texture on the GPU for the given texture object. 38220 * 38221 * @param {Texture} texture - The texture. 38222 * @param {Object} [options={}] - Optional configuration parameter. 38223 */ 38224 createTexture(texture3, options = {}) { 38225 const backend = this.backend; 38226 const textureData = backend.get(texture3); 38227 if (textureData.initialized) { 38228 throw new Error("WebGPUTextureUtils: Texture already initialized."); 38229 } 38230 if (texture3.isExternalTexture) { 38231 textureData.texture = texture3.sourceTexture; 38232 textureData.initialized = true; 38233 return; 38234 } 38235 if (options.needsMipmaps === void 0) options.needsMipmaps = false; 38236 if (options.levels === void 0) options.levels = 1; 38237 if (options.depth === void 0) options.depth = 1; 38238 const { width, height, depth: depth3, levels } = options; 38239 if (texture3.isFramebufferTexture) { 38240 if (options.renderTarget) { 38241 options.format = this.backend.utils.getCurrentColorFormat(options.renderTarget); 38242 } else { 38243 options.format = this.backend.utils.getPreferredCanvasFormat(); 38244 } 38245 } 38246 const dimension = this._getDimension(texture3); 38247 const format = texture3.internalFormat || options.format || getFormat(texture3, backend.device); 38248 textureData.format = format; 38249 const { samples, primarySamples, isMSAA } = backend.utils.getTextureSampleData(texture3); 38250 let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; 38251 if (texture3.isStorageTexture === true) { 38252 usage |= GPUTextureUsage.STORAGE_BINDING; 38253 } 38254 if (texture3.isCompressedTexture !== true && texture3.isCompressedArrayTexture !== true && format !== GPUTextureFormat.RGB9E5UFloat) { 38255 usage |= GPUTextureUsage.RENDER_ATTACHMENT; 38256 } 38257 const textureDescriptorGPU = { 38258 label: texture3.name, 38259 size: { 38260 width, 38261 height, 38262 depthOrArrayLayers: depth3 38263 }, 38264 mipLevelCount: levels, 38265 sampleCount: primarySamples, 38266 dimension, 38267 format, 38268 usage 38269 }; 38270 if (format === void 0) { 38271 warn("WebGPURenderer: Texture format not supported."); 38272 this.createDefaultTexture(texture3); 38273 return; 38274 } 38275 if (texture3.isCubeTexture) { 38276 textureDescriptorGPU.textureBindingViewDimension = GPUTextureViewDimension.Cube; 38277 } 38278 try { 38279 textureData.texture = backend.device.createTexture(textureDescriptorGPU); 38280 } catch (e) { 38281 warn("WebGPURenderer: Failed to create texture with descriptor:", textureDescriptorGPU); 38282 this.createDefaultTexture(texture3); 38283 return; 38284 } 38285 if (isMSAA) { 38286 const msaaTextureDescriptorGPU = Object.assign({}, textureDescriptorGPU); 38287 msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + "-msaa"; 38288 msaaTextureDescriptorGPU.sampleCount = samples; 38289 msaaTextureDescriptorGPU.mipLevelCount = 1; 38290 textureData.msaaTexture = backend.device.createTexture(msaaTextureDescriptorGPU); 38291 } 38292 textureData.initialized = true; 38293 textureData.textureDescriptorGPU = textureDescriptorGPU; 38294 } 38295 /** 38296 * Destroys the GPU data for the given texture object. 38297 * 38298 * @param {Texture} texture - The texture. 38299 * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. 38300 */ 38301 destroyTexture(texture3, isDefaultTexture = false) { 38302 const backend = this.backend; 38303 const textureData = backend.get(texture3); 38304 if (textureData.texture !== void 0 && isDefaultTexture === false) textureData.texture.destroy(); 38305 if (textureData.msaaTexture !== void 0) textureData.msaaTexture.destroy(); 38306 backend.delete(texture3); 38307 } 38308 /** 38309 * Generates mipmaps for the given texture. 38310 * 38311 * @param {Texture} texture - The texture. 38312 * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. 38313 */ 38314 generateMipmaps(texture3, encoder = null) { 38315 const textureData = this.backend.get(texture3); 38316 this._generateMipmaps(textureData.texture, encoder); 38317 } 38318 /** 38319 * Returns the color buffer representing the color 38320 * attachment of the default framebuffer. 38321 * 38322 * @return {GPUTexture} The color buffer. 38323 */ 38324 getColorBuffer() { 38325 const backend = this.backend; 38326 const canvasTarget = backend.renderer.getCanvasTarget(); 38327 const { width, height } = backend.getDrawingBufferSize(); 38328 const samples = backend.renderer.currentSamples; 38329 const colorTexture = canvasTarget.colorTexture; 38330 const colorTextureData = backend.get(colorTexture); 38331 if (colorTexture.width === width && colorTexture.height === height && colorTexture.samples === samples) { 38332 return colorTextureData.texture; 38333 } 38334 let colorBuffer = colorTextureData.texture; 38335 if (colorBuffer) colorBuffer.destroy(); 38336 colorBuffer = backend.device.createTexture({ 38337 label: "colorBuffer", 38338 size: { 38339 width, 38340 height, 38341 depthOrArrayLayers: 1 38342 }, 38343 sampleCount: backend.utils.getSampleCount(backend.renderer.currentSamples), 38344 format: backend.utils.getPreferredCanvasFormat(), 38345 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC 38346 }); 38347 colorTexture.source.width = width; 38348 colorTexture.source.height = height; 38349 colorTexture.samples = samples; 38350 colorTextureData.texture = colorBuffer; 38351 return colorBuffer; 38352 } 38353 /** 38354 * Returns the depth buffer representing the depth 38355 * attachment of the default framebuffer. 38356 * 38357 * @param {boolean} [depth=true] - Whether depth is enabled or not. 38358 * @param {boolean} [stencil=false] - Whether stencil is enabled or not. 38359 * @return {GPUTexture} The depth buffer. 38360 */ 38361 getDepthBuffer(depth3 = true, stencil = false) { 38362 const backend = this.backend; 38363 const canvasTarget = backend.renderer.getCanvasTarget(); 38364 const { width, height } = backend.getDrawingBufferSize(); 38365 const samples = backend.renderer.currentSamples; 38366 const depthTexture = canvasTarget.depthTexture; 38367 if (depthTexture.width === width && depthTexture.height === height && depthTexture.samples === samples && depthTexture.depth === depth3 && depthTexture.stencil === stencil) { 38368 return backend.get(depthTexture).texture; 38369 } 38370 const depthTextureGPU = backend.get(depthTexture).texture; 38371 let format, type; 38372 if (stencil) { 38373 format = DepthStencilFormat; 38374 type = backend.renderer.reversedDepthBuffer === true ? FloatType : UnsignedInt248Type; 38375 } else if (depth3) { 38376 format = DepthFormat; 38377 type = backend.renderer.reversedDepthBuffer === true ? FloatType : UnsignedIntType; 38378 } 38379 if (depthTextureGPU !== void 0) { 38380 if (depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type && depthTexture.samples === samples) { 38381 return depthTextureGPU; 38382 } 38383 this.destroyTexture(depthTexture); 38384 } 38385 depthTexture.name = "depthBuffer"; 38386 depthTexture.format = format; 38387 depthTexture.type = type; 38388 depthTexture.image.width = width; 38389 depthTexture.image.height = height; 38390 depthTexture.samples = samples; 38391 this.createTexture(depthTexture, { width, height }); 38392 return backend.get(depthTexture).texture; 38393 } 38394 /** 38395 * Uploads the updated texture data to the GPU. 38396 * 38397 * @param {Texture} texture - The texture. 38398 * @param {Object} [options={}] - Optional configuration parameter. 38399 */ 38400 updateTexture(texture3, options) { 38401 const textureData = this.backend.get(texture3); 38402 const mipmaps = texture3.mipmaps; 38403 const { textureDescriptorGPU } = textureData; 38404 if (texture3.isRenderTargetTexture || textureDescriptorGPU === void 0) 38405 return; 38406 if (texture3.isDataTexture) { 38407 if (mipmaps.length > 0) { 38408 for (let i = 0, il = mipmaps.length; i < il; i++) { 38409 const mipmap = mipmaps[i]; 38410 this._copyBufferToTexture(mipmap, textureData.texture, textureDescriptorGPU, 0, texture3.flipY, 0, i); 38411 } 38412 } else { 38413 this._copyBufferToTexture(options.image, textureData.texture, textureDescriptorGPU, 0, texture3.flipY); 38414 } 38415 } else if (texture3.isArrayTexture || texture3.isDataArrayTexture || texture3.isData3DTexture) { 38416 if (texture3.layerUpdates && texture3.layerUpdates.size > 0) { 38417 for (const layerIndex of texture3.layerUpdates) { 38418 this._copyBufferToTexture(options.image, textureData.texture, textureDescriptorGPU, layerIndex, texture3.flipY, layerIndex); 38419 } 38420 texture3.clearLayerUpdates(); 38421 } else { 38422 for (let i = 0; i < options.image.depth; i++) { 38423 this._copyBufferToTexture(options.image, textureData.texture, textureDescriptorGPU, i, texture3.flipY, i); 38424 } 38425 } 38426 } else if (texture3.isCompressedTexture || texture3.isCompressedArrayTexture) { 38427 this._copyCompressedBufferToTexture(texture3.mipmaps, textureData.texture, textureDescriptorGPU); 38428 } else if (texture3.isCubeTexture) { 38429 this._copyCubeMapToTexture(texture3, textureData.texture, textureDescriptorGPU); 38430 } else if (texture3.isHTMLTexture) { 38431 const device = this.backend.device; 38432 const canvas = this.backend.renderer.domElement; 38433 const image = texture3.image; 38434 if (typeof device.queue.copyElementImageToTexture !== "function") return; 38435 if (!textureData.hasPaintCallback) { 38436 textureData.hasPaintCallback = true; 38437 canvas.requestPaint(); 38438 return; 38439 } 38440 const width = textureDescriptorGPU.size.width; 38441 const height = textureDescriptorGPU.size.height; 38442 device.queue.copyElementImageToTexture( 38443 image, 38444 width, 38445 height, 38446 { texture: textureData.texture } 38447 ); 38448 if (texture3.flipY) { 38449 this._flipY(textureData.texture, textureDescriptorGPU); 38450 } 38451 } else { 38452 if (mipmaps.length > 0) { 38453 for (let i = 0, il = mipmaps.length; i < il; i++) { 38454 const mipmap = mipmaps[i]; 38455 this._copyImageToTexture(mipmap, textureData.texture, textureDescriptorGPU, 0, texture3.flipY, texture3.premultiplyAlpha, i); 38456 } 38457 } else { 38458 this._copyImageToTexture(options.image, textureData.texture, textureDescriptorGPU, 0, texture3.flipY, texture3.premultiplyAlpha); 38459 } 38460 } 38461 textureData.version = texture3.version; 38462 } 38463 /** 38464 * Returns texture data as a typed array. 38465 * 38466 * @async 38467 * @param {Texture} texture - The texture to copy. 38468 * @param {number} x - The x coordinate of the copy origin. 38469 * @param {number} y - The y coordinate of the copy origin. 38470 * @param {number} width - The width of the copy. 38471 * @param {number} height - The height of the copy. 38472 * @param {number} faceIndex - The face index. 38473 * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished. 38474 */ 38475 async copyTextureToBuffer(texture3, x, y, width, height, faceIndex) { 38476 const device = this.backend.device; 38477 const textureData = this.backend.get(texture3); 38478 const textureGPU = textureData.texture; 38479 const format = textureData.textureDescriptorGPU.format; 38480 const bytesPerTexel = this._getBytesPerTexel(format); 38481 let bytesPerRow = width * bytesPerTexel; 38482 bytesPerRow = Math.ceil(bytesPerRow / 256) * 256; 38483 const readBuffer = device.createBuffer( 38484 { 38485 size: (height - 1) * bytesPerRow + width * bytesPerTexel, 38486 // see https://github.com/mrdoob/three.js/issues/31658#issuecomment-3229442010 38487 usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 38488 } 38489 ); 38490 const encoder = device.createCommandEncoder(); 38491 encoder.copyTextureToBuffer( 38492 { 38493 texture: textureGPU, 38494 origin: { x, y, z: faceIndex } 38495 }, 38496 { 38497 buffer: readBuffer, 38498 bytesPerRow 38499 }, 38500 { 38501 width, 38502 height 38503 } 38504 ); 38505 const typedArrayType = this._getTypedArrayType(format); 38506 device.queue.submit([encoder.finish()]); 38507 await readBuffer.mapAsync(GPUMapMode.READ); 38508 const buffer3 = readBuffer.getMappedRange().slice(); 38509 readBuffer.destroy(); 38510 return new typedArrayType(buffer3); 38511 } 38512 /** 38513 * Frees all internal resources. 38514 */ 38515 dispose() { 38516 this._samplerCache.clear(); 38517 } 38518 /** 38519 * Returns the default GPU texture for the given format. 38520 * 38521 * @private 38522 * @param {string} format - The GPU format. 38523 * @return {GPUTexture} The GPU texture. 38524 */ 38525 _getDefaultTextureGPU(format) { 38526 let defaultTexture = this.defaultTexture[format]; 38527 if (defaultTexture === void 0) { 38528 const texture3 = new Texture(); 38529 texture3.minFilter = NearestFilter; 38530 texture3.magFilter = NearestFilter; 38531 this.createTexture(texture3, { width: 1, height: 1, format }); 38532 this.defaultTexture[format] = defaultTexture = texture3; 38533 } 38534 return this.backend.get(defaultTexture).texture; 38535 } 38536 /** 38537 * Returns the default GPU cube texture for the given format. 38538 * 38539 * @private 38540 * @param {string} format - The GPU format. 38541 * @return {GPUTexture} The GPU texture. 38542 */ 38543 _getDefaultCubeTextureGPU(format) { 38544 let defaultCubeTexture = this.defaultCubeTexture[format]; 38545 if (defaultCubeTexture === void 0) { 38546 const texture3 = new CubeTexture(); 38547 texture3.minFilter = NearestFilter; 38548 texture3.magFilter = NearestFilter; 38549 this.createTexture(texture3, { width: 1, height: 1, depth: 6 }); 38550 this.defaultCubeTexture[format] = defaultCubeTexture = texture3; 38551 } 38552 return this.backend.get(defaultCubeTexture).texture; 38553 } 38554 /** 38555 * Uploads cube texture image data to the GPU memory. 38556 * 38557 * @private 38558 * @param {CubeTexture} texture - The cube texture. 38559 * @param {GPUTexture} textureGPU - The GPU texture. 38560 * @param {Object} textureDescriptorGPU - The GPU texture descriptor. 38561 */ 38562 _copyCubeMapToTexture(texture3, textureGPU, textureDescriptorGPU) { 38563 const images = texture3.images; 38564 const mipmaps = texture3.mipmaps; 38565 for (let i = 0; i < 6; i++) { 38566 const image = images[i]; 38567 const flipIndex = texture3.flipY === true ? _flipMap[i] : i; 38568 if (image.isDataTexture) { 38569 this._copyBufferToTexture(image.image, textureGPU, textureDescriptorGPU, flipIndex, texture3.flipY); 38570 } else { 38571 this._copyImageToTexture(image, textureGPU, textureDescriptorGPU, flipIndex, texture3.flipY, texture3.premultiplyAlpha); 38572 } 38573 for (let j = 0; j < mipmaps.length; j++) { 38574 const mipmap = mipmaps[j]; 38575 const image2 = mipmap.images[i]; 38576 if (image2.isDataTexture) { 38577 this._copyBufferToTexture(image2.image, textureGPU, textureDescriptorGPU, flipIndex, texture3.flipY, 0, j + 1); 38578 } else { 38579 this._copyImageToTexture(image2, textureGPU, textureDescriptorGPU, flipIndex, texture3.flipY, texture3.premultiplyAlpha, j + 1); 38580 } 38581 } 38582 } 38583 } 38584 /** 38585 * Uploads texture image data to the GPU memory. 38586 * 38587 * @private 38588 * @param {HTMLImageElement|ImageBitmap|HTMLCanvasElement} image - The image data. 38589 * @param {GPUTexture} textureGPU - The GPU texture. 38590 * @param {Object} textureDescriptorGPU - The GPU texture descriptor. 38591 * @param {number} originDepth - The origin depth. 38592 * @param {boolean} flipY - Whether to flip texture data along their vertical axis or not. 38593 * @param {boolean} premultiplyAlpha - Whether the texture should have its RGB channels premultiplied by the alpha channel or not. 38594 * @param {number} [mipLevel=0] - The mip level where the data should be copied to. 38595 */ 38596 _copyImageToTexture(image, textureGPU, textureDescriptorGPU, originDepth, flipY, premultiplyAlpha3, mipLevel = 0) { 38597 const device = this.backend.device; 38598 const width = mipLevel > 0 ? image.width : textureDescriptorGPU.size.width; 38599 const height = mipLevel > 0 ? image.height : textureDescriptorGPU.size.height; 38600 try { 38601 device.queue.copyExternalImageToTexture( 38602 { 38603 source: image, 38604 flipY 38605 }, 38606 { 38607 texture: textureGPU, 38608 mipLevel, 38609 origin: { x: 0, y: 0, z: originDepth }, 38610 premultipliedAlpha: premultiplyAlpha3 38611 }, 38612 { 38613 width, 38614 height, 38615 depthOrArrayLayers: 1 38616 } 38617 ); 38618 } catch (_) { 38619 } 38620 } 38621 /** 38622 * Returns the pass utils singleton. 38623 * 38624 * @private 38625 * @return {WebGPUTexturePassUtils} The utils instance. 38626 */ 38627 _getPassUtils() { 38628 let passUtils = this._passUtils; 38629 if (passUtils === null) { 38630 this._passUtils = passUtils = new WebGPUTexturePassUtils(this.backend.device); 38631 } 38632 return passUtils; 38633 } 38634 /** 38635 * Generates mipmaps for the given GPU texture. 38636 * 38637 * @private 38638 * @param {GPUTexture} textureGPU - The GPU texture object. 38639 * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. 38640 */ 38641 _generateMipmaps(textureGPU, encoder = null) { 38642 this._getPassUtils().generateMipmaps(textureGPU, encoder); 38643 } 38644 /** 38645 * Flip the contents of the given GPU texture along its vertical axis. 38646 * 38647 * @private 38648 * @param {GPUTexture} textureGPU - The GPU texture object. 38649 * @param {Object} textureDescriptorGPU - The texture descriptor. 38650 * @param {number} [originDepth=0] - The origin depth. 38651 */ 38652 _flipY(textureGPU, textureDescriptorGPU, originDepth = 0) { 38653 this._getPassUtils().flipY(textureGPU, textureDescriptorGPU, originDepth); 38654 } 38655 /** 38656 * Uploads texture buffer data to the GPU memory. 38657 * 38658 * @private 38659 * @param {Object} image - An object defining the image buffer data. 38660 * @param {GPUTexture} textureGPU - The GPU texture. 38661 * @param {Object} textureDescriptorGPU - The GPU texture descriptor. 38662 * @param {number} originDepth - The origin depth. 38663 * @param {boolean} flipY - Whether to flip texture data along their vertical axis or not. 38664 * @param {number} [depth=0] - The depth offset when copying array or 3D texture data. 38665 * @param {number} [mipLevel=0] - The mip level where the data should be copied to. 38666 */ 38667 _copyBufferToTexture(image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth3 = 0, mipLevel = 0) { 38668 const device = this.backend.device; 38669 const data = image.data; 38670 const bytesPerTexel = this._getBytesPerTexel(textureDescriptorGPU.format); 38671 const bytesPerRow = image.width * bytesPerTexel; 38672 device.queue.writeTexture( 38673 { 38674 texture: textureGPU, 38675 mipLevel, 38676 origin: { x: 0, y: 0, z: originDepth } 38677 }, 38678 data, 38679 { 38680 offset: image.width * image.height * bytesPerTexel * depth3, 38681 bytesPerRow 38682 }, 38683 { 38684 width: image.width, 38685 height: image.height, 38686 depthOrArrayLayers: 1 38687 } 38688 ); 38689 if (flipY === true) { 38690 this._flipY(textureGPU, textureDescriptorGPU, originDepth); 38691 } 38692 } 38693 /** 38694 * Uploads compressed texture data to the GPU memory. 38695 * 38696 * @private 38697 * @param {Array<Object>} mipmaps - An array with mipmap data. 38698 * @param {GPUTexture} textureGPU - The GPU texture. 38699 * @param {Object} textureDescriptorGPU - The GPU texture descriptor. 38700 */ 38701 _copyCompressedBufferToTexture(mipmaps, textureGPU, textureDescriptorGPU) { 38702 const device = this.backend.device; 38703 const blockData = this._getBlockData(textureDescriptorGPU.format); 38704 const isArrayTexture = textureDescriptorGPU.size.depthOrArrayLayers > 1; 38705 for (let i = 0; i < mipmaps.length; i++) { 38706 const mipmap = mipmaps[i]; 38707 const width = mipmap.width; 38708 const height = mipmap.height; 38709 const depth3 = isArrayTexture ? textureDescriptorGPU.size.depthOrArrayLayers : 1; 38710 const bytesPerRow = Math.ceil(width / blockData.width) * blockData.byteLength; 38711 const bytesPerImage = bytesPerRow * Math.ceil(height / blockData.height); 38712 for (let j = 0; j < depth3; j++) { 38713 device.queue.writeTexture( 38714 { 38715 texture: textureGPU, 38716 mipLevel: i, 38717 origin: { x: 0, y: 0, z: j } 38718 }, 38719 mipmap.data, 38720 { 38721 offset: j * bytesPerImage, 38722 bytesPerRow, 38723 rowsPerImage: Math.ceil(height / blockData.height) 38724 }, 38725 { 38726 width: Math.ceil(width / blockData.width) * blockData.width, 38727 height: Math.ceil(height / blockData.height) * blockData.height, 38728 depthOrArrayLayers: 1 38729 } 38730 ); 38731 } 38732 } 38733 } 38734 /** 38735 * This method is only relevant for compressed texture formats. It returns a block 38736 * data descriptor for the given GPU compressed texture format. 38737 * 38738 * @private 38739 * @param {string} format - The GPU compressed texture format. 38740 * @return {Object} The block data descriptor. 38741 */ 38742 _getBlockData(format) { 38743 if (format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB) return { byteLength: 8, width: 4, height: 4 }; 38744 if (format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB) return { byteLength: 16, width: 4, height: 4 }; 38745 if (format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB) return { byteLength: 16, width: 4, height: 4 }; 38746 if (format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSnorm) return { byteLength: 8, width: 4, height: 4 }; 38747 if (format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm) return { byteLength: 16, width: 4, height: 4 }; 38748 if (format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat) return { byteLength: 16, width: 4, height: 4 }; 38749 if (format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB) return { byteLength: 16, width: 4, height: 4 }; 38750 if (format === GPUTextureFormat.ETC2RGB8Unorm || format === GPUTextureFormat.ETC2RGB8UnormSRGB) return { byteLength: 8, width: 4, height: 4 }; 38751 if (format === GPUTextureFormat.ETC2RGB8A1Unorm || format === GPUTextureFormat.ETC2RGB8A1UnormSRGB) return { byteLength: 8, width: 4, height: 4 }; 38752 if (format === GPUTextureFormat.ETC2RGBA8Unorm || format === GPUTextureFormat.ETC2RGBA8UnormSRGB) return { byteLength: 16, width: 4, height: 4 }; 38753 if (format === GPUTextureFormat.EACR11Unorm) return { byteLength: 8, width: 4, height: 4 }; 38754 if (format === GPUTextureFormat.EACR11Snorm) return { byteLength: 8, width: 4, height: 4 }; 38755 if (format === GPUTextureFormat.EACRG11Unorm) return { byteLength: 16, width: 4, height: 4 }; 38756 if (format === GPUTextureFormat.EACRG11Snorm) return { byteLength: 16, width: 4, height: 4 }; 38757 if (format === GPUTextureFormat.ASTC4x4Unorm || format === GPUTextureFormat.ASTC4x4UnormSRGB) return { byteLength: 16, width: 4, height: 4 }; 38758 if (format === GPUTextureFormat.ASTC5x4Unorm || format === GPUTextureFormat.ASTC5x4UnormSRGB) return { byteLength: 16, width: 5, height: 4 }; 38759 if (format === GPUTextureFormat.ASTC5x5Unorm || format === GPUTextureFormat.ASTC5x5UnormSRGB) return { byteLength: 16, width: 5, height: 5 }; 38760 if (format === GPUTextureFormat.ASTC6x5Unorm || format === GPUTextureFormat.ASTC6x5UnormSRGB) return { byteLength: 16, width: 6, height: 5 }; 38761 if (format === GPUTextureFormat.ASTC6x6Unorm || format === GPUTextureFormat.ASTC6x6UnormSRGB) return { byteLength: 16, width: 6, height: 6 }; 38762 if (format === GPUTextureFormat.ASTC8x5Unorm || format === GPUTextureFormat.ASTC8x5UnormSRGB) return { byteLength: 16, width: 8, height: 5 }; 38763 if (format === GPUTextureFormat.ASTC8x6Unorm || format === GPUTextureFormat.ASTC8x6UnormSRGB) return { byteLength: 16, width: 8, height: 6 }; 38764 if (format === GPUTextureFormat.ASTC8x8Unorm || format === GPUTextureFormat.ASTC8x8UnormSRGB) return { byteLength: 16, width: 8, height: 8 }; 38765 if (format === GPUTextureFormat.ASTC10x5Unorm || format === GPUTextureFormat.ASTC10x5UnormSRGB) return { byteLength: 16, width: 10, height: 5 }; 38766 if (format === GPUTextureFormat.ASTC10x6Unorm || format === GPUTextureFormat.ASTC10x6UnormSRGB) return { byteLength: 16, width: 10, height: 6 }; 38767 if (format === GPUTextureFormat.ASTC10x8Unorm || format === GPUTextureFormat.ASTC10x8UnormSRGB) return { byteLength: 16, width: 10, height: 8 }; 38768 if (format === GPUTextureFormat.ASTC10x10Unorm || format === GPUTextureFormat.ASTC10x10UnormSRGB) return { byteLength: 16, width: 10, height: 10 }; 38769 if (format === GPUTextureFormat.ASTC12x10Unorm || format === GPUTextureFormat.ASTC12x10UnormSRGB) return { byteLength: 16, width: 12, height: 10 }; 38770 if (format === GPUTextureFormat.ASTC12x12Unorm || format === GPUTextureFormat.ASTC12x12UnormSRGB) return { byteLength: 16, width: 12, height: 12 }; 38771 } 38772 /** 38773 * Converts the three.js uv wrapping constants to GPU address mode constants. 38774 * 38775 * @private 38776 * @param {number} value - The three.js constant defining a uv wrapping mode. 38777 * @return {string} The GPU address mode. 38778 */ 38779 _convertAddressMode(value) { 38780 let addressMode = GPUAddressMode.ClampToEdge; 38781 if (value === RepeatWrapping) { 38782 addressMode = GPUAddressMode.Repeat; 38783 } else if (value === MirroredRepeatWrapping) { 38784 addressMode = GPUAddressMode.MirrorRepeat; 38785 } 38786 return addressMode; 38787 } 38788 /** 38789 * Converts the three.js filter constants to GPU filter constants. 38790 * 38791 * @private 38792 * @param {number} value - The three.js constant defining a filter mode. 38793 * @return {string} The GPU filter mode. 38794 */ 38795 _convertFilterMode(value) { 38796 let filterMode = GPUFilterMode.Linear; 38797 if (value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter) { 38798 filterMode = GPUFilterMode.Nearest; 38799 } 38800 return filterMode; 38801 } 38802 /** 38803 * Returns the bytes-per-texel value for the given GPU texture format. 38804 * 38805 * @private 38806 * @param {string} format - The GPU texture format. 38807 * @return {number} The bytes-per-texel. 38808 */ 38809 _getBytesPerTexel(format) { 38810 if (format === GPUTextureFormat.R8Unorm || format === GPUTextureFormat.R8Snorm || format === GPUTextureFormat.R8Uint || format === GPUTextureFormat.R8Sint) return 1; 38811 if (format === GPUTextureFormat.R16Uint || format === GPUTextureFormat.R16Sint || format === GPUTextureFormat.R16Float || format === GPUTextureFormat.RG8Unorm || format === GPUTextureFormat.RG8Snorm || format === GPUTextureFormat.RG8Uint || format === GPUTextureFormat.RG8Sint || format === GPUTextureFormat.R16Unorm || format === GPUTextureFormat.R16Snorm) return 2; 38812 if (format === GPUTextureFormat.R32Uint || format === GPUTextureFormat.R32Sint || format === GPUTextureFormat.R32Float || format === GPUTextureFormat.RG16Uint || format === GPUTextureFormat.RG16Sint || format === GPUTextureFormat.RG16Float || format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB || format === GPUTextureFormat.RGBA8Snorm || format === GPUTextureFormat.RGBA8Uint || format === GPUTextureFormat.RGBA8Sint || format === GPUTextureFormat.BGRA8Unorm || format === GPUTextureFormat.BGRA8UnormSRGB || format === GPUTextureFormat.RG16Unorm || format === GPUTextureFormat.RG16Snorm || // Packed 32-bit formats 38813 format === GPUTextureFormat.RGB9E5UFloat || format === GPUTextureFormat.RGB10A2Unorm || format === GPUTextureFormat.RG11B10UFloat || format === GPUTextureFormat.Depth32Float || format === GPUTextureFormat.Depth24Plus || format === GPUTextureFormat.Depth24PlusStencil8 || format === GPUTextureFormat.Depth32FloatStencil8) return 4; 38814 if (format === GPUTextureFormat.RG32Uint || format === GPUTextureFormat.RG32Sint || format === GPUTextureFormat.RG32Float || format === GPUTextureFormat.RGBA16Uint || format === GPUTextureFormat.RGBA16Sint || format === GPUTextureFormat.RGBA16Float || format === GPUTextureFormat.RGBA16Unorm || format === GPUTextureFormat.RGBA16Snorm) return 8; 38815 if (format === GPUTextureFormat.RGBA32Uint || format === GPUTextureFormat.RGBA32Sint || format === GPUTextureFormat.RGBA32Float) return 16; 38816 } 38817 /** 38818 * Returns the corresponding typed array type for the given GPU texture format. 38819 * 38820 * @private 38821 * @param {string} format - The GPU texture format. 38822 * @return {TypedArray.constructor} The typed array type. 38823 */ 38824 _getTypedArrayType(format) { 38825 if (format === GPUTextureFormat.R8Uint) return Uint8Array; 38826 if (format === GPUTextureFormat.R8Sint) return Int8Array; 38827 if (format === GPUTextureFormat.R8Unorm) return Uint8Array; 38828 if (format === GPUTextureFormat.R8Snorm) return Int8Array; 38829 if (format === GPUTextureFormat.RG8Uint) return Uint8Array; 38830 if (format === GPUTextureFormat.RG8Sint) return Int8Array; 38831 if (format === GPUTextureFormat.RG8Unorm) return Uint8Array; 38832 if (format === GPUTextureFormat.RG8Snorm) return Int8Array; 38833 if (format === GPUTextureFormat.RGBA8Uint) return Uint8Array; 38834 if (format === GPUTextureFormat.RGBA8Sint) return Int8Array; 38835 if (format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB) return Uint8Array; 38836 if (format === GPUTextureFormat.RGBA8Snorm) return Int8Array; 38837 if (format === GPUTextureFormat.R16Uint) return Uint16Array; 38838 if (format === GPUTextureFormat.R16Sint) return Int16Array; 38839 if (format === GPUTextureFormat.RG16Uint) return Uint16Array; 38840 if (format === GPUTextureFormat.RG16Sint) return Int16Array; 38841 if (format === GPUTextureFormat.RGBA16Uint) return Uint16Array; 38842 if (format === GPUTextureFormat.RGBA16Sint) return Int16Array; 38843 if (format === GPUTextureFormat.R16Float) return Uint16Array; 38844 if (format === GPUTextureFormat.RG16Float) return Uint16Array; 38845 if (format === GPUTextureFormat.RGBA16Float) return Uint16Array; 38846 if (format === GPUTextureFormat.R16Unorm) return Uint16Array; 38847 if (format === GPUTextureFormat.R16Snorm) return Int16Array; 38848 if (format === GPUTextureFormat.RG16Unorm) return Uint16Array; 38849 if (format === GPUTextureFormat.RG16Snorm) return Int16Array; 38850 if (format === GPUTextureFormat.RGBA16Unorm) return Uint16Array; 38851 if (format === GPUTextureFormat.RGBA16Snorm) return Int16Array; 38852 if (format === GPUTextureFormat.R32Uint) return Uint32Array; 38853 if (format === GPUTextureFormat.R32Sint) return Int32Array; 38854 if (format === GPUTextureFormat.R32Float) return Float32Array; 38855 if (format === GPUTextureFormat.RG32Uint) return Uint32Array; 38856 if (format === GPUTextureFormat.RG32Sint) return Int32Array; 38857 if (format === GPUTextureFormat.RG32Float) return Float32Array; 38858 if (format === GPUTextureFormat.RGBA32Uint) return Uint32Array; 38859 if (format === GPUTextureFormat.RGBA32Sint) return Int32Array; 38860 if (format === GPUTextureFormat.RGBA32Float) return Float32Array; 38861 if (format === GPUTextureFormat.BGRA8Unorm || format === GPUTextureFormat.BGRA8UnormSRGB) return Uint8Array; 38862 if (format === GPUTextureFormat.RGB10A2Unorm) return Uint32Array; 38863 if (format === GPUTextureFormat.RGB9E5UFloat) return Uint32Array; 38864 if (format === GPUTextureFormat.RG11B10UFloat) return Uint32Array; 38865 if (format === GPUTextureFormat.Depth32Float) return Float32Array; 38866 if (format === GPUTextureFormat.Depth24Plus) return Uint32Array; 38867 if (format === GPUTextureFormat.Depth24PlusStencil8) return Uint32Array; 38868 if (format === GPUTextureFormat.Depth32FloatStencil8) return Float32Array; 38869 } 38870 /** 38871 * Returns the GPU dimensions for the given texture. 38872 * 38873 * @private 38874 * @param {Texture} texture - The texture. 38875 * @return {string} The GPU dimension. 38876 */ 38877 _getDimension(texture3) { 38878 let dimension; 38879 if (texture3.is3DTexture || texture3.isData3DTexture) { 38880 dimension = GPUTextureDimension.ThreeD; 38881 } else { 38882 dimension = GPUTextureDimension.TwoD; 38883 } 38884 return dimension; 38885 } 38886}; 38887function getFormat(texture3, device) { 38888 const format = texture3.format; 38889 const type = texture3.type; 38890 const normalized = texture3.normalized; 38891 const colorSpace = texture3.colorSpace; 38892 const transfer = ColorManagement.getTransfer(colorSpace); 38893 let formatGPU; 38894 let textureFormatsTier1 = false; 38895 if (normalized) { 38896 textureFormatsTier1 = device.features.has(GPUFeatureName.TextureFormatsTier1); 38897 if (textureFormatsTier1 === false) { 38898 warn("WebGPURenderer: Unable to use normalized textures without texture-formats-tier1 feature."); 38899 } 38900 } 38901 if (texture3.isCompressedTexture === true || texture3.isCompressedArrayTexture === true) { 38902 switch (format) { 38903 case RGB_S3TC_DXT1_Format: 38904 case RGBA_S3TC_DXT1_Format: 38905 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm; 38906 break; 38907 case RGBA_S3TC_DXT3_Format: 38908 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm; 38909 break; 38910 case RGBA_S3TC_DXT5_Format: 38911 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm; 38912 break; 38913 case RED_RGTC1_Format: 38914 formatGPU = GPUTextureFormat.BC4RUnorm; 38915 break; 38916 case SIGNED_RED_RGTC1_Format: 38917 formatGPU = GPUTextureFormat.BC4RSnorm; 38918 break; 38919 case RED_GREEN_RGTC2_Format: 38920 formatGPU = GPUTextureFormat.BC5RGUnorm; 38921 break; 38922 case SIGNED_RED_GREEN_RGTC2_Format: 38923 formatGPU = GPUTextureFormat.BC5RGSnorm; 38924 break; 38925 case RGBA_BPTC_Format: 38926 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.BC7RGBAUnormSRGB : GPUTextureFormat.BC7RGBAUnorm; 38927 break; 38928 case RGB_ETC2_Format: 38929 case RGB_ETC1_Format: 38930 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ETC2RGB8UnormSRGB : GPUTextureFormat.ETC2RGB8Unorm; 38931 break; 38932 case RGBA_ETC2_EAC_Format: 38933 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ETC2RGBA8UnormSRGB : GPUTextureFormat.ETC2RGBA8Unorm; 38934 break; 38935 case R11_EAC_Format: 38936 formatGPU = GPUTextureFormat.EACR11Unorm; 38937 break; 38938 case SIGNED_R11_EAC_Format: 38939 formatGPU = GPUTextureFormat.EACR11Snorm; 38940 break; 38941 case RG11_EAC_Format: 38942 formatGPU = GPUTextureFormat.EACRG11Unorm; 38943 break; 38944 case SIGNED_RG11_EAC_Format: 38945 formatGPU = GPUTextureFormat.EACRG11Snorm; 38946 break; 38947 case RGBA_ASTC_4x4_Format: 38948 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC4x4UnormSRGB : GPUTextureFormat.ASTC4x4Unorm; 38949 break; 38950 case RGBA_ASTC_5x4_Format: 38951 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC5x4UnormSRGB : GPUTextureFormat.ASTC5x4Unorm; 38952 break; 38953 case RGBA_ASTC_5x5_Format: 38954 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC5x5UnormSRGB : GPUTextureFormat.ASTC5x5Unorm; 38955 break; 38956 case RGBA_ASTC_6x5_Format: 38957 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC6x5UnormSRGB : GPUTextureFormat.ASTC6x5Unorm; 38958 break; 38959 case RGBA_ASTC_6x6_Format: 38960 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC6x6UnormSRGB : GPUTextureFormat.ASTC6x6Unorm; 38961 break; 38962 case RGBA_ASTC_8x5_Format: 38963 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC8x5UnormSRGB : GPUTextureFormat.ASTC8x5Unorm; 38964 break; 38965 case RGBA_ASTC_8x6_Format: 38966 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC8x6UnormSRGB : GPUTextureFormat.ASTC8x6Unorm; 38967 break; 38968 case RGBA_ASTC_8x8_Format: 38969 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC8x8UnormSRGB : GPUTextureFormat.ASTC8x8Unorm; 38970 break; 38971 case RGBA_ASTC_10x5_Format: 38972 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC10x5UnormSRGB : GPUTextureFormat.ASTC10x5Unorm; 38973 break; 38974 case RGBA_ASTC_10x6_Format: 38975 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC10x6UnormSRGB : GPUTextureFormat.ASTC10x6Unorm; 38976 break; 38977 case RGBA_ASTC_10x8_Format: 38978 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC10x8UnormSRGB : GPUTextureFormat.ASTC10x8Unorm; 38979 break; 38980 case RGBA_ASTC_10x10_Format: 38981 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC10x10UnormSRGB : GPUTextureFormat.ASTC10x10Unorm; 38982 break; 38983 case RGBA_ASTC_12x10_Format: 38984 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC12x10UnormSRGB : GPUTextureFormat.ASTC12x10Unorm; 38985 break; 38986 case RGBA_ASTC_12x12_Format: 38987 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.ASTC12x12UnormSRGB : GPUTextureFormat.ASTC12x12Unorm; 38988 break; 38989 case RGBAFormat: 38990 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm; 38991 break; 38992 default: 38993 error("WebGPURenderer: Unsupported texture format.", format); 38994 } 38995 } else { 38996 switch (format) { 38997 case RGBAFormat: 38998 switch (type) { 38999 case ByteType: 39000 formatGPU = GPUTextureFormat.RGBA8Snorm; 39001 break; 39002 case ShortType: 39003 formatGPU = textureFormatsTier1 ? GPUTextureFormat.RGBA16Snorm : GPUTextureFormat.RGBA16Sint; 39004 break; 39005 case UnsignedShortType: 39006 formatGPU = textureFormatsTier1 ? GPUTextureFormat.RGBA16Unorm : GPUTextureFormat.RGBA16Uint; 39007 break; 39008 case UnsignedIntType: 39009 formatGPU = GPUTextureFormat.RGBA32Uint; 39010 break; 39011 case IntType: 39012 formatGPU = GPUTextureFormat.RGBA32Sint; 39013 break; 39014 case UnsignedByteType: 39015 formatGPU = transfer === SRGBTransfer ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm; 39016 break; 39017 case HalfFloatType: 39018 formatGPU = GPUTextureFormat.RGBA16Float; 39019 break; 39020 case FloatType: 39021 formatGPU = GPUTextureFormat.RGBA32Float; 39022 break; 39023 default: 39024 error("WebGPURenderer: Unsupported texture type with RGBAFormat.", type); 39025 } 39026 break; 39027 case RGBFormat: 39028 switch (type) { 39029 case UnsignedInt5999Type: 39030 formatGPU = GPUTextureFormat.RGB9E5UFloat; 39031 break; 39032 case UnsignedInt101111Type: 39033 formatGPU = GPUTextureFormat.RG11B10UFloat; 39034 break; 39035 default: 39036 error("WebGPURenderer: Unsupported texture type with RGBFormat.", type); 39037 } 39038 break; 39039 case RedFormat: 39040 switch (type) { 39041 case ByteType: 39042 formatGPU = GPUTextureFormat.R8Snorm; 39043 break; 39044 case ShortType: 39045 formatGPU = textureFormatsTier1 ? GPUTextureFormat.R16Snorm : GPUTextureFormat.R16Sint; 39046 break; 39047 case UnsignedShortType: 39048 formatGPU = textureFormatsTier1 ? GPUTextureFormat.R16Unorm : GPUTextureFormat.R16Uint; 39049 break; 39050 case UnsignedIntType: 39051 formatGPU = GPUTextureFormat.R32Uint; 39052 break; 39053 case IntType: 39054 formatGPU = GPUTextureFormat.R32Sint; 39055 break; 39056 case UnsignedByteType: 39057 formatGPU = GPUTextureFormat.R8Unorm; 39058 break; 39059 case HalfFloatType: 39060 formatGPU = GPUTextureFormat.R16Float; 39061 break; 39062 case FloatType: 39063 formatGPU = GPUTextureFormat.R32Float; 39064 break; 39065 default: 39066 error("WebGPURenderer: Unsupported texture type with RedFormat.", type); 39067 } 39068 break; 39069 case RGFormat: 39070 switch (type) { 39071 case ByteType: 39072 formatGPU = GPUTextureFormat.RG8Snorm; 39073 break; 39074 case ShortType: 39075 formatGPU = textureFormatsTier1 ? GPUTextureFormat.RG16Snorm : GPUTextureFormat.RG16Sint; 39076 break; 39077 case UnsignedShortType: 39078 formatGPU = textureFormatsTier1 ? GPUTextureFormat.RG16Unorm : GPUTextureFormat.RG16Uint; 39079 break; 39080 case UnsignedIntType: 39081 formatGPU = GPUTextureFormat.RG32Uint; 39082 break; 39083 case IntType: 39084 formatGPU = GPUTextureFormat.RG32Sint; 39085 break; 39086 case UnsignedByteType: 39087 formatGPU = GPUTextureFormat.RG8Unorm; 39088 break; 39089 case HalfFloatType: 39090 formatGPU = GPUTextureFormat.RG16Float; 39091 break; 39092 case FloatType: 39093 formatGPU = GPUTextureFormat.RG32Float; 39094 break; 39095 default: 39096 error("WebGPURenderer: Unsupported texture type with RGFormat.", type); 39097 } 39098 break; 39099 case DepthFormat: 39100 switch (type) { 39101 case UnsignedShortType: 39102 formatGPU = GPUTextureFormat.Depth16Unorm; 39103 break; 39104 case UnsignedIntType: 39105 formatGPU = GPUTextureFormat.Depth24Plus; 39106 break; 39107 case FloatType: 39108 formatGPU = GPUTextureFormat.Depth32Float; 39109 break; 39110 default: 39111 error("WebGPURenderer: Unsupported texture type with DepthFormat.", type); 39112 } 39113 break; 39114 case DepthStencilFormat: 39115 switch (type) { 39116 case UnsignedInt248Type: 39117 formatGPU = GPUTextureFormat.Depth24PlusStencil8; 39118 break; 39119 case FloatType: 39120 if (device && device.features.has(GPUFeatureName.Depth32FloatStencil8) === false) { 39121 error('WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.'); 39122 } 39123 formatGPU = GPUTextureFormat.Depth32FloatStencil8; 39124 break; 39125 default: 39126 error("WebGPURenderer: Unsupported texture type with DepthStencilFormat.", type); 39127 } 39128 break; 39129 case RedIntegerFormat: 39130 switch (type) { 39131 case IntType: 39132 formatGPU = GPUTextureFormat.R32Sint; 39133 break; 39134 case UnsignedIntType: 39135 formatGPU = GPUTextureFormat.R32Uint; 39136 break; 39137 default: 39138 error("WebGPURenderer: Unsupported texture type with RedIntegerFormat.", type); 39139 } 39140 break; 39141 case RGIntegerFormat: 39142 switch (type) { 39143 case IntType: 39144 formatGPU = GPUTextureFormat.RG32Sint; 39145 break; 39146 case UnsignedIntType: 39147 formatGPU = GPUTextureFormat.RG32Uint; 39148 break; 39149 default: 39150 error("WebGPURenderer: Unsupported texture type with RGIntegerFormat.", type); 39151 } 39152 break; 39153 case RGBAIntegerFormat: 39154 switch (type) { 39155 case IntType: 39156 formatGPU = GPUTextureFormat.RGBA32Sint; 39157 break; 39158 case UnsignedIntType: 39159 formatGPU = GPUTextureFormat.RGBA32Uint; 39160 break; 39161 default: 39162 error("WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.", type); 39163 } 39164 break; 39165 default: 39166 error("WebGPURenderer: Unsupported texture format.", format); 39167 } 39168 } 39169 return formatGPU; 39170} 39171var declarationRegexp = /^[fn]*\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)\s*[\-\>]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i; 39172var propertiesRegexp = /([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/ig; 39173var wgslTypeLib$1 = { 39174 "f32": "float", 39175 "i32": "int", 39176 "u32": "uint", 39177 "bool": "bool", 39178 "vec2<f32>": "vec2", 39179 "vec2<i32>": "ivec2", 39180 "vec2<u32>": "uvec2", 39181 "vec2<bool>": "bvec2", 39182 "vec2f": "vec2", 39183 "vec2i": "ivec2", 39184 "vec2u": "uvec2", 39185 "vec2b": "bvec2", 39186 "vec3<f32>": "vec3", 39187 "vec3<i32>": "ivec3", 39188 "vec3<u32>": "uvec3", 39189 "vec3<bool>": "bvec3", 39190 "vec3f": "vec3", 39191 "vec3i": "ivec3", 39192 "vec3u": "uvec3", 39193 "vec3b": "bvec3", 39194 "vec4<f32>": "vec4", 39195 "vec4<i32>": "ivec4", 39196 "vec4<u32>": "uvec4", 39197 "vec4<bool>": "bvec4", 39198 "vec4f": "vec4", 39199 "vec4i": "ivec4", 39200 "vec4u": "uvec4", 39201 "vec4b": "bvec4", 39202 "mat2x2<f32>": "mat2", 39203 "mat2x2f": "mat2", 39204 "mat3x3<f32>": "mat3", 39205 "mat3x3f": "mat3", 39206 "mat4x4<f32>": "mat4", 39207 "mat4x4f": "mat4", 39208 "sampler": "sampler", 39209 "texture_1d": "texture", 39210 "texture_2d": "texture", 39211 "texture_2d_array": "texture", 39212 "texture_multisampled_2d": "cubeTexture", 39213 "texture_depth_2d": "depthTexture", 39214 "texture_depth_2d_array": "depthTexture", 39215 "texture_depth_multisampled_2d": "depthTexture", 39216 "texture_depth_cube": "depthTexture", 39217 "texture_depth_cube_array": "depthTexture", 39218 "texture_3d": "texture3D", 39219 "texture_cube": "cubeTexture", 39220 "texture_cube_array": "cubeTexture", 39221 "texture_storage_1d": "storageTexture", 39222 "texture_storage_2d": "storageTexture", 39223 "texture_storage_2d_array": "storageTexture", 39224 "texture_storage_3d": "storageTexture" 39225}; 39226var parse = (source) => { 39227 source = source.trim(); 39228 const declaration = source.match(declarationRegexp); 39229 if (declaration !== null && declaration.length === 4) { 39230 const inputsCode = declaration[2]; 39231 const propsMatches = []; 39232 let match = null; 39233 while ((match = propertiesRegexp.exec(inputsCode)) !== null) { 39234 propsMatches.push({ name: match[1], type: match[2] }); 39235 } 39236 const inputs = []; 39237 for (let i = 0; i < propsMatches.length; i++) { 39238 const { name: name2, type: type2 } = propsMatches[i]; 39239 let resolvedType = type2; 39240 if (resolvedType.startsWith("ptr")) { 39241 resolvedType = "pointer"; 39242 } else { 39243 if (resolvedType.startsWith("texture")) { 39244 resolvedType = type2.split("<")[0]; 39245 } 39246 resolvedType = wgslTypeLib$1[resolvedType]; 39247 } 39248 inputs.push(new NodeFunctionInput(resolvedType, name2)); 39249 } 39250 const blockCode = source.substring(declaration[0].length); 39251 const outputType = declaration[3] || "void"; 39252 const name = declaration[1] !== void 0 ? declaration[1] : ""; 39253 const type = wgslTypeLib$1[outputType] || outputType; 39254 return { 39255 type, 39256 inputs, 39257 name, 39258 inputsCode, 39259 blockCode, 39260 outputType 39261 }; 39262 } else { 39263 throw new Error("FunctionNode: Function is not a WGSL code."); 39264 } 39265}; 39266var WGSLNodeFunction = class extends NodeFunction { 39267 /** 39268 * Constructs a new WGSL node function. 39269 * 39270 * @param {string} source - The WGSL source. 39271 */ 39272 constructor(source) { 39273 const { type, inputs, name, inputsCode, blockCode, outputType } = parse(source); 39274 super(type, inputs, name); 39275 this.inputsCode = inputsCode; 39276 this.blockCode = blockCode; 39277 this.outputType = outputType; 39278 } 39279 /** 39280 * This method returns the WGSL code of the node function. 39281 * 39282 * @param {string} [name=this.name] - The function's name. 39283 * @return {string} The shader code. 39284 */ 39285 getCode(name = this.name) { 39286 const outputType = this.outputType !== "void" ? "-> " + this.outputType : ""; 39287 return `fn ${name} ( ${this.inputsCode.trim()} ) ${outputType}` + this.blockCode; 39288 } 39289}; 39290var WGSLNodeParser = class extends NodeParser { 39291 /** 39292 * The method parses the given WGSL code an returns a node function. 39293 * 39294 * @param {string} source - The WGSL code. 39295 * @return {WGSLNodeFunction} A node function. 39296 */ 39297 parseFunction(source) { 39298 return new WGSLNodeFunction(source); 39299 } 39300}; 39301var accessNames = { 39302 [NodeAccess.READ_ONLY]: "read", 39303 [NodeAccess.WRITE_ONLY]: "write", 39304 [NodeAccess.READ_WRITE]: "read_write" 39305}; 39306var wrapNames = { 39307 [RepeatWrapping]: "repeat", 39308 [ClampToEdgeWrapping]: "clamp", 39309 [MirroredRepeatWrapping]: "mirror" 39310}; 39311var gpuShaderStageLib = { 39312 "vertex": GPUShaderStage.VERTEX, 39313 "fragment": GPUShaderStage.FRAGMENT, 39314 "compute": GPUShaderStage.COMPUTE 39315}; 39316var supports = { 39317 instance: true, 39318 swizzleAssign: false, 39319 storageBuffer: true 39320}; 39321var wgslFnOpLib = { 39322 "^^": "tsl_xor" 39323}; 39324var wgslTypeLib = { 39325 float: "f32", 39326 int: "i32", 39327 uint: "u32", 39328 bool: "bool", 39329 color: "vec3<f32>", 39330 vec2: "vec2<f32>", 39331 ivec2: "vec2<i32>", 39332 uvec2: "vec2<u32>", 39333 bvec2: "vec2<bool>", 39334 vec3: "vec3<f32>", 39335 ivec3: "vec3<i32>", 39336 uvec3: "vec3<u32>", 39337 bvec3: "vec3<bool>", 39338 vec4: "vec4<f32>", 39339 ivec4: "vec4<i32>", 39340 uvec4: "vec4<u32>", 39341 bvec4: "vec4<bool>", 39342 mat2: "mat2x2<f32>", 39343 mat3: "mat3x3<f32>", 39344 mat4: "mat4x4<f32>" 39345}; 39346var wgslCodeCache = {}; 39347var wgslPolyfill = { 39348 tsl_xor: new CodeNode("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"), 39349 mod_float: new CodeNode("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"), 39350 mod_vec2: new CodeNode("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"), 39351 mod_vec3: new CodeNode("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"), 39352 mod_vec4: new CodeNode("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"), 39353 equals_bool: new CodeNode("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"), 39354 equals_bvec2: new CodeNode("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2<bool> { return vec2<bool>( a.x == b.x, a.y == b.y ); }"), 39355 equals_bvec3: new CodeNode("fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3<bool> { return vec3<bool>( a.x == b.x, a.y == b.y, a.z == b.z ); }"), 39356 equals_bvec4: new CodeNode("fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4<bool> { return vec4<bool>( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }"), 39357 repeatWrapping_float: new CodeNode("fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }"), 39358 mirrorWrapping_float: new CodeNode("fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }"), 39359 clampWrapping_float: new CodeNode("fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }"), 39360 biquadraticTexture: new CodeNode( 39361 /* wgsl */ 39362 ` 39363fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f { 39364 39365 let res = vec2f( iRes ); 39366 39367 let uvScaled = coord * res; 39368 let uvWrapping = ( ( uvScaled % res ) + res ) % res; 39369 39370 // https://www.shadertoy.com/view/WtyXRy 39371 39372 let uv = uvWrapping - 0.5; 39373 let iuv = floor( uv ); 39374 let f = fract( uv ); 39375 39376 let rg1 = textureLoad( map, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level ); 39377 let rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level ); 39378 let rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level ); 39379 let rg4 = textureLoad( map, vec2u( iuv + vec2( 1.5, 1.5 ) ) % iRes, level ); 39380 39381 return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y ); 39382 39383} 39384` 39385 ), 39386 biquadraticTextureArray: new CodeNode( 39387 /* wgsl */ 39388 ` 39389fn tsl_biquadraticTexture_array( map : texture_2d_array<f32>, coord : vec2f, iRes : vec2u, layer : u32, level : u32 ) -> vec4f { 39390 39391 let res = vec2f( iRes ); 39392 39393 let uvScaled = coord * res; 39394 let uvWrapping = ( ( uvScaled % res ) + res ) % res; 39395 39396 // https://www.shadertoy.com/view/WtyXRy 39397 39398 let uv = uvWrapping - 0.5; 39399 let iuv = floor( uv ); 39400 let f = fract( uv ); 39401 39402 let rg1 = textureLoad( map, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, layer, level ); 39403 let rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, layer, level ); 39404 let rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, layer, level ); 39405 let rg4 = textureLoad( map, vec2u( iuv + vec2( 1.5, 1.5 ) ) % iRes, layer, level ); 39406 39407 return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y ); 39408 39409} 39410` 39411 ) 39412}; 39413var wgslMethods = { 39414 dFdx: "dpdx", 39415 dFdy: "- dpdy", 39416 mod_float: "tsl_mod_float", 39417 mod_vec2: "tsl_mod_vec2", 39418 mod_vec3: "tsl_mod_vec3", 39419 mod_vec4: "tsl_mod_vec4", 39420 equals_bool: "tsl_equals_bool", 39421 equals_bvec2: "tsl_equals_bvec2", 39422 equals_bvec3: "tsl_equals_bvec3", 39423 equals_bvec4: "tsl_equals_bvec4", 39424 inversesqrt: "inverseSqrt", 39425 bitcast: "bitcast<f32>", 39426 floatpack_snorm_2x16: "pack2x16snorm", 39427 floatpack_unorm_2x16: "pack2x16unorm", 39428 floatpack_float16_2x16: "pack2x16float", 39429 floatunpack_snorm_2x16: "unpack2x16snorm", 39430 floatunpack_unorm_2x16: "unpack2x16unorm", 39431 floatunpack_float16_2x16: "unpack2x16float" 39432}; 39433var diagnostics = ""; 39434if ((typeof navigator !== "undefined" && /Firefox|Deno/g.test(navigator.userAgent)) !== true) { 39435 diagnostics += "diagnostic( off, derivative_uniformity );\n"; 39436} 39437var WGSLNodeBuilder = class extends NodeBuilder { 39438 /** 39439 * Constructs a new WGSL node builder renderer. 39440 * 39441 * @param {Object3D} object - The 3D object. 39442 * @param {Renderer} renderer - The renderer. 39443 */ 39444 constructor(object, renderer) { 39445 super(object, renderer, new WGSLNodeParser()); 39446 this.uniformGroups = {}; 39447 this.uniformGroupsBindings = {}; 39448 this.builtins = {}; 39449 this.directives = {}; 39450 this.scopedArrays = /* @__PURE__ */ new Map(); 39451 this.allowEarlyReturns = true; 39452 this.allowGlobalVariables = true; 39453 } 39454 /** 39455 * Generates the WGSL snippet for sampled textures. 39456 * 39457 * @private 39458 * @param {Texture} texture - The texture. 39459 * @param {string} textureProperty - The name of the texture uniform in the shader. 39460 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39461 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39462 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39463 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39464 * @return {string} The WGSL snippet. 39465 */ 39466 _generateTextureSample(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 39467 if (shaderStage === "fragment") { 39468 if (depthSnippet) { 39469 if (offsetSnippet) { 39470 return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${offsetSnippet} )`; 39471 } 39472 return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet} )`; 39473 } else { 39474 if (offsetSnippet) { 39475 return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${offsetSnippet} )`; 39476 } 39477 return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet} )`; 39478 } 39479 } else { 39480 return this.generateTextureSampleLevel(texture3, textureProperty, uvSnippet, "0", depthSnippet); 39481 } 39482 } 39483 /** 39484 * Generates the WGSL snippet when sampling textures with explicit mip level. 39485 * 39486 * @private 39487 * @param {Texture} texture - The texture. 39488 * @param {string} textureProperty - The name of the texture uniform in the shader. 39489 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39490 * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39491 * @param {string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39492 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39493 * @return {string} The WGSL snippet. 39494 */ 39495 generateTextureSampleLevel(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet) { 39496 if (this.isUnfilterable(texture3) === false) { 39497 if (depthSnippet) { 39498 if (offsetSnippet) { 39499 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${levelSnippet}, ${offsetSnippet} )`; 39500 } 39501 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${levelSnippet} )`; 39502 } else { 39503 if (offsetSnippet) { 39504 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${levelSnippet}, ${offsetSnippet} )`; 39505 } 39506 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${levelSnippet} )`; 39507 } 39508 } else if (this.isFilteredTexture(texture3)) { 39509 return this.generateFilteredTexture(texture3, textureProperty, uvSnippet, offsetSnippet, levelSnippet, depthSnippet); 39510 } else { 39511 return this.generateTextureLod(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet); 39512 } 39513 } 39514 /** 39515 * Generates a wrap function used in context of textures. 39516 * 39517 * @param {Texture} texture - The texture to generate the function for. 39518 * @return {string} The name of the generated function. 39519 */ 39520 generateWrapFunction(texture3) { 39521 const functionName = `tsl_coord_${wrapNames[texture3.wrapS]}S_${wrapNames[texture3.wrapT]}_${texture3.is3DTexture || texture3.isData3DTexture ? "3d" : "2d"}T`; 39522 let nodeCode = wgslCodeCache[functionName]; 39523 if (nodeCode === void 0) { 39524 const includes = []; 39525 const coordType = texture3.is3DTexture || texture3.isData3DTexture ? "vec3f" : "vec2f"; 39526 let code3 = `fn ${functionName}( coord : ${coordType} ) -> ${coordType} { 39527 39528 return ${coordType}( 39529`; 39530 const addWrapSnippet = (wrap, axis) => { 39531 if (wrap === RepeatWrapping) { 39532 includes.push(wgslPolyfill.repeatWrapping_float); 39533 code3 += ` tsl_repeatWrapping_float( coord.${axis} )`; 39534 } else if (wrap === ClampToEdgeWrapping) { 39535 includes.push(wgslPolyfill.clampWrapping_float); 39536 code3 += ` tsl_clampWrapping_float( coord.${axis} )`; 39537 } else if (wrap === MirroredRepeatWrapping) { 39538 includes.push(wgslPolyfill.mirrorWrapping_float); 39539 code3 += ` tsl_mirrorWrapping_float( coord.${axis} )`; 39540 } else { 39541 code3 += ` coord.${axis}`; 39542 warn(`WebGPURenderer: Unsupported texture wrap type "${wrap}" for vertex shader.`); 39543 } 39544 }; 39545 addWrapSnippet(texture3.wrapS, "x"); 39546 code3 += ",\n"; 39547 addWrapSnippet(texture3.wrapT, "y"); 39548 if (texture3.is3DTexture || texture3.isData3DTexture) { 39549 code3 += ",\n"; 39550 addWrapSnippet(texture3.wrapR, "z"); 39551 } 39552 code3 += "\n );\n\n}\n"; 39553 wgslCodeCache[functionName] = nodeCode = new CodeNode(code3, includes); 39554 } 39555 nodeCode.build(this); 39556 return functionName; 39557 } 39558 /** 39559 * Generates the array declaration string. 39560 * 39561 * @param {string} type - The type. 39562 * @param {?number} [count] - The count. 39563 * @return {string} The generated value as a shader string. 39564 */ 39565 generateArrayDeclaration(type, count) { 39566 return `array< ${this.getType(type)}, ${count} >`; 39567 } 39568 /** 39569 * Generates a WGSL variable that holds the texture dimension of the given texture. 39570 * It also returns information about the number of layers (elements) of an arrayed 39571 * texture as well as the cube face count of cube textures. 39572 * 39573 * @param {Texture} texture - The texture to generate the function for. 39574 * @param {string} textureProperty - The name of the video texture uniform in the shader. 39575 * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39576 * @return {string} The name of the dimension variable. 39577 */ 39578 generateTextureDimension(texture3, textureProperty, levelSnippet) { 39579 const textureData = this.getDataFromNode(texture3, this.shaderStage, this.cache); 39580 if (textureData.dimensionsSnippet === void 0) textureData.dimensionsSnippet = {}; 39581 let textureDimensionNode = textureData.dimensionsSnippet[levelSnippet]; 39582 if (textureData.dimensionsSnippet[levelSnippet] === void 0) { 39583 let textureDimensionsParams; 39584 let dimensionType; 39585 const { primarySamples } = this.renderer.backend.utils.getTextureSampleData(texture3); 39586 const isMultisampled = primarySamples > 1; 39587 if (texture3.is3DTexture || texture3.isData3DTexture) { 39588 dimensionType = "vec3<u32>"; 39589 } else { 39590 dimensionType = "vec2<u32>"; 39591 } 39592 if (isMultisampled || texture3.isStorageTexture) { 39593 textureDimensionsParams = textureProperty; 39594 } else { 39595 textureDimensionsParams = `${textureProperty}${levelSnippet ? `, u32( ${levelSnippet} )` : ""}`; 39596 } 39597 textureDimensionNode = new VarNode(new ExpressionNode(`textureDimensions( ${textureDimensionsParams} )`, dimensionType)); 39598 textureData.dimensionsSnippet[levelSnippet] = textureDimensionNode; 39599 if (texture3.isArrayTexture || texture3.isDataArrayTexture || texture3.is3DTexture || texture3.isData3DTexture) { 39600 textureData.arrayLayerCount = new VarNode( 39601 new ExpressionNode( 39602 `textureNumLayers(${textureProperty})`, 39603 "u32" 39604 ) 39605 ); 39606 } 39607 if (texture3.isTextureCube) { 39608 textureData.cubeFaceCount = new VarNode( 39609 new ExpressionNode("6u", "u32") 39610 ); 39611 } 39612 } 39613 return textureDimensionNode.build(this); 39614 } 39615 /** 39616 * Generates the WGSL snippet for a manual filtered texture. 39617 * 39618 * @param {Texture} texture - The texture. 39619 * @param {string} textureProperty - The name of the texture uniform in the shader. 39620 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39621 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39622 * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39623 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39624 * @return {string} The WGSL snippet. 39625 */ 39626 generateFilteredTexture(texture3, textureProperty, uvSnippet, offsetSnippet, levelSnippet = "0u", depthSnippet) { 39627 const wrapFunction = this.generateWrapFunction(texture3); 39628 const textureDimension = this.generateTextureDimension(texture3, textureProperty, levelSnippet); 39629 if (offsetSnippet) { 39630 uvSnippet = `${uvSnippet} + vec2<f32>(${offsetSnippet}) / ${textureDimension}`; 39631 } 39632 if (depthSnippet) { 39633 this._include("biquadraticTextureArray"); 39634 return `tsl_biquadraticTexture_array( ${textureProperty}, ${wrapFunction}( ${uvSnippet} ), ${textureDimension}, u32( ${depthSnippet} ), u32( ${levelSnippet} ) )`; 39635 } 39636 this._include("biquadraticTexture"); 39637 return `tsl_biquadraticTexture( ${textureProperty}, ${wrapFunction}( ${uvSnippet} ), ${textureDimension}, u32( ${levelSnippet} ) )`; 39638 } 39639 /** 39640 * Generates the WGSL snippet for a texture lookup with explicit level-of-detail. 39641 * Since it's a lookup, no sampling or filtering is applied. 39642 * 39643 * @param {Texture} texture - The texture. 39644 * @param {string} textureProperty - The name of the texture uniform in the shader. 39645 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39646 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39647 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39648 * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39649 * @return {string} The WGSL snippet. 39650 */ 39651 generateTextureLod(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet = "0u") { 39652 if (texture3.isCubeTexture === true) { 39653 if (offsetSnippet) { 39654 uvSnippet = `${uvSnippet} + vec3<f32>(${offsetSnippet})`; 39655 } 39656 const levelType = texture3.isDepthTexture ? "u32" : "f32"; 39657 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${levelType}( ${levelSnippet} ) )`; 39658 } 39659 const wrapFunction = this.generateWrapFunction(texture3); 39660 const textureDimension = this.generateTextureDimension(texture3, textureProperty, levelSnippet); 39661 const vecType = texture3.is3DTexture || texture3.isData3DTexture ? "vec3" : "vec2"; 39662 const textureDimensionMargin = vecType === "vec3" ? "vec3<u32>( 1, 1, 1 )" : "vec2<u32>( 1, 1 )"; 39663 if (offsetSnippet) { 39664 uvSnippet = `${uvSnippet} + ${vecType}<f32>(${offsetSnippet}) / ${vecType}<f32>( ${textureDimension} )`; 39665 } 39666 const clampMin = `${vecType}<f32>( 0 )`; 39667 const clampMax = `${vecType}<f32>( ${textureDimension} - ${textureDimensionMargin} )`; 39668 uvSnippet = `${vecType}<u32>( clamp( floor( ${wrapFunction}( ${uvSnippet} ) * ${vecType}<f32>( ${textureDimension} ) ), ${clampMin}, ${clampMax} ) )`; 39669 return this.generateTextureLoad(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, null); 39670 } 39671 /** 39672 * Generates the WGSL snippet that reads a single texel from a storage texture. 39673 * 39674 * @param {Texture} texture - The texture. 39675 * @param {string} textureProperty - The name of the texture uniform in the shader. 39676 * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39677 * @param {?string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39678 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39679 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39680 * @return {string} The WGSL snippet. 39681 */ 39682 generateStorageTextureLoad(texture3, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet) { 39683 if (offsetSnippet) { 39684 uvIndexSnippet = `${uvIndexSnippet} + ${offsetSnippet}`; 39685 } 39686 let snippet; 39687 if (depthSnippet) { 39688 snippet = `textureLoad( ${textureProperty}, ${uvIndexSnippet}, ${depthSnippet} )`; 39689 } else { 39690 snippet = `textureLoad( ${textureProperty}, ${uvIndexSnippet} )`; 39691 } 39692 return snippet; 39693 } 39694 /** 39695 * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering. 39696 * 39697 * @param {Texture} texture - The texture. 39698 * @param {string} textureProperty - The name of the texture uniform in the shader. 39699 * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39700 * @param {?string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39701 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39702 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39703 * @return {string} The WGSL snippet. 39704 */ 39705 generateTextureLoad(texture3, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet) { 39706 if (levelSnippet === null) levelSnippet = "0u"; 39707 if (offsetSnippet) { 39708 uvIndexSnippet = `${uvIndexSnippet} + ${offsetSnippet}`; 39709 } 39710 let snippet; 39711 if (depthSnippet) { 39712 snippet = `textureLoad( ${textureProperty}, ${uvIndexSnippet}, ${depthSnippet}, u32( ${levelSnippet} ) )`; 39713 } else { 39714 snippet = `textureLoad( ${textureProperty}, ${uvIndexSnippet}, u32( ${levelSnippet} ) )`; 39715 if (this.renderer.backend.compatibilityMode && texture3.isDepthTexture) { 39716 snippet += ".x"; 39717 } 39718 } 39719 return snippet; 39720 } 39721 /** 39722 * Generates the WGSL snippet that writes a single texel to a texture. 39723 * 39724 * @param {Texture} texture - The texture. 39725 * @param {string} textureProperty - The name of the texture uniform in the shader. 39726 * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39727 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39728 * @param {string} valueSnippet - A WGSL snippet that represent the new texel value. 39729 * @return {string} The WGSL snippet. 39730 */ 39731 generateTextureStore(texture3, textureProperty, uvIndexSnippet, depthSnippet, valueSnippet) { 39732 let snippet; 39733 if (depthSnippet) { 39734 snippet = `textureStore( ${textureProperty}, ${uvIndexSnippet}, ${depthSnippet}, ${valueSnippet} )`; 39735 } else { 39736 snippet = `textureStore( ${textureProperty}, ${uvIndexSnippet}, ${valueSnippet} )`; 39737 } 39738 return snippet; 39739 } 39740 /** 39741 * Returns `true` if the sampled values of the given texture should be compared against a reference value. 39742 * 39743 * @param {Texture} texture - The texture. 39744 * @return {boolean} Whether the sampled values of the given texture should be compared against a reference value or not. 39745 */ 39746 isSampleCompare(texture3) { 39747 return texture3.isDepthTexture === true && texture3.compareFunction !== null && this.renderer.hasCompatibility(Compatibility.TEXTURE_COMPARE); 39748 } 39749 /** 39750 * Returns `true` if the given texture is unfilterable. 39751 * 39752 * @param {Texture} texture - The texture. 39753 * @return {boolean} Whether the given texture is unfilterable or not. 39754 */ 39755 isUnfilterable(texture3) { 39756 return this.getComponentTypeFromTexture(texture3) !== "float" || !this.isAvailable("float32Filterable") && texture3.type === FloatType || this.isSampleCompare(texture3) === false && texture3.minFilter === NearestFilter && texture3.magFilter === NearestFilter || this.renderer.backend.utils.getTextureSampleData(texture3).primarySamples > 1; 39757 } 39758 /** 39759 * Generates the WGSL snippet for sampling/loading the given texture. 39760 * 39761 * @param {Texture} texture - The texture. 39762 * @param {string} textureProperty - The name of the texture uniform in the shader. 39763 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39764 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39765 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39766 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39767 * @return {string} The WGSL snippet. 39768 */ 39769 generateTexture(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 39770 let snippet = null; 39771 if (this.isUnfilterable(texture3)) { 39772 snippet = this.generateTextureLod(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, "0", shaderStage); 39773 } else { 39774 snippet = this._generateTextureSample(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage); 39775 } 39776 return snippet; 39777 } 39778 /** 39779 * Generates the WGSL snippet for sampling/loading the given texture using explicit gradients. 39780 * 39781 * @param {Texture} texture - The texture. 39782 * @param {string} textureProperty - The name of the texture uniform in the shader. 39783 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39784 * @param {Array<string>} gradSnippet - An array holding both gradient WGSL snippets. 39785 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39786 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39787 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39788 * @return {string} The WGSL snippet. 39789 */ 39790 generateTextureGrad(texture3, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 39791 if (shaderStage === "fragment") { 39792 if (depthSnippet) { 39793 if (offsetSnippet) { 39794 return `textureSampleGrad( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]}, ${offsetSnippet} )`; 39795 } 39796 return `textureSampleGrad( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]} )`; 39797 } else { 39798 if (offsetSnippet) { 39799 return `textureSampleGrad( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]}, ${offsetSnippet} )`; 39800 } 39801 return `textureSampleGrad( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]} )`; 39802 } 39803 } else { 39804 error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${shaderStage} shader.`); 39805 } 39806 } 39807 /** 39808 * Generates the WGSL snippet for sampling a depth texture and comparing the sampled depth values 39809 * against a reference value. 39810 * 39811 * @param {Texture} texture - The texture. 39812 * @param {string} textureProperty - The name of the texture uniform in the shader. 39813 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39814 * @param {string} compareSnippet - A WGSL snippet that represents the reference value. 39815 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39816 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39817 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39818 * @return {string} The WGSL snippet. 39819 */ 39820 generateTextureCompare(texture3, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 39821 if (shaderStage === "fragment") { 39822 if (texture3.isDepthTexture === true && texture3.isArrayTexture === true) { 39823 if (offsetSnippet) { 39824 return `textureSampleCompare( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${compareSnippet}, ${offsetSnippet} )`; 39825 } 39826 return `textureSampleCompare( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${compareSnippet} )`; 39827 } 39828 if (offsetSnippet) { 39829 return `textureSampleCompare( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${compareSnippet}, ${offsetSnippet} )`; 39830 } 39831 return `textureSampleCompare( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${compareSnippet} )`; 39832 } else { 39833 error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${shaderStage} shader.`); 39834 } 39835 } 39836 /** 39837 * Generates the WGSL snippet when sampling textures with explicit mip level. 39838 * 39839 * @param {Texture} texture - The texture. 39840 * @param {string} textureProperty - The name of the texture uniform in the shader. 39841 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39842 * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. 39843 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39844 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39845 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39846 * @return {string} The WGSL snippet. 39847 */ 39848 generateTextureLevel(texture3, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet) { 39849 if (this.isUnfilterable(texture3) === false) { 39850 if (depthSnippet) { 39851 if (offsetSnippet) { 39852 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${levelSnippet}, ${offsetSnippet} )`; 39853 } 39854 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${levelSnippet} )`; 39855 } else { 39856 if (offsetSnippet) { 39857 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${levelSnippet}, ${offsetSnippet} )`; 39858 } 39859 return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${levelSnippet} )`; 39860 } 39861 } else if (this.isFilteredTexture(texture3)) { 39862 return this.generateFilteredTexture(texture3, textureProperty, uvSnippet, offsetSnippet, levelSnippet, depthSnippet); 39863 } else { 39864 return this.generateTextureLod(texture3, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet); 39865 } 39866 } 39867 /** 39868 * Generates the WGSL snippet when sampling textures with a bias to the mip level. 39869 * 39870 * @param {Texture} texture - The texture. 39871 * @param {string} textureProperty - The name of the texture uniform in the shader. 39872 * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. 39873 * @param {string} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling. 39874 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. 39875 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. 39876 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39877 * @return {string} The WGSL snippet. 39878 */ 39879 generateTextureBias(texture3, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage) { 39880 if (shaderStage === "fragment") { 39881 if (depthSnippet) { 39882 if (offsetSnippet) { 39883 return `textureSampleBias( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${biasSnippet}, ${offsetSnippet} )`; 39884 } 39885 return `textureSampleBias( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet}, ${biasSnippet} )`; 39886 } else { 39887 if (offsetSnippet) { 39888 return `textureSampleBias( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${biasSnippet}, ${offsetSnippet} )`; 39889 } 39890 return `textureSampleBias( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${biasSnippet} )`; 39891 } 39892 } else { 39893 error(`WebGPURenderer: THREE.TextureNode.biasNode does not support ${shaderStage} shader.`); 39894 } 39895 } 39896 /** 39897 * Returns a WGSL snippet that represents the property name of the given node. 39898 * 39899 * @param {Node} node - The node. 39900 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 39901 * @return {string} The property name. 39902 */ 39903 getPropertyName(node, shaderStage = this.shaderStage) { 39904 if (node.isNodeVarying === true && node.needsInterpolation === true) { 39905 if (shaderStage === "vertex") { 39906 return `varyings.${node.name}`; 39907 } 39908 } else if (node.isNodeUniform === true) { 39909 const name = node.name; 39910 const type = node.type; 39911 if (type === "texture" || type === "cubeTexture" || type === "cubeDepthTexture" || type === "storageTexture" || type === "texture3D") { 39912 return name; 39913 } else if (type === "buffer" || type === "storageBuffer" || type === "indirectStorageBuffer") { 39914 if (this.isCustomStruct(node)) { 39915 return name; 39916 } 39917 return name + ".value"; 39918 } else { 39919 return node.groupNode.name + "." + name; 39920 } 39921 } 39922 return super.getPropertyName(node); 39923 } 39924 /** 39925 * Returns the output struct name. 39926 * 39927 * @return {string} The name of the output struct. 39928 */ 39929 getOutputStructName() { 39930 return "output"; 39931 } 39932 /** 39933 * Returns the native shader operator name for a given generic name. 39934 * 39935 * @param {string} op - The operator name to resolve. 39936 * @return {?string} The resolved operator name. 39937 */ 39938 getFunctionOperator(op) { 39939 const fnOp = wgslFnOpLib[op]; 39940 if (fnOp !== void 0) { 39941 this._include(fnOp); 39942 return fnOp; 39943 } 39944 return null; 39945 } 39946 /** 39947 * Returns the node access for the given node and shader stage. 39948 * 39949 * @param {StorageTextureNode|StorageBufferNode} node - The storage node. 39950 * @param {string} shaderStage - The shader stage. 39951 * @return {string} The node access. 39952 */ 39953 getNodeAccess(node, shaderStage) { 39954 if (shaderStage !== "compute") { 39955 if (node.isAtomic === true) { 39956 warn("WebGPURenderer: Atomic operations are only supported in compute shaders."); 39957 return NodeAccess.READ_WRITE; 39958 } 39959 return NodeAccess.READ_ONLY; 39960 } 39961 return node.access; 39962 } 39963 /** 39964 * Returns A WGSL snippet representing the storage access. 39965 * 39966 * @param {StorageTextureNode|StorageBufferNode} node - The storage node. 39967 * @param {string} shaderStage - The shader stage. 39968 * @return {string} The WGSL snippet representing the storage access. 39969 */ 39970 getStorageAccess(node, shaderStage) { 39971 return accessNames[this.getNodeAccess(node, shaderStage)]; 39972 } 39973 /** 39974 * This method is one of the more important ones since it's responsible 39975 * for generating a matching binding instance for the given uniform node. 39976 * 39977 * These bindings are later used in the renderer to create bind groups 39978 * and layouts. 39979 * 39980 * @param {UniformNode} node - The uniform node. 39981 * @param {string} type - The node data type. 39982 * @param {string} shaderStage - The shader stage. 39983 * @param {?string} [name=null] - An optional uniform name. 39984 * @return {NodeUniform} The node uniform object. 39985 */ 39986 getUniformFromNode(node, type, shaderStage, name = null) { 39987 const uniformNode = super.getUniformFromNode(node, type, shaderStage, name); 39988 const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); 39989 if (nodeData.uniformGPU === void 0) { 39990 let uniformGPU; 39991 const group = node.groupNode; 39992 const groupName = group.name; 39993 const bindings = this.getBindGroupArray(groupName, shaderStage); 39994 if (type === "texture" || type === "cubeTexture" || type === "cubeDepthTexture" || type === "storageTexture" || type === "texture3D") { 39995 let texture3 = null; 39996 const access6 = this.getNodeAccess(node, shaderStage); 39997 if (type === "texture" || type === "storageTexture") { 39998 if (node.value.is3DTexture === true) { 39999 texture3 = new NodeSampledTexture3D(uniformNode.name, uniformNode.node, group, access6); 40000 } else { 40001 texture3 = new NodeSampledTexture(uniformNode.name, uniformNode.node, group, access6); 40002 } 40003 } else if (type === "cubeTexture" || type === "cubeDepthTexture") { 40004 texture3 = new NodeSampledCubeTexture(uniformNode.name, uniformNode.node, group, access6); 40005 } else if (type === "texture3D") { 40006 texture3 = new NodeSampledTexture3D(uniformNode.name, uniformNode.node, group, access6); 40007 } 40008 texture3.store = node.isStorageTextureNode === true; 40009 texture3.mipLevel = texture3.store ? node.mipLevel : 0; 40010 texture3.setVisibility(gpuShaderStageLib[shaderStage]); 40011 const needsSampler = node.value.isCubeTexture === true || this.isUnfilterable(node.value) === false && texture3.store === false; 40012 if (needsSampler) { 40013 const sampler3 = new NodeSampler(`${uniformNode.name}_sampler`, uniformNode.node, group); 40014 sampler3.setVisibility(gpuShaderStageLib[shaderStage]); 40015 bindings.push(sampler3, texture3); 40016 uniformGPU = [sampler3, texture3]; 40017 } else { 40018 bindings.push(texture3); 40019 uniformGPU = [texture3]; 40020 } 40021 } else if (type === "buffer" || type === "storageBuffer" || type === "indirectStorageBuffer") { 40022 const sharedData = this.getSharedDataFromNode(node); 40023 let buffer3 = sharedData.buffer; 40024 if (buffer3 === void 0) { 40025 const bufferClass = type === "buffer" ? NodeUniformBuffer : NodeStorageBuffer; 40026 buffer3 = new bufferClass(node, group); 40027 sharedData.buffer = buffer3; 40028 } 40029 buffer3.setVisibility(buffer3.getVisibility() | gpuShaderStageLib[shaderStage]); 40030 bindings.push(buffer3); 40031 uniformGPU = buffer3; 40032 uniformNode.name = name ? name : "NodeBuffer_" + uniformNode.id; 40033 } else { 40034 let uniformsGroup = this.uniformGroups[groupName]; 40035 if (uniformsGroup === void 0) { 40036 uniformsGroup = new NodeUniformsGroup(groupName, group); 40037 uniformsGroup.setVisibility(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE); 40038 this.uniformGroups[groupName] = uniformsGroup; 40039 } 40040 if (bindings.indexOf(uniformsGroup) === -1) { 40041 bindings.push(uniformsGroup); 40042 } 40043 uniformGPU = this.getNodeUniform(uniformNode, type); 40044 const uniformName = uniformGPU.name; 40045 const alreadyExists = uniformsGroup.uniforms.some((u) => u.name === uniformName); 40046 if (!alreadyExists) { 40047 uniformsGroup.addUniform(uniformGPU); 40048 } 40049 } 40050 nodeData.uniformGPU = uniformGPU; 40051 } 40052 return uniformNode; 40053 } 40054 /** 40055 * This method should be used whenever builtins are required in nodes. 40056 * The internal builtins data structure will make sure builtins are 40057 * defined in the WGSL source. 40058 * 40059 * @param {string} name - The builtin name. 40060 * @param {string} property - The property name. 40061 * @param {string} type - The node data type. 40062 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 40063 * @return {string} The property name. 40064 */ 40065 getBuiltin(name, property3, type, shaderStage = this.shaderStage) { 40066 const map = this.builtins[shaderStage] || (this.builtins[shaderStage] = /* @__PURE__ */ new Map()); 40067 if (map.has(name) === false) { 40068 map.set(name, { 40069 name, 40070 property: property3, 40071 type 40072 }); 40073 } 40074 return property3; 40075 } 40076 /** 40077 * Returns `true` if the given builtin is defined in the given shader stage. 40078 * 40079 * @param {string} name - The builtin name. 40080 * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. 40081 * @return {boolean} Whether the given builtin is defined in the given shader stage or not. 40082 */ 40083 hasBuiltin(name, shaderStage = this.shaderStage) { 40084 return this.builtins[shaderStage] !== void 0 && this.builtins[shaderStage].has(name); 40085 } 40086 /** 40087 * Returns the vertex index builtin. 40088 * 40089 * @return {string} The vertex index. 40090 */ 40091 getVertexIndex() { 40092 if (this.shaderStage === "vertex") { 40093 return this.getBuiltin("vertex_index", "vertexIndex", "u32", "attribute"); 40094 } 40095 return "vertexIndex"; 40096 } 40097 /** 40098 * Builds the given shader node. 40099 * 40100 * @param {ShaderNodeInternal} shaderNode - The shader node. 40101 * @return {string} The WGSL function code. 40102 */ 40103 buildFunctionCode(shaderNode) { 40104 const layout = shaderNode.layout; 40105 const flowData = this.flowShaderNode(shaderNode); 40106 const parameters = []; 40107 for (const input of layout.inputs) { 40108 parameters.push(input.name + " : " + this.getType(input.type)); 40109 } 40110 let code3 = `fn ${layout.name}( ${parameters.join(", ")} ) -> ${this.getType(layout.type)} { 40111${flowData.vars} 40112${flowData.code} 40113`; 40114 if (flowData.result) { 40115 code3 += ` return ${flowData.result}; 40116`; 40117 } 40118 code3 += "\n}\n"; 40119 return code3; 40120 } 40121 /** 40122 * Contextually returns either the vertex stage instance index builtin 40123 * or the linearized index of an compute invocation within a grid of workgroups. 40124 * 40125 * @return {string} The instance index. 40126 */ 40127 getInstanceIndex() { 40128 if (this.shaderStage === "vertex") { 40129 return this.getBuiltin("instance_index", "instanceIndex", "u32", "attribute"); 40130 } 40131 return "instanceIndex"; 40132 } 40133 /** 40134 * Returns a builtin representing the index of a compute invocation within the scope of a workgroup load. 40135 * 40136 * @return {string} The invocation local index. 40137 */ 40138 getInvocationLocalIndex() { 40139 return this.getBuiltin("local_invocation_index", "invocationLocalIndex", "u32", "attribute"); 40140 } 40141 /** 40142 * Returns a builtin representing the size of a subgroup within the current shader. 40143 * 40144 * @return {string} The subgroup size. 40145 */ 40146 getSubgroupSize() { 40147 this.enableSubGroups(); 40148 return this.getBuiltin("subgroup_size", "subgroupSize", "u32", "attribute"); 40149 } 40150 /** 40151 * Returns a builtin representing the index of a compute invocation within the scope of a subgroup. 40152 * 40153 * @return {string} The invocation subgroup index. 40154 */ 40155 getInvocationSubgroupIndex() { 40156 this.enableSubGroups(); 40157 return this.getBuiltin("subgroup_invocation_id", "invocationSubgroupIndex", "u32", "attribute"); 40158 } 40159 /** 40160 * Returns a builtin representing the index of a compute invocation's subgroup within its workgroup. 40161 * 40162 * @return {string} The subgroup index. 40163 */ 40164 getSubgroupIndex() { 40165 this.enableSubGroups(); 40166 return this.getBuiltin("subgroup_id", "subgroupIndex", "u32", "attribute"); 40167 } 40168 /** 40169 * Overwritten as a NOP since this method is intended for the WebGL 2 backend. 40170 * 40171 * @return {null} Null. 40172 */ 40173 getDrawIndex() { 40174 return null; 40175 } 40176 /** 40177 * Returns the front facing builtin. 40178 * 40179 * @return {string} The front facing builtin. 40180 */ 40181 getFrontFacing() { 40182 return this.getBuiltin("front_facing", "isFront", "bool"); 40183 } 40184 /** 40185 * Returns the frag coord builtin. 40186 * 40187 * @return {string} The frag coord builtin. 40188 */ 40189 getFragCoord() { 40190 return this.getBuiltin("position", "fragCoord", "vec4<f32>") + ".xy"; 40191 } 40192 /** 40193 * Returns the frag depth builtin. 40194 * 40195 * @return {string} The frag depth builtin. 40196 */ 40197 getFragDepth() { 40198 return "output." + this.getBuiltin("frag_depth", "depth", "f32", "output"); 40199 } 40200 /** 40201 * Returns the clip distances builtin. 40202 * 40203 * @return {string} The clip distances builtin. 40204 */ 40205 getClipDistance() { 40206 return "varyings.hw_clip_distances"; 40207 } 40208 /** 40209 * Whether to flip texture data along its vertical axis or not. 40210 * 40211 * @return {boolean} Returns always `false` in context of WGSL. 40212 */ 40213 isFlipY() { 40214 return false; 40215 } 40216 /** 40217 * Enables the given directive for the given shader stage. 40218 * 40219 * @param {string} name - The directive name. 40220 * @param {string} [shaderStage=this.shaderStage] - The shader stage to enable the directive for. 40221 */ 40222 enableDirective(name, shaderStage = this.shaderStage) { 40223 const stage = this.directives[shaderStage] || (this.directives[shaderStage] = /* @__PURE__ */ new Set()); 40224 stage.add(name); 40225 } 40226 /** 40227 * Returns the directives of the given shader stage as a WGSL string. 40228 * 40229 * @param {string} shaderStage - The shader stage. 40230 * @return {string} A WGSL snippet that enables the directives of the given stage. 40231 */ 40232 getDirectives(shaderStage) { 40233 const snippets = []; 40234 const directives = this.directives[shaderStage]; 40235 if (directives !== void 0) { 40236 for (const directive of directives) { 40237 snippets.push(`enable ${directive};`); 40238 } 40239 } 40240 return snippets.join("\n"); 40241 } 40242 /** 40243 * Enables the 'subgroups' directive. 40244 */ 40245 enableSubGroups() { 40246 this.enableDirective("subgroups"); 40247 } 40248 /** 40249 * Enables the 'subgroups-f16' directive. 40250 */ 40251 enableSubgroupsF16() { 40252 this.enableDirective("subgroups-f16"); 40253 } 40254 /** 40255 * Enables the 'clip_distances' directive. 40256 */ 40257 enableClipDistances() { 40258 this.enableDirective("clip_distances"); 40259 } 40260 /** 40261 * Enables the 'f16' directive. 40262 */ 40263 enableShaderF16() { 40264 this.enableDirective("f16"); 40265 } 40266 /** 40267 * Enables the 'dual_source_blending' directive. 40268 */ 40269 enableDualSourceBlending() { 40270 this.enableDirective("dual_source_blending"); 40271 } 40272 /** 40273 * Enables hardware clipping. 40274 * 40275 * @param {string} planeCount - The clipping plane count. 40276 */ 40277 enableHardwareClipping(planeCount) { 40278 this.enableClipDistances(); 40279 this.getBuiltin("clip_distances", "hw_clip_distances", `array<f32, ${planeCount} >`, "vertex"); 40280 } 40281 /** 40282 * Returns the builtins of the given shader stage as a WGSL string. 40283 * 40284 * @param {string} shaderStage - The shader stage. 40285 * @return {string} A WGSL snippet that represents the builtins of the given stage. 40286 */ 40287 getBuiltins(shaderStage) { 40288 const snippets = []; 40289 const builtins = this.builtins[shaderStage]; 40290 if (builtins !== void 0) { 40291 for (const { name, property: property3, type } of builtins.values()) { 40292 snippets.push(`@builtin( ${name} ) ${property3} : ${type}`); 40293 } 40294 } 40295 return snippets.join(",\n "); 40296 } 40297 /** 40298 * This method should be used when a new scoped buffer is used in context of 40299 * compute shaders. It adds the array to the internal data structure which is 40300 * later used to generate the respective WGSL. 40301 * 40302 * @param {string} name - The array name. 40303 * @param {string} scope - The scope. 40304 * @param {string} bufferType - The buffer type. 40305 * @param {string} bufferCount - The buffer count. 40306 * @return {string} The array name. 40307 */ 40308 getScopedArray(name, scope, bufferType, bufferCount) { 40309 if (this.scopedArrays.has(name) === false) { 40310 this.scopedArrays.set(name, { 40311 name, 40312 scope, 40313 bufferType, 40314 bufferCount 40315 }); 40316 } 40317 return name; 40318 } 40319 /** 40320 * Returns the scoped arrays of the given shader stage as a WGSL string. 40321 * 40322 * @param {string} shaderStage - The shader stage. 40323 * @return {string|undefined} The WGSL snippet that defines the scoped arrays. 40324 * Returns `undefined` when used in the vertex or fragment stage. 40325 */ 40326 getScopedArrays(shaderStage) { 40327 if (shaderStage !== "compute") { 40328 return; 40329 } 40330 const snippets = []; 40331 for (const { name, scope, bufferType, bufferCount } of this.scopedArrays.values()) { 40332 const type = this.getType(bufferType); 40333 snippets.push(`var<${scope}> ${name}: array< ${type}, ${bufferCount} >;`); 40334 } 40335 return snippets.join("\n"); 40336 } 40337 /** 40338 * Returns the shader attributes of the given shader stage as a WGSL string. 40339 * 40340 * @param {string} shaderStage - The shader stage. 40341 * @return {string} The WGSL snippet that defines the shader attributes. 40342 */ 40343 getAttributes(shaderStage) { 40344 const snippets = []; 40345 if (shaderStage === "compute") { 40346 this.getBuiltin("global_invocation_id", "globalId", "vec3<u32>", "attribute"); 40347 this.getBuiltin("workgroup_id", "workgroupId", "vec3<u32>", "attribute"); 40348 this.getBuiltin("local_invocation_id", "localId", "vec3<u32>", "attribute"); 40349 this.getBuiltin("num_workgroups", "numWorkgroups", "vec3<u32>", "attribute"); 40350 if (this.renderer.hasFeature("subgroups")) { 40351 this.enableDirective("subgroups", shaderStage); 40352 this.getBuiltin("subgroup_size", "subgroupSize", "u32", "attribute"); 40353 } 40354 } 40355 if (shaderStage === "vertex" || shaderStage === "compute") { 40356 const builtins = this.getBuiltins("attribute"); 40357 if (builtins) snippets.push(builtins); 40358 const attributes = this.getAttributesArray(); 40359 for (let index = 0, length3 = attributes.length; index < length3; index++) { 40360 const attribute3 = attributes[index]; 40361 const name = attribute3.name; 40362 const type = this.getType(attribute3.type); 40363 snippets.push(`@location( ${index} ) ${name} : ${type}`); 40364 } 40365 } 40366 return snippets.join(",\n "); 40367 } 40368 /** 40369 * Returns the members of the given struct type node as a WGSL string. 40370 * 40371 * @param {StructTypeNode} struct - The struct type node. 40372 * @return {string} The WGSL snippet that defines the struct members. 40373 */ 40374 getStructMembers(struct3) { 40375 const snippets = []; 40376 for (const member of struct3.members) { 40377 const prefix = struct3.output ? "@location( " + member.index + " ) " : ""; 40378 let type = this.getType(member.type); 40379 if (member.atomic) { 40380 type = "atomic< " + type + " >"; 40381 } 40382 snippets.push(` ${prefix + member.name} : ${type}`); 40383 } 40384 if (struct3.output) { 40385 snippets.push(` ${this.getBuiltins("output")}`); 40386 } 40387 return snippets.join(",\n"); 40388 } 40389 /** 40390 * Returns the structs of the given shader stage as a WGSL string. 40391 * 40392 * @param {string} shaderStage - The shader stage. 40393 * @return {string} The WGSL snippet that defines the structs. 40394 */ 40395 getStructs(shaderStage) { 40396 let result = ""; 40397 const structs = this.structs[shaderStage]; 40398 if (structs.length > 0) { 40399 const snippets = []; 40400 for (const struct3 of structs) { 40401 let snippet = `struct ${struct3.name} { 40402`; 40403 snippet += this.getStructMembers(struct3); 40404 snippet += "\n};"; 40405 snippets.push(snippet); 40406 } 40407 result = "\n" + snippets.join("\n\n") + "\n"; 40408 } 40409 return result; 40410 } 40411 /** 40412 * Returns a WGSL string representing a variable. 40413 * 40414 * @param {string} type - The variable's type. 40415 * @param {string} name - The variable's name. 40416 * @param {?number} [count=null] - The array length. 40417 * @param {string} [qualifier=''] - The variable's qualifier. 40418 * @return {string} The WGSL snippet that defines a variable. 40419 */ 40420 getVar(type, name, count = null, qualifier = "") { 40421 let snippet = `var${qualifier} ${name} : `; 40422 if (count !== null) { 40423 snippet += this.generateArrayDeclaration(type, count); 40424 } else { 40425 snippet += this.getType(type); 40426 } 40427 return snippet; 40428 } 40429 /** 40430 * Returns the variables of the given shader stage as a WGSL string. 40431 * 40432 * @param {string} shaderStage - The shader stage. 40433 * @return {string} The WGSL snippet that defines the variables. 40434 */ 40435 getVars(shaderStage, global = false) { 40436 let qualifier = ""; 40437 if (global) { 40438 qualifier = "<private>"; 40439 } 40440 const snippets = []; 40441 const vars = this.vars[shaderStage]; 40442 if (vars !== void 0) { 40443 for (const variable of vars) { 40444 snippets.push(`${this.getVar(variable.type, variable.name, variable.count, qualifier)};`); 40445 } 40446 } 40447 return global ? snippets.join("\n") : ` 40448 ${snippets.join("\n ")} 40449`; 40450 } 40451 /** 40452 * Returns the varyings of the given shader stage as a WGSL string. 40453 * 40454 * @param {string} shaderStage - The shader stage. 40455 * @return {string} The WGSL snippet that defines the varyings. 40456 */ 40457 getVaryings(shaderStage) { 40458 const snippets = []; 40459 if (shaderStage === "vertex") { 40460 this.getBuiltin("position", "builtinClipSpace", "vec4<f32>", "vertex"); 40461 } 40462 if (shaderStage === "vertex" || shaderStage === "fragment") { 40463 const varyings = this.varyings; 40464 const vars = this.vars[shaderStage]; 40465 let varyingIndex = 0; 40466 for (let index = 0; index < varyings.length; index++) { 40467 const varying3 = varyings[index]; 40468 if (varying3.needsInterpolation) { 40469 let attributesSnippet = `@location( ${varyingIndex++} )`; 40470 if (varying3.interpolationType) { 40471 const samplingSnippet = varying3.interpolationSampling !== null ? `, ${varying3.interpolationSampling} )` : " )"; 40472 attributesSnippet += ` @interpolate( ${varying3.interpolationType}${samplingSnippet}`; 40473 } else if (/^(int|uint|ivec|uvec)/.test(varying3.type)) { 40474 attributesSnippet += " @interpolate(flat, either)"; 40475 } 40476 snippets.push(`${attributesSnippet} ${varying3.name} : ${this.getType(varying3.type)}`); 40477 } else if (shaderStage === "vertex" && vars.includes(varying3) === false) { 40478 vars.push(varying3); 40479 } 40480 } 40481 } 40482 const builtins = this.getBuiltins(shaderStage); 40483 if (builtins) snippets.push(builtins); 40484 const code3 = snippets.join(",\n "); 40485 return shaderStage === "vertex" ? this._getWGSLStruct("VaryingsStruct", " " + code3) : code3; 40486 } 40487 isCustomStruct(nodeUniform) { 40488 const attribute3 = nodeUniform.value; 40489 const bufferNode = nodeUniform.node; 40490 const isAttributeStructType = (attribute3.isBufferAttribute || attribute3.isInstancedBufferAttribute) && bufferNode.structTypeNode !== null; 40491 const isStructArray = bufferNode.value && bufferNode.value.array && (typeof bufferNode.value.itemSize === "number" && bufferNode.value.array.length > bufferNode.value.itemSize); 40492 return isAttributeStructType && !isStructArray; 40493 } 40494 /** 40495 * Returns the uniforms of the given shader stage as a WGSL string. 40496 * 40497 * @param {string} shaderStage - The shader stage. 40498 * @return {string} The WGSL snippet that defines the uniforms. 40499 */ 40500 getUniforms(shaderStage) { 40501 const backend = this.renderer.backend; 40502 const uniforms = this.uniforms[shaderStage]; 40503 const bindingSnippets = []; 40504 const bufferSnippets = []; 40505 const structSnippets = []; 40506 const uniformGroups = {}; 40507 for (const uniform3 of uniforms) { 40508 const groupName = uniform3.groupNode.name; 40509 const uniformIndexes = this.bindingsIndexes[groupName]; 40510 if (uniform3.type === "texture" || uniform3.type === "cubeTexture" || uniform3.type === "cubeDepthTexture" || uniform3.type === "storageTexture" || uniform3.type === "texture3D") { 40511 const texture3 = uniform3.node.value; 40512 const needsSampler = texture3.isCubeTexture === true || this.isUnfilterable(texture3) === false && uniform3.node.isStorageTextureNode !== true; 40513 if (needsSampler) { 40514 if (this.isSampleCompare(texture3)) { 40515 bindingSnippets.push(`@binding( ${uniformIndexes.binding++} ) @group( ${uniformIndexes.group} ) var ${uniform3.name}_sampler : sampler_comparison;`); 40516 } else { 40517 bindingSnippets.push(`@binding( ${uniformIndexes.binding++} ) @group( ${uniformIndexes.group} ) var ${uniform3.name}_sampler : sampler;`); 40518 } 40519 } 40520 let textureType; 40521 let multisampled = ""; 40522 const { primarySamples } = backend.utils.getTextureSampleData(texture3); 40523 if (primarySamples > 1) { 40524 multisampled = "_multisampled"; 40525 } 40526 if (texture3.isCubeTexture === true && texture3.isDepthTexture === true) { 40527 textureType = "texture_depth_cube"; 40528 } else if (texture3.isCubeTexture === true) { 40529 textureType = "texture_cube<f32>"; 40530 } else if (texture3.isDepthTexture === true) { 40531 if (backend.compatibilityMode && texture3.compareFunction === null) { 40532 textureType = `texture${multisampled}_2d<f32>`; 40533 } else { 40534 textureType = `texture_depth${multisampled}_2d${texture3.isArrayTexture === true ? "_array" : ""}`; 40535 } 40536 } else if (uniform3.node.isStorageTextureNode === true) { 40537 const format = getFormat(texture3, backend.device); 40538 const access6 = this.getStorageAccess(uniform3.node, shaderStage); 40539 const is3D = uniform3.node.value.is3DTexture; 40540 const isArrayTexture = uniform3.node.value.isArrayTexture; 40541 const dimension = is3D ? "3d" : `2d${isArrayTexture ? "_array" : ""}`; 40542 textureType = `texture_storage_${dimension}<${format}, ${access6}>`; 40543 } else if (texture3.isArrayTexture === true || texture3.isDataArrayTexture === true || texture3.isCompressedArrayTexture === true) { 40544 textureType = "texture_2d_array<f32>"; 40545 } else if (texture3.is3DTexture === true || texture3.isData3DTexture === true) { 40546 textureType = "texture_3d<f32>"; 40547 } else { 40548 const componentPrefix = this.getComponentTypeFromTexture(texture3).charAt(0); 40549 textureType = `texture${multisampled}_2d<${componentPrefix}32>`; 40550 } 40551 bindingSnippets.push(`@binding( ${uniformIndexes.binding++} ) @group( ${uniformIndexes.group} ) var ${uniform3.name} : ${textureType};`); 40552 } else if (uniform3.type === "buffer" || uniform3.type === "storageBuffer" || uniform3.type === "indirectStorageBuffer") { 40553 const bufferNode = uniform3.node; 40554 const bufferType = this.getType(bufferNode.getNodeType(this)); 40555 const bufferCount = bufferNode.bufferCount; 40556 const bufferCountSnippet = bufferCount > 0 && uniform3.type === "buffer" ? ", " + bufferCount : ""; 40557 const bufferAccessMode = bufferNode.isStorageBufferNode ? `storage, ${this.getStorageAccess(bufferNode, shaderStage)}` : "uniform"; 40558 if (this.isCustomStruct(uniform3)) { 40559 bufferSnippets.push(`@binding( ${uniformIndexes.binding++} ) @group( ${uniformIndexes.group} ) var<${bufferAccessMode}> ${uniform3.name} : ${bufferType};`); 40560 } else { 40561 const bufferTypeSnippet = bufferNode.isAtomic ? `atomic<${bufferType}>` : `${bufferType}`; 40562 const bufferSnippet = ` value : array< ${bufferTypeSnippet}${bufferCountSnippet} >`; 40563 bufferSnippets.push(this._getWGSLStructBinding(uniform3.name, bufferSnippet, bufferAccessMode, uniformIndexes.binding++, uniformIndexes.group)); 40564 } 40565 } else { 40566 const groupName2 = uniform3.groupNode.name; 40567 if (uniformGroups[groupName2] === void 0) { 40568 const sharedUniformGroup3 = this.uniformGroups[groupName2]; 40569 if (sharedUniformGroup3 !== void 0) { 40570 const snippets = []; 40571 for (const sharedUniform of sharedUniformGroup3.uniforms) { 40572 const type = sharedUniform.getType(); 40573 const vectorType = this.getType(this.getVectorType(type)); 40574 snippets.push(` ${sharedUniform.name} : ${vectorType}`); 40575 } 40576 let groupBinding = this.uniformGroupsBindings[groupName2]; 40577 if (groupBinding === void 0) { 40578 groupBinding = { 40579 index: uniformIndexes.binding++, 40580 id: uniformIndexes.group 40581 }; 40582 this.uniformGroupsBindings[groupName2] = groupBinding; 40583 } 40584 uniformGroups[groupName2] = { 40585 index: groupBinding.index, 40586 id: groupBinding.id, 40587 snippets 40588 }; 40589 } 40590 } 40591 } 40592 } 40593 for (const name in uniformGroups) { 40594 const group = uniformGroups[name]; 40595 structSnippets.push(this._getWGSLStructBinding(name, group.snippets.join(",\n"), "uniform", group.index, group.id)); 40596 } 40597 const code3 = [...bindingSnippets, ...bufferSnippets, ...structSnippets].join("\n"); 40598 return code3; 40599 } 40600 /** 40601 * Controls the code build of the shader stages. 40602 */ 40603 buildCode() { 40604 const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; 40605 this.sortBindingGroups(); 40606 for (const shaderStage in shadersData) { 40607 this.shaderStage = shaderStage; 40608 const allowGlobal = this.allowGlobalVariables; 40609 const stageData = shadersData[shaderStage]; 40610 stageData.uniforms = this.getUniforms(shaderStage); 40611 stageData.attributes = this.getAttributes(shaderStage); 40612 stageData.varyings = this.getVaryings(shaderStage); 40613 stageData.structs = this.getStructs(shaderStage); 40614 stageData.vars = this.getVars(shaderStage, allowGlobal); 40615 stageData.codes = this.getCodes(shaderStage); 40616 stageData.directives = this.getDirectives(shaderStage); 40617 stageData.scopedArrays = this.getScopedArrays(shaderStage); 40618 let flow = "// code\n\n"; 40619 flow += this.flowCode[shaderStage]; 40620 const flowNodes = this.flowNodes[shaderStage]; 40621 const mainNode = flowNodes[flowNodes.length - 1]; 40622 const outputNode = mainNode.outputNode; 40623 const isOutputStruct = outputNode !== void 0 && outputNode.isOutputStructNode === true; 40624 for (const node of flowNodes) { 40625 const flowSlotData = this.getFlowData( 40626 node 40627 /*, shaderStage*/ 40628 ); 40629 const slotName = node.name; 40630 if (slotName) { 40631 if (flow.length > 0) flow += "\n"; 40632 flow += ` // flow -> ${slotName} 40633`; 40634 } 40635 flow += `${flowSlotData.code} 40636 `; 40637 if (node === mainNode && shaderStage !== "compute") { 40638 flow += "// result\n\n "; 40639 if (shaderStage === "vertex") { 40640 flow += `varyings.builtinClipSpace = ${flowSlotData.result};`; 40641 } else if (shaderStage === "fragment") { 40642 if (isOutputStruct) { 40643 stageData.returnType = outputNode.getNodeType(this); 40644 stageData.structs += "var<private> output : " + stageData.returnType + ";"; 40645 flow += `return ${flowSlotData.result};`; 40646 } else { 40647 let structSnippet = " @location( 0 ) color: vec4<f32>"; 40648 const builtins = this.getBuiltins("output"); 40649 if (builtins) structSnippet += ",\n " + builtins; 40650 stageData.returnType = "OutputStruct"; 40651 stageData.structs += this._getWGSLStruct("OutputStruct", structSnippet); 40652 stageData.structs += "\nvar<private> output : OutputStruct;"; 40653 flow += `output.color = ${flowSlotData.result}; 40654 40655 return output;`; 40656 } 40657 } 40658 } 40659 } 40660 stageData.flow = flow; 40661 } 40662 this.shaderStage = null; 40663 if (this.material !== null) { 40664 this.vertexShader = this._getWGSLVertexCode(shadersData.vertex); 40665 this.fragmentShader = this._getWGSLFragmentCode(shadersData.fragment); 40666 } else { 40667 const workgroupSize = this.object.workgroupSize; 40668 this.computeShader = this._getWGSLComputeCode(shadersData.compute, workgroupSize); 40669 } 40670 } 40671 /** 40672 * Returns the native shader method name for a given generic name. 40673 * 40674 * @param {string} method - The method name to resolve. 40675 * @param {?string} [output=null] - An optional output. 40676 * @return {string} The resolved WGSL method name. 40677 */ 40678 getMethod(method, output3 = null) { 40679 let wgslMethod; 40680 if (output3 !== null) { 40681 wgslMethod = this._getWGSLMethod(method + "_" + output3); 40682 } 40683 if (wgslMethod === void 0) { 40684 wgslMethod = this._getWGSLMethod(method); 40685 } 40686 return wgslMethod || method; 40687 } 40688 /** 40689 * Returns the bitcast method name for a given input and outputType. 40690 * 40691 * @param {string} type - The output type to bitcast to. 40692 * @return {string} The resolved WGSL bitcast invocation. 40693 */ 40694 getBitcastMethod(type) { 40695 const dataType = this.getType(type); 40696 return `bitcast<${dataType}>`; 40697 } 40698 /** 40699 * Returns the float packing method name for a given numeric encoding. 40700 * 40701 * @param {string} encoding - The numeric encoding that describes how the float values are mapped to the integer range. 40702 * @returns {string} The resolve WGSL float packing method name. 40703 */ 40704 getFloatPackingMethod(encoding) { 40705 return this.getMethod(`floatpack_${encoding}_2x16`); 40706 } 40707 /** 40708 * Returns the float unpacking method name for a given numeric encoding. 40709 * 40710 * @param {string} encoding - The numeric encoding that describes how the integer values are mapped to the float range. 40711 * @returns {string} The resolve WGSL float unpacking method name. 40712 */ 40713 getFloatUnpackingMethod(encoding) { 40714 return this.getMethod(`floatunpack_${encoding}_2x16`); 40715 } 40716 /** 40717 * Returns the native snippet for a ternary operation. 40718 * 40719 * @param {string} condSnippet - The condition determining which expression gets resolved. 40720 * @param {string} ifSnippet - The expression to resolve to if the condition is true. 40721 * @param {string} elseSnippet - The expression to resolve to if the condition is false. 40722 * @return {string} The resolved method name. 40723 */ 40724 getTernary(condSnippet, ifSnippet, elseSnippet) { 40725 return `select( ${elseSnippet}, ${ifSnippet}, ${condSnippet} )`; 40726 } 40727 /** 40728 * Returns the WGSL type of the given node data type. 40729 * 40730 * @param {string} type - The node data type. 40731 * @return {string} The WGSL type. 40732 */ 40733 getType(type) { 40734 return wgslTypeLib[type] || type; 40735 } 40736 /** 40737 * Whether the requested feature is available or not. 40738 * 40739 * @param {string} name - The requested feature. 40740 * @return {boolean} Whether the requested feature is supported or not. 40741 */ 40742 isAvailable(name) { 40743 let result = supports[name]; 40744 if (result === void 0) { 40745 if (name === "float32Filterable") { 40746 result = this.renderer.hasFeature("float32-filterable"); 40747 } else if (name === "clipDistance") { 40748 result = this.renderer.hasFeature("clip-distances"); 40749 } 40750 supports[name] = result; 40751 } 40752 return result; 40753 } 40754 /** 40755 * Returns the native shader method name for a given generic name. 40756 * 40757 * @private 40758 * @param {string} method - The method name to resolve. 40759 * @return {string} The resolved WGSL method name. 40760 */ 40761 _getWGSLMethod(method) { 40762 if (wgslPolyfill[method] !== void 0) { 40763 this._include(method); 40764 } 40765 return wgslMethods[method]; 40766 } 40767 /** 40768 * Includes the given method name into the current 40769 * function node. 40770 * 40771 * @private 40772 * @param {string} name - The method name to include. 40773 * @return {CodeNode} The respective code node. 40774 */ 40775 _include(name) { 40776 const codeNode = wgslPolyfill[name]; 40777 codeNode.build(this); 40778 this.addInclude(codeNode); 40779 return codeNode; 40780 } 40781 /** 40782 * Returns a WGSL vertex shader based on the given shader data. 40783 * 40784 * @private 40785 * @param {Object} shaderData - The shader data. 40786 * @return {string} The vertex shader. 40787 */ 40788 _getWGSLVertexCode(shaderData) { 40789 return `${this.getSignature()} 40790// directives 40791${shaderData.directives} 40792 40793// structs 40794${shaderData.structs} 40795 40796// uniforms 40797${shaderData.uniforms} 40798 40799// varyings 40800${shaderData.varyings} 40801var<private> varyings : VaryingsStruct; 40802 40803// vars 40804${shaderData.vars} 40805 40806// codes 40807${shaderData.codes} 40808 40809@vertex 40810fn main( ${shaderData.attributes} ) -> VaryingsStruct { 40811 40812 // flow 40813 ${shaderData.flow} 40814 40815 return varyings; 40816 40817} 40818`; 40819 } 40820 /** 40821 * Returns a WGSL fragment shader based on the given shader data. 40822 * 40823 * @private 40824 * @param {Object} shaderData - The shader data. 40825 * @return {string} The vertex shader. 40826 */ 40827 _getWGSLFragmentCode(shaderData) { 40828 return `${this.getSignature()} 40829// global 40830${diagnostics} 40831 40832// structs 40833${shaderData.structs} 40834 40835// uniforms 40836${shaderData.uniforms} 40837 40838// vars 40839${shaderData.vars} 40840 40841// codes 40842${shaderData.codes} 40843 40844@fragment 40845fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} { 40846 40847 // flow 40848 ${shaderData.flow} 40849 40850} 40851`; 40852 } 40853 /** 40854 * Returns a WGSL compute shader based on the given shader data. 40855 * 40856 * @private 40857 * @param {Object} shaderData - The shader data. 40858 * @param {string} workgroupSize - The workgroup size. 40859 * @return {string} The vertex shader. 40860 */ 40861 _getWGSLComputeCode(shaderData, workgroupSize) { 40862 const [workgroupSizeX, workgroupSizeY, workgroupSizeZ] = workgroupSize; 40863 return `${this.getSignature()} 40864// directives 40865${shaderData.directives} 40866 40867// system 40868var<private> instanceIndex : u32; 40869 40870// locals 40871${shaderData.scopedArrays} 40872 40873// structs 40874${shaderData.structs} 40875 40876// uniforms 40877${shaderData.uniforms} 40878 40879// vars 40880${this.allowGlobalVariables ? shaderData.vars : ""} 40881 40882// codes 40883${shaderData.codes} 40884 40885@compute @workgroup_size( ${workgroupSizeX}, ${workgroupSizeY}, ${workgroupSizeZ} ) 40886fn main( ${shaderData.attributes} ) { 40887 40888 // local vars 40889 ${this.allowGlobalVariables ? "" : shaderData.vars} 40890 40891 // system 40892 instanceIndex = globalId.x 40893 + globalId.y * ( ${workgroupSizeX} * numWorkgroups.x ) 40894 + globalId.z * ( ${workgroupSizeX} * numWorkgroups.x ) * ( ${workgroupSizeY} * numWorkgroups.y ); 40895 40896 // flow 40897 ${shaderData.flow} 40898 40899} 40900`; 40901 } 40902 /** 40903 * Returns a WGSL struct based on the given name and variables. 40904 * 40905 * @private 40906 * @param {string} name - The struct name. 40907 * @param {string} vars - The struct variables. 40908 * @return {string} The WGSL snippet representing a struct. 40909 */ 40910 _getWGSLStruct(name, vars) { 40911 return ` 40912struct ${name} { 40913${vars} 40914};`; 40915 } 40916 /** 40917 * Returns a WGSL struct binding. 40918 * 40919 * @private 40920 * @param {string} name - The struct name. 40921 * @param {string} vars - The struct variables. 40922 * @param {string} access - The access. 40923 * @param {number} [binding=0] - The binding index. 40924 * @param {number} [group=0] - The group index. 40925 * @return {string} The WGSL snippet representing a struct binding. 40926 */ 40927 _getWGSLStructBinding(name, vars, access6, binding = 0, group = 0) { 40928 const structName = name + "Struct"; 40929 const structSnippet = this._getWGSLStruct(structName, vars); 40930 return `${structSnippet} 40931@binding( ${binding} ) @group( ${group} ) 40932var<${access6}> ${name} : ${structName};`; 40933 } 40934}; 40935var WebGPUUtils = class { 40936 /** 40937 * Constructs a new utility object. 40938 * 40939 * @param {WebGPUBackend} backend - The WebGPU backend. 40940 */ 40941 constructor(backend) { 40942 this.backend = backend; 40943 } 40944 /** 40945 * Returns the depth/stencil GPU format for the given render context. 40946 * 40947 * @param {RenderContext} renderContext - The render context. 40948 * @return {string} The depth/stencil GPU texture format. 40949 */ 40950 getCurrentDepthStencilFormat(renderContext) { 40951 let format; 40952 if (renderContext.depth) { 40953 if (renderContext.depthTexture !== null) { 40954 format = this.getTextureFormatGPU(renderContext.depthTexture); 40955 } else if (renderContext.stencil) { 40956 if (this.backend.renderer.reversedDepthBuffer === true) { 40957 format = GPUTextureFormat.Depth32FloatStencil8; 40958 } else { 40959 format = GPUTextureFormat.Depth24PlusStencil8; 40960 } 40961 } else { 40962 if (this.backend.renderer.reversedDepthBuffer === true) { 40963 format = GPUTextureFormat.Depth32Float; 40964 } else { 40965 format = GPUTextureFormat.Depth24Plus; 40966 } 40967 } 40968 } 40969 return format; 40970 } 40971 /** 40972 * Returns the GPU format for the given texture. 40973 * 40974 * @param {Texture} texture - The texture. 40975 * @return {string} The GPU texture format. 40976 */ 40977 getTextureFormatGPU(texture3) { 40978 return this.backend.get(texture3).format; 40979 } 40980 /** 40981 * Returns an object that defines the multi-sampling state of the given texture. 40982 * 40983 * @param {Texture} texture - The texture. 40984 * @return {Object} The multi-sampling state. 40985 */ 40986 getTextureSampleData(texture3) { 40987 let samples; 40988 if (texture3.isFramebufferTexture) { 40989 samples = 1; 40990 } else if (texture3.isDepthTexture && !texture3.renderTarget) { 40991 const renderer = this.backend.renderer; 40992 const renderTarget = renderer.getRenderTarget(); 40993 samples = renderTarget ? renderTarget.samples : renderer.currentSamples; 40994 } else if (texture3.renderTarget) { 40995 samples = texture3.renderTarget.samples; 40996 } 40997 samples = samples || 1; 40998 const isMSAA = samples > 1 && texture3.renderTarget !== null && (texture3.isDepthTexture !== true && texture3.isFramebufferTexture !== true); 40999 const primarySamples = isMSAA ? 1 : samples; 41000 return { samples, primarySamples, isMSAA }; 41001 } 41002 /** 41003 * Returns the default color attachment's GPU format of the current render context. 41004 * 41005 * @param {RenderContext} renderContext - The render context. 41006 * @return {string} The GPU texture format of the default color attachment. 41007 */ 41008 getCurrentColorFormat(renderContext) { 41009 let format; 41010 if (renderContext.textures !== null) { 41011 format = this.getTextureFormatGPU(renderContext.textures[0]); 41012 } else { 41013 format = this.getPreferredCanvasFormat(); 41014 } 41015 return format; 41016 } 41017 /** 41018 * Returns the GPU formats of all color attachments of the current render context. 41019 * 41020 * @param {RenderContext} renderContext - The render context. 41021 * @return {Array<string>} The GPU texture formats of all color attachments. 41022 */ 41023 getCurrentColorFormats(renderContext) { 41024 if (renderContext.textures !== null) { 41025 return renderContext.textures.map((t) => this.getTextureFormatGPU(t)); 41026 } else { 41027 return [this.getPreferredCanvasFormat()]; 41028 } 41029 } 41030 /** 41031 * Returns the output color space of the current render context. 41032 * 41033 * @param {RenderContext} renderContext - The render context. 41034 * @return {string} The output color space. 41035 */ 41036 getCurrentColorSpace(renderContext) { 41037 if (renderContext.textures !== null) { 41038 return renderContext.textures[0].colorSpace; 41039 } 41040 return this.backend.renderer.outputColorSpace; 41041 } 41042 /** 41043 * Returns GPU primitive topology for the given object and material. 41044 * 41045 * @param {Object3D} object - The 3D object. 41046 * @param {Material} material - The material. 41047 * @return {string} The GPU primitive topology. 41048 */ 41049 getPrimitiveTopology(object, material) { 41050 if (object.isPoints) return GPUPrimitiveTopology.PointList; 41051 else if (object.isLineSegments || object.isMesh && material.wireframe === true) return GPUPrimitiveTopology.LineList; 41052 else if (object.isLine) return GPUPrimitiveTopology.LineStrip; 41053 else if (object.isMesh) return GPUPrimitiveTopology.TriangleList; 41054 } 41055 /** 41056 * Returns a modified sample count from the given sample count value. 41057 * 41058 * That is required since WebGPU only supports either 1 or 4. 41059 * 41060 * @param {number} sampleCount - The input sample count. 41061 * @return {number} The (potentially updated) output sample count. 41062 */ 41063 getSampleCount(sampleCount) { 41064 return sampleCount >= 4 ? 4 : 1; 41065 } 41066 /** 41067 * Returns the sample count of the given render context. 41068 * 41069 * @param {RenderContext} renderContext - The render context. 41070 * @return {number} The sample count. 41071 */ 41072 getSampleCountRenderContext(renderContext) { 41073 if (renderContext.textures !== null) { 41074 return this.getSampleCount(renderContext.sampleCount); 41075 } 41076 return this.getSampleCount(this.backend.renderer.currentSamples); 41077 } 41078 /** 41079 * Returns the preferred canvas format. 41080 * 41081 * There is a separate method for this so it's possible to 41082 * honor edge cases for specific devices. 41083 * 41084 * @return {string} The GPU texture format of the canvas. 41085 */ 41086 getPreferredCanvasFormat() { 41087 const parameters = this.backend.parameters; 41088 const bufferType = parameters.outputType; 41089 if (bufferType === void 0) { 41090 return navigator.gpu.getPreferredCanvasFormat(); 41091 } else if (bufferType === UnsignedByteType) { 41092 return GPUTextureFormat.BGRA8Unorm; 41093 } else if (bufferType === HalfFloatType) { 41094 return GPUTextureFormat.RGBA16Float; 41095 } else { 41096 throw new Error("Unsupported output buffer type."); 41097 } 41098 } 41099}; 41100var typedArraysToVertexFormatPrefix = /* @__PURE__ */ new Map([ 41101 [Int8Array, ["sint8", "snorm8"]], 41102 [Uint8Array, ["uint8", "unorm8"]], 41103 [Int16Array, ["sint16", "snorm16"]], 41104 [Uint16Array, ["uint16", "unorm16"]], 41105 [Int32Array, ["sint32", "snorm32"]], 41106 [Uint32Array, ["uint32", "unorm32"]], 41107 [Float32Array, ["float32"]] 41108]); 41109if (typeof Float16Array !== "undefined") { 41110 typedArraysToVertexFormatPrefix.set(Float16Array, ["float16"]); 41111} 41112var typedAttributeToVertexFormatPrefix = /* @__PURE__ */ new Map([ 41113 [Float16BufferAttribute, ["float16"]] 41114]); 41115var typeArraysToVertexFormatPrefixForItemSize1 = /* @__PURE__ */ new Map([ 41116 [Int32Array, "sint32"], 41117 [Int16Array, "sint32"], 41118 // patch for INT16 41119 [Uint32Array, "uint32"], 41120 [Uint16Array, "uint32"], 41121 // patch for UINT16 41122 [Float32Array, "float32"] 41123]); 41124var WebGPUAttributeUtils = class { 41125 /** 41126 * Constructs a new utility object. 41127 * 41128 * @param {WebGPUBackend} backend - The WebGPU backend. 41129 */ 41130 constructor(backend) { 41131 this.backend = backend; 41132 } 41133 /** 41134 * Creates the GPU buffer for the given buffer attribute. 41135 * 41136 * @param {BufferAttribute} attribute - The buffer attribute. 41137 * @param {GPUBufferUsage} usage - A flag that indicates how the buffer may be used after its creation. 41138 */ 41139 createAttribute(attribute3, usage) { 41140 const bufferAttribute3 = this._getBufferAttribute(attribute3); 41141 const backend = this.backend; 41142 const bufferData = backend.get(bufferAttribute3); 41143 let buffer3 = bufferData.buffer; 41144 if (buffer3 === void 0) { 41145 const device = backend.device; 41146 let array3 = bufferAttribute3.array; 41147 if (attribute3.normalized === false) { 41148 if (array3.constructor === Int16Array || array3.constructor === Int8Array) { 41149 array3 = new Int32Array(array3); 41150 } else if (array3.constructor === Uint16Array || array3.constructor === Uint8Array) { 41151 array3 = new Uint32Array(array3); 41152 if (usage & GPUBufferUsage.INDEX) { 41153 for (let i = 0; i < array3.length; i++) { 41154 if (array3[i] === 65535) array3[i] = 4294967295; 41155 } 41156 } 41157 } 41158 } 41159 bufferAttribute3.array = array3; 41160 if ((bufferAttribute3.isStorageBufferAttribute || bufferAttribute3.isStorageInstancedBufferAttribute) && bufferAttribute3.itemSize === 3) { 41161 array3 = new array3.constructor(bufferAttribute3.count * 4); 41162 for (let i = 0; i < bufferAttribute3.count; i++) { 41163 array3.set(bufferAttribute3.array.subarray(i * 3, i * 3 + 3), i * 4); 41164 } 41165 bufferAttribute3.itemSize = 4; 41166 bufferAttribute3.array = array3; 41167 bufferData._force3to4BytesAlignment = true; 41168 } 41169 const byteLength = array3.byteLength; 41170 const size3 = byteLength + (4 - byteLength % 4) % 4; 41171 buffer3 = device.createBuffer({ 41172 label: bufferAttribute3.name, 41173 size: size3, 41174 usage, 41175 mappedAtCreation: true 41176 }); 41177 new array3.constructor(buffer3.getMappedRange()).set(array3); 41178 buffer3.unmap(); 41179 bufferData.buffer = buffer3; 41180 } 41181 } 41182 /** 41183 * Updates the GPU buffer of the given buffer attribute. 41184 * 41185 * @param {BufferAttribute} attribute - The buffer attribute. 41186 */ 41187 updateAttribute(attribute3) { 41188 const bufferAttribute3 = this._getBufferAttribute(attribute3); 41189 const backend = this.backend; 41190 const device = backend.device; 41191 const bufferData = backend.get(bufferAttribute3); 41192 const buffer3 = backend.get(bufferAttribute3).buffer; 41193 let array3 = bufferAttribute3.array; 41194 if (bufferData._force3to4BytesAlignment === true) { 41195 array3 = new array3.constructor(bufferAttribute3.count * 4); 41196 for (let i = 0; i < bufferAttribute3.count; i++) { 41197 array3.set(bufferAttribute3.array.subarray(i * 3, i * 3 + 3), i * 4); 41198 } 41199 bufferAttribute3.array = array3; 41200 } 41201 const updateRanges = bufferAttribute3.updateRanges; 41202 if (updateRanges.length === 0) { 41203 device.queue.writeBuffer( 41204 buffer3, 41205 0, 41206 array3, 41207 0 41208 ); 41209 } else { 41210 const isTyped = isTypedArray(array3); 41211 const byteOffsetFactor = isTyped ? 1 : array3.BYTES_PER_ELEMENT; 41212 for (let i = 0, l = updateRanges.length; i < l; i++) { 41213 const range3 = updateRanges[i]; 41214 let dataOffset, size3; 41215 if (bufferData._force3to4BytesAlignment === true) { 41216 const vertexStart = Math.floor(range3.start / 3); 41217 const vertexCount = Math.ceil(range3.count / 3); 41218 dataOffset = vertexStart * 4 * byteOffsetFactor; 41219 size3 = vertexCount * 4 * byteOffsetFactor; 41220 } else { 41221 dataOffset = range3.start * byteOffsetFactor; 41222 size3 = range3.count * byteOffsetFactor; 41223 } 41224 const bufferOffset = dataOffset * (isTyped ? array3.BYTES_PER_ELEMENT : 1); 41225 device.queue.writeBuffer( 41226 buffer3, 41227 bufferOffset, 41228 array3, 41229 dataOffset, 41230 size3 41231 ); 41232 } 41233 bufferAttribute3.clearUpdateRanges(); 41234 } 41235 } 41236 /** 41237 * This method creates the vertex buffer layout data which are 41238 * require when creating a render pipeline for the given render object. 41239 * 41240 * @param {RenderObject} renderObject - The render object. 41241 * @return {Array<Object>} An array holding objects which describe the vertex buffer layout. 41242 */ 41243 createShaderVertexBuffers(renderObject) { 41244 const attributes = renderObject.getAttributes(); 41245 const vertexBuffers = /* @__PURE__ */ new Map(); 41246 for (let slot = 0; slot < attributes.length; slot++) { 41247 const geometryAttribute = attributes[slot]; 41248 const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT; 41249 const bufferAttribute3 = this._getBufferAttribute(geometryAttribute); 41250 let vertexBufferLayout = vertexBuffers.get(bufferAttribute3); 41251 if (vertexBufferLayout === void 0) { 41252 let arrayStride, stepMode; 41253 if (geometryAttribute.isInterleavedBufferAttribute === true) { 41254 arrayStride = geometryAttribute.data.stride * bytesPerElement; 41255 stepMode = geometryAttribute.data.isInstancedInterleavedBuffer ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex; 41256 } else { 41257 arrayStride = geometryAttribute.itemSize * bytesPerElement; 41258 stepMode = geometryAttribute.isInstancedBufferAttribute ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex; 41259 } 41260 if (geometryAttribute.normalized === false && (geometryAttribute.array.constructor === Int16Array || geometryAttribute.array.constructor === Uint16Array)) { 41261 arrayStride = 4; 41262 } 41263 vertexBufferLayout = { 41264 arrayStride, 41265 attributes: [], 41266 stepMode 41267 }; 41268 vertexBuffers.set(bufferAttribute3, vertexBufferLayout); 41269 } 41270 const format = this._getVertexFormat(geometryAttribute); 41271 const offset3 = geometryAttribute.isInterleavedBufferAttribute === true ? geometryAttribute.offset * bytesPerElement : 0; 41272 vertexBufferLayout.attributes.push({ 41273 shaderLocation: slot, 41274 offset: offset3, 41275 format 41276 }); 41277 } 41278 return Array.from(vertexBuffers.values()); 41279 } 41280 /** 41281 * Destroys the GPU buffer of the given buffer attribute. 41282 * 41283 * @param {BufferAttribute} attribute - The buffer attribute. 41284 */ 41285 destroyAttribute(attribute3) { 41286 const backend = this.backend; 41287 const data = backend.get(this._getBufferAttribute(attribute3)); 41288 data.buffer.destroy(); 41289 backend.delete(attribute3); 41290 } 41291 /** 41292 * This method performs a readback operation by moving buffer data from 41293 * a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can 41294 * be used to retain and reuse handles to the intermediate buffers and prevent 41295 * new allocation. 41296 * 41297 * @async 41298 * @param {BufferAttribute} attribute - The storage buffer attribute to read frm. 41299 * @param {number} count - The offset from which to start reading the 41300 * @param {number} offset - The storage buffer attribute. 41301 * @param {ReadbackBuffer|ArrayBuffer} target - The storage buffer attribute. 41302 * @return {Promise<ArrayBuffer|ReadbackBuffer>} A promise that resolves with the buffer data when the data are ready. 41303 */ 41304 async getArrayBufferAsync(attribute3, target = null, offset3 = 0, count = -1) { 41305 const backend = this.backend; 41306 const device = backend.device; 41307 const data = backend.get(this._getBufferAttribute(attribute3)); 41308 const bufferGPU = data.buffer; 41309 const byteLength = count === -1 ? bufferGPU.size - offset3 : count; 41310 let readBufferGPU; 41311 if (target !== null && target.isReadbackBuffer) { 41312 const readbackInfo = backend.get(target); 41313 if (target._mapped === true) { 41314 throw new Error("WebGPURenderer: ReadbackBuffer must be released before being used again."); 41315 } 41316 target._mapped = true; 41317 if (readbackInfo.readBufferGPU === void 0) { 41318 readBufferGPU = device.createBuffer({ 41319 label: `${target.name}_readback`, 41320 size: target.maxByteLength, 41321 usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 41322 }); 41323 const releaseCallback = () => { 41324 target.buffer = null; 41325 target._mapped = false; 41326 readBufferGPU.unmap(); 41327 }; 41328 const disposeCallback = () => { 41329 target.buffer = null; 41330 target._mapped = false; 41331 readBufferGPU.destroy(); 41332 backend.delete(target); 41333 target.removeEventListener("release", releaseCallback); 41334 target.removeEventListener("dispose", disposeCallback); 41335 }; 41336 target.addEventListener("release", releaseCallback); 41337 target.addEventListener("dispose", disposeCallback); 41338 readbackInfo.readBufferGPU = readBufferGPU; 41339 } else { 41340 readBufferGPU = readbackInfo.readBufferGPU; 41341 } 41342 } else { 41343 readBufferGPU = device.createBuffer({ 41344 label: `${attribute3.name}_readback`, 41345 size: byteLength, 41346 usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 41347 }); 41348 } 41349 const cmdEncoder = device.createCommandEncoder({ 41350 label: `readback_encoder_${attribute3.name}` 41351 }); 41352 cmdEncoder.copyBufferToBuffer( 41353 bufferGPU, 41354 offset3, 41355 readBufferGPU, 41356 0, 41357 byteLength 41358 ); 41359 const gpuCommands = cmdEncoder.finish(); 41360 device.queue.submit([gpuCommands]); 41361 await readBufferGPU.mapAsync(GPUMapMode.READ, 0, byteLength); 41362 if (target === null) { 41363 const arrayBuffer3 = readBufferGPU.getMappedRange(0, byteLength); 41364 const result = arrayBuffer3.slice(); 41365 readBufferGPU.destroy(); 41366 return result; 41367 } else if (target.isReadbackBuffer) { 41368 target.buffer = readBufferGPU.getMappedRange(0, byteLength); 41369 return target; 41370 } else { 41371 const arrayBuffer3 = readBufferGPU.getMappedRange(0, byteLength); 41372 new Uint8Array(target).set(new Uint8Array(arrayBuffer3)); 41373 readBufferGPU.destroy(); 41374 return target; 41375 } 41376 } 41377 /** 41378 * Returns the vertex format of the given buffer attribute. 41379 * 41380 * @private 41381 * @param {BufferAttribute} geometryAttribute - The buffer attribute. 41382 * @return {string|undefined} The vertex format (e.g. 'float32x3'). 41383 */ 41384 _getVertexFormat(geometryAttribute) { 41385 const { itemSize, normalized } = geometryAttribute; 41386 const ArrayType = geometryAttribute.array.constructor; 41387 const AttributeType2 = geometryAttribute.constructor; 41388 let format; 41389 if (itemSize === 1) { 41390 format = typeArraysToVertexFormatPrefixForItemSize1.get(ArrayType); 41391 } else { 41392 const prefixOptions = typedAttributeToVertexFormatPrefix.get(AttributeType2) || typedArraysToVertexFormatPrefix.get(ArrayType); 41393 const prefix = prefixOptions[normalized ? 1 : 0]; 41394 if (prefix) { 41395 const bytesPerUnit = ArrayType.BYTES_PER_ELEMENT * itemSize; 41396 const paddedBytesPerUnit = Math.floor((bytesPerUnit + 3) / 4) * 4; 41397 const paddedItemSize = paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT; 41398 if (paddedItemSize % 1) { 41399 throw new Error("THREE.WebGPUAttributeUtils: Bad vertex format item size."); 41400 } 41401 format = `${prefix}x${paddedItemSize}`; 41402 } 41403 } 41404 if (!format) { 41405 error("WebGPUAttributeUtils: Vertex format not supported yet."); 41406 } 41407 return format; 41408 } 41409 /** 41410 * Utility method for handling interleaved buffer attributes correctly. 41411 * To process them, their `InterleavedBuffer` is returned. 41412 * 41413 * @private 41414 * @param {BufferAttribute} attribute - The attribute. 41415 * @return {BufferAttribute|InterleavedBuffer} 41416 */ 41417 _getBufferAttribute(attribute3) { 41418 if (attribute3.isInterleavedBufferAttribute) attribute3 = attribute3.data; 41419 return attribute3; 41420 } 41421}; 41422var BindGroupLayout = class { 41423 /** 41424 * Constructs a new layout. 41425 * 41426 * @param {GPUBindGroupLayout} layoutGPU - A GPU Bind Group Layout. 41427 */ 41428 constructor(layoutGPU) { 41429 this.layoutGPU = layoutGPU; 41430 this.usedTimes = 0; 41431 } 41432}; 41433var WebGPUBindingUtils = class { 41434 /** 41435 * Constructs a new utility object. 41436 * 41437 * @param {WebGPUBackend} backend - The WebGPU backend. 41438 */ 41439 constructor(backend) { 41440 this.backend = backend; 41441 this._bindGroupLayoutCache = /* @__PURE__ */ new Map(); 41442 } 41443 /** 41444 * Creates a GPU bind group layout for the given bind group. 41445 * 41446 * @param {BindGroup} bindGroup - The bind group. 41447 * @return {GPUBindGroupLayout} The GPU bind group layout. 41448 */ 41449 createBindingsLayout(bindGroup) { 41450 const backend = this.backend; 41451 const device = backend.device; 41452 const bindingsData = backend.get(bindGroup); 41453 if (bindingsData.layout) { 41454 return bindingsData.layout.layoutGPU; 41455 } 41456 const entries5 = this._createLayoutEntries(bindGroup); 41457 const bindGroupLayoutKey = hashString(JSON.stringify(entries5)); 41458 let bindGroupLayout = this._bindGroupLayoutCache.get(bindGroupLayoutKey); 41459 if (bindGroupLayout === void 0) { 41460 bindGroupLayout = new BindGroupLayout(device.createBindGroupLayout({ entries: entries5 })); 41461 this._bindGroupLayoutCache.set(bindGroupLayoutKey, bindGroupLayout); 41462 } 41463 bindGroupLayout.usedTimes++; 41464 bindingsData.layout = bindGroupLayout; 41465 bindingsData.layoutKey = bindGroupLayoutKey; 41466 return bindGroupLayout.layoutGPU; 41467 } 41468 /** 41469 * Creates bindings from the given bind group definition. 41470 * 41471 * @param {BindGroup} bindGroup - The bind group. 41472 * @param {Array<BindGroup>} bindings - Array of bind groups. 41473 * @param {number} cacheIndex - The cache index. 41474 * @param {number} version - The version. 41475 */ 41476 createBindings(bindGroup, bindings, cacheIndex, version = 0) { 41477 const { backend } = this; 41478 const bindingsData = backend.get(bindGroup); 41479 const bindLayoutGPU = this.createBindingsLayout(bindGroup); 41480 let bindGroupGPU; 41481 if (cacheIndex > 0) { 41482 if (bindingsData.groups === void 0) { 41483 bindingsData.groups = []; 41484 bindingsData.versions = []; 41485 } 41486 if (bindingsData.versions[cacheIndex] === version) { 41487 bindGroupGPU = bindingsData.groups[cacheIndex]; 41488 } 41489 } 41490 if (bindGroupGPU === void 0) { 41491 bindGroupGPU = this.createBindGroup(bindGroup, bindLayoutGPU); 41492 if (cacheIndex > 0) { 41493 bindingsData.groups[cacheIndex] = bindGroupGPU; 41494 bindingsData.versions[cacheIndex] = version; 41495 } 41496 } 41497 bindingsData.group = bindGroupGPU; 41498 } 41499 /** 41500 * Updates a buffer binding. 41501 * 41502 * @param {Buffer} binding - The buffer binding to update. 41503 */ 41504 updateBinding(binding) { 41505 const backend = this.backend; 41506 const device = backend.device; 41507 const array3 = binding.buffer; 41508 const buffer3 = backend.get(binding).buffer; 41509 const updateRanges = binding.updateRanges; 41510 if (updateRanges.length === 0) { 41511 device.queue.writeBuffer( 41512 buffer3, 41513 0, 41514 array3, 41515 0 41516 ); 41517 } else { 41518 const isTyped = isTypedArray(array3); 41519 const byteOffsetFactor = isTyped ? 1 : array3.BYTES_PER_ELEMENT; 41520 for (let i = 0, l = updateRanges.length; i < l; i++) { 41521 const range3 = updateRanges[i]; 41522 const dataOffset = range3.start * byteOffsetFactor; 41523 const size3 = range3.count * byteOffsetFactor; 41524 const bufferOffset = dataOffset * (isTyped ? array3.BYTES_PER_ELEMENT : 1); 41525 device.queue.writeBuffer( 41526 buffer3, 41527 bufferOffset, 41528 array3, 41529 dataOffset, 41530 size3 41531 ); 41532 } 41533 } 41534 } 41535 /** 41536 * Creates a GPU bind group for the camera index. 41537 * 41538 * @param {Uint32Array} data - The index data. 41539 * @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout. 41540 * @return {GPUBindGroup} The GPU bind group. 41541 */ 41542 createBindGroupIndex(data, layoutGPU) { 41543 const backend = this.backend; 41544 const device = backend.device; 41545 const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST; 41546 const index = data[0]; 41547 const buffer3 = device.createBuffer({ 41548 label: "bindingCameraIndex_" + index, 41549 size: 16, 41550 // uint(4) * 4 41551 usage 41552 }); 41553 device.queue.writeBuffer(buffer3, 0, data, 0); 41554 const entries5 = [{ binding: 0, resource: { buffer: buffer3 } }]; 41555 return device.createBindGroup({ 41556 label: "bindGroupCameraIndex_" + index, 41557 layout: layoutGPU, 41558 entries: entries5 41559 }); 41560 } 41561 /** 41562 * Creates a GPU bind group for the given bind group and GPU layout. 41563 * 41564 * @param {BindGroup} bindGroup - The bind group. 41565 * @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout. 41566 * @return {GPUBindGroup} The GPU bind group. 41567 */ 41568 createBindGroup(bindGroup, layoutGPU) { 41569 const backend = this.backend; 41570 const device = backend.device; 41571 let bindingPoint = 0; 41572 const entriesGPU = []; 41573 for (const binding of bindGroup.bindings) { 41574 if (binding.isUniformBuffer) { 41575 const bindingData = backend.get(binding); 41576 if (bindingData.buffer === void 0) { 41577 const byteLength = binding.byteLength; 41578 const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST; 41579 const visibilities = []; 41580 if (binding.visibility & GPUShaderStage.VERTEX) { 41581 visibilities.push("vertex"); 41582 } 41583 if (binding.visibility & GPUShaderStage.FRAGMENT) { 41584 visibilities.push("fragment"); 41585 } 41586 if (binding.visibility & GPUShaderStage.COMPUTE) { 41587 visibilities.push("compute"); 41588 } 41589 const bufferVisibility = `(${visibilities.join(",")})`; 41590 const bufferGPU = device.createBuffer({ 41591 label: `bindingBuffer${binding.id}_${binding.name}_${bufferVisibility}`, 41592 size: byteLength, 41593 usage 41594 }); 41595 bindingData.buffer = bufferGPU; 41596 } 41597 entriesGPU.push({ binding: bindingPoint, resource: { buffer: bindingData.buffer } }); 41598 } else if (binding.isStorageBuffer) { 41599 const buffer3 = backend.get(binding.attribute).buffer; 41600 entriesGPU.push({ binding: bindingPoint, resource: { buffer: buffer3 } }); 41601 } else if (binding.isSampledTexture) { 41602 const textureData = backend.get(binding.texture); 41603 let resourceGPU; 41604 if (textureData.externalTexture !== void 0) { 41605 resourceGPU = device.importExternalTexture({ source: textureData.externalTexture }); 41606 } else { 41607 const mipLevelCount = binding.store ? 1 : textureData.texture.mipLevelCount; 41608 const baseMipLevel = binding.store ? binding.mipLevel : 0; 41609 let propertyName = `view-${textureData.texture.width}-${textureData.texture.height}`; 41610 if (textureData.texture.depthOrArrayLayers > 1) { 41611 propertyName += `-${textureData.texture.depthOrArrayLayers}`; 41612 } 41613 propertyName += `-${mipLevelCount}-${baseMipLevel}`; 41614 resourceGPU = textureData[propertyName]; 41615 if (resourceGPU === void 0) { 41616 const aspectGPU = GPUTextureAspect.All; 41617 let dimensionViewGPU; 41618 if (binding.isSampledCubeTexture) { 41619 dimensionViewGPU = GPUTextureViewDimension.Cube; 41620 } else if (binding.isSampledTexture3D) { 41621 dimensionViewGPU = GPUTextureViewDimension.ThreeD; 41622 } else if (binding.texture.isArrayTexture || binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture) { 41623 dimensionViewGPU = GPUTextureViewDimension.TwoDArray; 41624 } else { 41625 dimensionViewGPU = GPUTextureViewDimension.TwoD; 41626 } 41627 resourceGPU = textureData[propertyName] = textureData.texture.createView({ aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount, baseMipLevel }); 41628 } 41629 } 41630 entriesGPU.push({ binding: bindingPoint, resource: resourceGPU }); 41631 } else if (binding.isSampler) { 41632 const textureGPU = backend.get(binding.texture); 41633 entriesGPU.push({ binding: bindingPoint, resource: textureGPU.sampler }); 41634 } 41635 bindingPoint++; 41636 } 41637 return device.createBindGroup({ 41638 label: "bindGroup_" + bindGroup.name, 41639 layout: layoutGPU, 41640 entries: entriesGPU 41641 }); 41642 } 41643 /** 41644 * Creates a GPU bind group layout entries for the given bind group. 41645 * 41646 * @private 41647 * @param {BindGroup} bindGroup - The bind group. 41648 * @return {Array<GPUBindGroupLayoutEntry>} The GPU bind group layout entries. 41649 */ 41650 _createLayoutEntries(bindGroup) { 41651 const entries5 = []; 41652 let index = 0; 41653 for (const binding of bindGroup.bindings) { 41654 const backend = this.backend; 41655 const bindingGPU = { 41656 binding: index, 41657 visibility: binding.visibility 41658 }; 41659 if (binding.isUniformBuffer || binding.isStorageBuffer) { 41660 const buffer3 = {}; 41661 if (binding.isStorageBuffer) { 41662 if (binding.visibility & GPUShaderStage.COMPUTE) { 41663 if (binding.access === NodeAccess.READ_WRITE || binding.access === NodeAccess.WRITE_ONLY) { 41664 buffer3.type = GPUBufferBindingType.Storage; 41665 } else { 41666 buffer3.type = GPUBufferBindingType.ReadOnlyStorage; 41667 } 41668 } else { 41669 buffer3.type = GPUBufferBindingType.ReadOnlyStorage; 41670 } 41671 } 41672 bindingGPU.buffer = buffer3; 41673 } else if (binding.isSampledTexture && binding.store) { 41674 const storageTexture3 = {}; 41675 storageTexture3.format = this.backend.get(binding.texture).texture.format; 41676 const access6 = binding.access; 41677 if (access6 === NodeAccess.READ_WRITE) { 41678 storageTexture3.access = GPUStorageTextureAccess.ReadWrite; 41679 } else if (access6 === NodeAccess.WRITE_ONLY) { 41680 storageTexture3.access = GPUStorageTextureAccess.WriteOnly; 41681 } else { 41682 storageTexture3.access = GPUStorageTextureAccess.ReadOnly; 41683 } 41684 if (binding.texture.isArrayTexture) { 41685 storageTexture3.viewDimension = GPUTextureViewDimension.TwoDArray; 41686 } else if (binding.texture.is3DTexture) { 41687 storageTexture3.viewDimension = GPUTextureViewDimension.ThreeD; 41688 } 41689 bindingGPU.storageTexture = storageTexture3; 41690 } else if (binding.isSampledTexture) { 41691 const texture3 = {}; 41692 const { primarySamples } = backend.utils.getTextureSampleData(binding.texture); 41693 if (primarySamples > 1) { 41694 texture3.multisampled = true; 41695 if (!binding.texture.isDepthTexture) { 41696 texture3.sampleType = GPUTextureSampleType.UnfilterableFloat; 41697 } 41698 } 41699 if (binding.texture.isDepthTexture) { 41700 if (backend.compatibilityMode && binding.texture.compareFunction === null) { 41701 texture3.sampleType = GPUTextureSampleType.UnfilterableFloat; 41702 } else { 41703 texture3.sampleType = GPUTextureSampleType.Depth; 41704 } 41705 } else if (binding.texture.isDataTexture || binding.texture.isDataArrayTexture || binding.texture.isData3DTexture || binding.texture.isStorageTexture) { 41706 const type = binding.texture.type; 41707 if (type === IntType) { 41708 texture3.sampleType = GPUTextureSampleType.SInt; 41709 } else if (type === UnsignedIntType) { 41710 texture3.sampleType = GPUTextureSampleType.UInt; 41711 } else if (type === FloatType) { 41712 if (this.backend.hasFeature("float32-filterable")) { 41713 texture3.sampleType = GPUTextureSampleType.Float; 41714 } else { 41715 texture3.sampleType = GPUTextureSampleType.UnfilterableFloat; 41716 } 41717 } 41718 } 41719 if (binding.isSampledCubeTexture) { 41720 texture3.viewDimension = GPUTextureViewDimension.Cube; 41721 } else if (binding.texture.isArrayTexture || binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture) { 41722 texture3.viewDimension = GPUTextureViewDimension.TwoDArray; 41723 } else if (binding.isSampledTexture3D) { 41724 texture3.viewDimension = GPUTextureViewDimension.ThreeD; 41725 } 41726 bindingGPU.texture = texture3; 41727 } else if (binding.isSampler) { 41728 const sampler3 = {}; 41729 if (binding.texture.isDepthTexture) { 41730 if (binding.texture.compareFunction !== null && backend.hasCompatibility(Compatibility.TEXTURE_COMPARE)) { 41731 sampler3.type = GPUSamplerBindingType.Comparison; 41732 } else { 41733 sampler3.type = GPUSamplerBindingType.NonFiltering; 41734 } 41735 } 41736 bindingGPU.sampler = sampler3; 41737 } else { 41738 error(`WebGPUBindingUtils: Unsupported binding "${binding}".`); 41739 } 41740 entries5.push(bindingGPU); 41741 index++; 41742 } 41743 return entries5; 41744 } 41745 /** 41746 * Delete the data associated with a bind group. 41747 * 41748 * @param {BindGroup} bindGroup - The bind group. 41749 */ 41750 deleteBindGroupData(bindGroup) { 41751 const { backend } = this; 41752 const bindingsData = backend.get(bindGroup); 41753 if (bindingsData.layout) { 41754 bindingsData.layout.usedTimes--; 41755 if (bindingsData.layout.usedTimes === 0) { 41756 this._bindGroupLayoutCache.delete(bindingsData.layoutKey); 41757 } 41758 bindingsData.layout = void 0; 41759 bindingsData.layoutKey = void 0; 41760 } 41761 } 41762 /** 41763 * Frees internal resources. 41764 */ 41765 dispose() { 41766 this._bindGroupLayoutCache.clear(); 41767 } 41768}; 41769var WebGPUCapabilities = class { 41770 /** 41771 * Constructs a new utility object. 41772 * 41773 * @param {WebGPUBackend} backend - The WebGPU backend. 41774 */ 41775 constructor(backend) { 41776 this.backend = backend; 41777 } 41778 /** 41779 * Returns the maximum anisotropy texture filtering value. 41780 * 41781 * @return {number} The maximum anisotropy texture filtering value. 41782 */ 41783 getMaxAnisotropy() { 41784 return 16; 41785 } 41786 /** 41787 * Returns the maximum number of bytes available for uniform buffers. 41788 * 41789 * @return {number} The maximum number of bytes available for uniform buffers. 41790 */ 41791 getUniformBufferLimit() { 41792 return this.backend.device.limits.maxUniformBufferBindingSize; 41793 } 41794}; 41795var WebGPUPipelineUtils = class { 41796 /** 41797 * Constructs a new utility object. 41798 * 41799 * @param {WebGPUBackend} backend - The WebGPU backend. 41800 */ 41801 constructor(backend) { 41802 this.backend = backend; 41803 this._activePipelines = /* @__PURE__ */ new WeakMap(); 41804 } 41805 /** 41806 * Sets the given pipeline for the given pass. The method makes sure to only set the 41807 * pipeline when necessary. 41808 * 41809 * @param {(GPURenderPassEncoder|GPUComputePassEncoder)} pass - The pass encoder. 41810 * @param {(GPURenderPipeline|GPUComputePipeline)} pipeline - The pipeline. 41811 */ 41812 setPipeline(pass3, pipeline) { 41813 const currentPipeline = this._activePipelines.get(pass3); 41814 if (currentPipeline !== pipeline) { 41815 pass3.setPipeline(pipeline); 41816 this._activePipelines.set(pass3, pipeline); 41817 } 41818 } 41819 /** 41820 * Returns the sample count derived from the given render context. 41821 * 41822 * @private 41823 * @param {RenderContext} renderContext - The render context. 41824 * @return {number} The sample count. 41825 */ 41826 _getSampleCount(renderContext) { 41827 return this.backend.utils.getSampleCountRenderContext(renderContext); 41828 } 41829 /** 41830 * Creates a render pipeline for the given render object. 41831 * 41832 * @param {RenderObject} renderObject - The render object. 41833 * @param {Array<Promise>} promises - An array of compilation promises which are used in `compileAsync()`. 41834 */ 41835 createRenderPipeline(renderObject, promises) { 41836 const { object, material, geometry, pipeline } = renderObject; 41837 const { vertexProgram, fragmentProgram } = pipeline; 41838 const backend = this.backend; 41839 const device = backend.device; 41840 const utils = backend.utils; 41841 const pipelineData = backend.get(pipeline); 41842 const bindGroupLayouts = []; 41843 for (const bindGroup of renderObject.getBindings()) { 41844 const bindingsData = backend.get(bindGroup); 41845 const { layoutGPU } = bindingsData.layout; 41846 bindGroupLayouts.push(layoutGPU); 41847 } 41848 const vertexBuffers = backend.attributeUtils.createShaderVertexBuffers(renderObject); 41849 let materialBlending; 41850 if (material.blending !== NoBlending && (material.blending !== NormalBlending || material.transparent !== false)) { 41851 materialBlending = this._getBlending(material); 41852 } 41853 let stencilFront = {}; 41854 if (material.stencilWrite === true) { 41855 stencilFront = { 41856 compare: this._getStencilCompare(material), 41857 failOp: this._getStencilOperation(material.stencilFail), 41858 depthFailOp: this._getStencilOperation(material.stencilZFail), 41859 passOp: this._getStencilOperation(material.stencilZPass) 41860 }; 41861 } 41862 const colorWriteMask = this._getColorWriteMask(material); 41863 const targets = []; 41864 if (renderObject.context.textures !== null) { 41865 const textures = renderObject.context.textures; 41866 const mrt3 = renderObject.context.mrt; 41867 for (let i = 0; i < textures.length; i++) { 41868 const texture3 = textures[i]; 41869 const colorFormat = utils.getTextureFormatGPU(texture3); 41870 let blending; 41871 if (mrt3 !== null) { 41872 if (this.backend.compatibilityMode !== true) { 41873 const blendMode = mrt3.getBlendMode(texture3.name); 41874 if (blendMode.blending === MaterialBlending) { 41875 blending = materialBlending; 41876 } else if (blendMode.blending !== NoBlending) { 41877 blending = this._getBlending(blendMode); 41878 } 41879 } else { 41880 warnOnce("WebGPURenderer: Multiple Render Targets (MRT) blending configuration is not fully supported in compatibility mode. The material blending will be used for all render targets."); 41881 blending = materialBlending; 41882 } 41883 } else { 41884 blending = materialBlending; 41885 } 41886 targets.push({ 41887 format: colorFormat, 41888 blend: blending, 41889 writeMask: colorWriteMask 41890 }); 41891 } 41892 } else { 41893 const colorFormat = utils.getCurrentColorFormat(renderObject.context); 41894 targets.push({ 41895 format: colorFormat, 41896 blend: materialBlending, 41897 writeMask: colorWriteMask 41898 }); 41899 } 41900 const vertexModule = backend.get(vertexProgram).module; 41901 const fragmentModule = backend.get(fragmentProgram).module; 41902 const primitiveState = this._getPrimitiveState(object, geometry, material); 41903 const depthCompare = this._getDepthCompare(material); 41904 const depthStencilFormat = utils.getCurrentDepthStencilFormat(renderObject.context); 41905 const sampleCount = this._getSampleCount(renderObject.context); 41906 const pipelineDescriptor = { 41907 label: `renderPipeline_${material.name || material.type}_${material.id}`, 41908 vertex: Object.assign({}, vertexModule, { buffers: vertexBuffers }), 41909 fragment: Object.assign({}, fragmentModule, { targets }), 41910 primitive: primitiveState, 41911 multisample: { 41912 count: sampleCount, 41913 alphaToCoverageEnabled: material.alphaToCoverage && sampleCount > 1 41914 }, 41915 layout: device.createPipelineLayout({ 41916 bindGroupLayouts 41917 }) 41918 }; 41919 const depthStencil = {}; 41920 const renderDepth = renderObject.context.depth; 41921 const renderStencil = renderObject.context.stencil; 41922 if (renderDepth === true || renderStencil === true) { 41923 if (renderDepth === true) { 41924 depthStencil.format = depthStencilFormat; 41925 depthStencil.depthWriteEnabled = material.depthWrite; 41926 depthStencil.depthCompare = depthCompare; 41927 } 41928 if (renderStencil === true) { 41929 depthStencil.stencilFront = stencilFront; 41930 depthStencil.stencilBack = stencilFront; 41931 depthStencil.stencilReadMask = material.stencilFuncMask; 41932 depthStencil.stencilWriteMask = material.stencilWriteMask; 41933 } 41934 if (material.polygonOffset === true) { 41935 depthStencil.depthBias = material.polygonOffsetUnits; 41936 depthStencil.depthBiasSlopeScale = material.polygonOffsetFactor; 41937 depthStencil.depthBiasClamp = 0; 41938 } 41939 pipelineDescriptor.depthStencil = depthStencil; 41940 } 41941 device.pushErrorScope("validation"); 41942 if (promises === null) { 41943 pipelineData.pipeline = device.createRenderPipeline(pipelineDescriptor); 41944 device.popErrorScope().then((err) => { 41945 if (err !== null) { 41946 pipelineData.error = true; 41947 error(err.message); 41948 } 41949 }); 41950 } else { 41951 const p = new Promise(async (resolve) => { 41952 try { 41953 pipelineData.pipeline = await device.createRenderPipelineAsync(pipelineDescriptor); 41954 } catch (err) { 41955 } 41956 const errorScope = await device.popErrorScope(); 41957 if (errorScope !== null) { 41958 pipelineData.error = true; 41959 error(errorScope.message); 41960 } 41961 resolve(); 41962 }); 41963 promises.push(p); 41964 } 41965 } 41966 /** 41967 * Creates GPU render bundle encoder for the given render context. 41968 * 41969 * @param {RenderContext} renderContext - The render context. 41970 * @param {?string} [label='renderBundleEncoder'] - The label. 41971 * @return {GPURenderBundleEncoder} The GPU render bundle encoder. 41972 */ 41973 createBundleEncoder(renderContext, label3 = "renderBundleEncoder") { 41974 const backend = this.backend; 41975 const { utils, device } = backend; 41976 const depthStencilFormat = utils.getCurrentDepthStencilFormat(renderContext); 41977 const colorFormats = utils.getCurrentColorFormats(renderContext); 41978 const sampleCount = this._getSampleCount(renderContext); 41979 const descriptor = { 41980 label: label3, 41981 colorFormats, 41982 depthStencilFormat, 41983 sampleCount 41984 }; 41985 return device.createRenderBundleEncoder(descriptor); 41986 } 41987 /** 41988 * Creates a compute pipeline for the given compute node. 41989 * 41990 * @param {ComputePipeline} pipeline - The compute pipeline. 41991 * @param {Array<BindGroup>} bindings - The bindings. 41992 */ 41993 createComputePipeline(pipeline, bindings) { 41994 const backend = this.backend; 41995 const device = backend.device; 41996 const computeProgram = backend.get(pipeline.computeProgram).module; 41997 const pipelineGPU = backend.get(pipeline); 41998 const bindGroupLayouts = []; 41999 for (const bindingsGroup of bindings) { 42000 const bindingsData = backend.get(bindingsGroup); 42001 const { layoutGPU } = bindingsData.layout; 42002 bindGroupLayouts.push(layoutGPU); 42003 } 42004 pipelineGPU.pipeline = device.createComputePipeline({ 42005 compute: computeProgram, 42006 layout: device.createPipelineLayout({ 42007 bindGroupLayouts 42008 }) 42009 }); 42010 } 42011 /** 42012 * Returns the blending state as a descriptor object required 42013 * for the pipeline creation. 42014 * 42015 * @private 42016 * @param {Material|BlendMode} object - The object containing blending information. 42017 * @return {Object} The blending state. 42018 */ 42019 _getBlending(object) { 42020 let color3, alpha; 42021 const blending = object.blending; 42022 const blendSrc = object.blendSrc; 42023 const blendDst = object.blendDst; 42024 const blendEquation = object.blendEquation; 42025 if (blending === CustomBlending) { 42026 const blendSrcAlpha = object.blendSrcAlpha !== null ? object.blendSrcAlpha : blendSrc; 42027 const blendDstAlpha = object.blendDstAlpha !== null ? object.blendDstAlpha : blendDst; 42028 const blendEquationAlpha = object.blendEquationAlpha !== null ? object.blendEquationAlpha : blendEquation; 42029 color3 = { 42030 srcFactor: this._getBlendFactor(blendSrc), 42031 dstFactor: this._getBlendFactor(blendDst), 42032 operation: this._getBlendOperation(blendEquation) 42033 }; 42034 alpha = { 42035 srcFactor: this._getBlendFactor(blendSrcAlpha), 42036 dstFactor: this._getBlendFactor(blendDstAlpha), 42037 operation: this._getBlendOperation(blendEquationAlpha) 42038 }; 42039 } else { 42040 const premultipliedAlpha = object.premultipliedAlpha; 42041 const setBlend = (srcRGB, dstRGB, srcAlpha, dstAlpha) => { 42042 color3 = { 42043 srcFactor: srcRGB, 42044 dstFactor: dstRGB, 42045 operation: GPUBlendOperation.Add 42046 }; 42047 alpha = { 42048 srcFactor: srcAlpha, 42049 dstFactor: dstAlpha, 42050 operation: GPUBlendOperation.Add 42051 }; 42052 }; 42053 if (premultipliedAlpha) { 42054 switch (blending) { 42055 case NormalBlending: 42056 setBlend(GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha); 42057 break; 42058 case AdditiveBlending: 42059 setBlend(GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One); 42060 break; 42061 case SubtractiveBlending: 42062 setBlend(GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One); 42063 break; 42064 case MultiplyBlending: 42065 setBlend(GPUBlendFactor.Dst, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.Zero, GPUBlendFactor.One); 42066 break; 42067 } 42068 } else { 42069 switch (blending) { 42070 case NormalBlending: 42071 setBlend(GPUBlendFactor.SrcAlpha, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha); 42072 break; 42073 case AdditiveBlending: 42074 setBlend(GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One); 42075 break; 42076 case SubtractiveBlending: 42077 error(`WebGPURenderer: "SubtractiveBlending" requires "${object.isMaterial ? "material" : "blendMode"}.premultipliedAlpha = true".`); 42078 break; 42079 case MultiplyBlending: 42080 error(`WebGPURenderer: "MultiplyBlending" requires "${object.isMaterial ? "material" : "blendMode"}.premultipliedAlpha = true".`); 42081 break; 42082 } 42083 } 42084 } 42085 if (color3 !== void 0 && alpha !== void 0) { 42086 return { color: color3, alpha }; 42087 } else { 42088 error("WebGPURenderer: Invalid blending: ", blending); 42089 } 42090 } 42091 /** 42092 * Returns the GPU blend factor which is required for the pipeline creation. 42093 * 42094 * @private 42095 * @param {number} blend - The blend factor as a three.js constant. 42096 * @return {string} The GPU blend factor. 42097 */ 42098 _getBlendFactor(blend) { 42099 let blendFactor; 42100 switch (blend) { 42101 case ZeroFactor: 42102 blendFactor = GPUBlendFactor.Zero; 42103 break; 42104 case OneFactor: 42105 blendFactor = GPUBlendFactor.One; 42106 break; 42107 case SrcColorFactor: 42108 blendFactor = GPUBlendFactor.Src; 42109 break; 42110 case OneMinusSrcColorFactor: 42111 blendFactor = GPUBlendFactor.OneMinusSrc; 42112 break; 42113 case SrcAlphaFactor: 42114 blendFactor = GPUBlendFactor.SrcAlpha; 42115 break; 42116 case OneMinusSrcAlphaFactor: 42117 blendFactor = GPUBlendFactor.OneMinusSrcAlpha; 42118 break; 42119 case DstColorFactor: 42120 blendFactor = GPUBlendFactor.Dst; 42121 break; 42122 case OneMinusDstColorFactor: 42123 blendFactor = GPUBlendFactor.OneMinusDst; 42124 break; 42125 case DstAlphaFactor: 42126 blendFactor = GPUBlendFactor.DstAlpha; 42127 break; 42128 case OneMinusDstAlphaFactor: 42129 blendFactor = GPUBlendFactor.OneMinusDstAlpha; 42130 break; 42131 case SrcAlphaSaturateFactor: 42132 blendFactor = GPUBlendFactor.SrcAlphaSaturated; 42133 break; 42134 case BlendColorFactor: 42135 blendFactor = GPUBlendFactor.Constant; 42136 break; 42137 case OneMinusBlendColorFactor: 42138 blendFactor = GPUBlendFactor.OneMinusConstant; 42139 break; 42140 default: 42141 error("WebGPURenderer: Blend factor not supported.", blend); 42142 } 42143 return blendFactor; 42144 } 42145 /** 42146 * Returns the GPU stencil compare function which is required for the pipeline creation. 42147 * 42148 * @private 42149 * @param {Material} material - The material. 42150 * @return {string} The GPU stencil compare function. 42151 */ 42152 _getStencilCompare(material) { 42153 let stencilCompare; 42154 const stencilFunc = material.stencilFunc; 42155 switch (stencilFunc) { 42156 case NeverStencilFunc: 42157 stencilCompare = GPUCompareFunction.Never; 42158 break; 42159 case AlwaysStencilFunc: 42160 stencilCompare = GPUCompareFunction.Always; 42161 break; 42162 case LessStencilFunc: 42163 stencilCompare = GPUCompareFunction.Less; 42164 break; 42165 case LessEqualStencilFunc: 42166 stencilCompare = GPUCompareFunction.LessEqual; 42167 break; 42168 case EqualStencilFunc: 42169 stencilCompare = GPUCompareFunction.Equal; 42170 break; 42171 case GreaterEqualStencilFunc: 42172 stencilCompare = GPUCompareFunction.GreaterEqual; 42173 break; 42174 case GreaterStencilFunc: 42175 stencilCompare = GPUCompareFunction.Greater; 42176 break; 42177 case NotEqualStencilFunc: 42178 stencilCompare = GPUCompareFunction.NotEqual; 42179 break; 42180 default: 42181 error("WebGPURenderer: Invalid stencil function.", stencilFunc); 42182 } 42183 return stencilCompare; 42184 } 42185 /** 42186 * Returns the GPU stencil operation which is required for the pipeline creation. 42187 * 42188 * @private 42189 * @param {number} op - A three.js constant defining the stencil operation. 42190 * @return {string} The GPU stencil operation. 42191 */ 42192 _getStencilOperation(op) { 42193 let stencilOperation; 42194 switch (op) { 42195 case KeepStencilOp: 42196 stencilOperation = GPUStencilOperation.Keep; 42197 break; 42198 case ZeroStencilOp: 42199 stencilOperation = GPUStencilOperation.Zero; 42200 break; 42201 case ReplaceStencilOp: 42202 stencilOperation = GPUStencilOperation.Replace; 42203 break; 42204 case InvertStencilOp: 42205 stencilOperation = GPUStencilOperation.Invert; 42206 break; 42207 case IncrementStencilOp: 42208 stencilOperation = GPUStencilOperation.IncrementClamp; 42209 break; 42210 case DecrementStencilOp: 42211 stencilOperation = GPUStencilOperation.DecrementClamp; 42212 break; 42213 case IncrementWrapStencilOp: 42214 stencilOperation = GPUStencilOperation.IncrementWrap; 42215 break; 42216 case DecrementWrapStencilOp: 42217 stencilOperation = GPUStencilOperation.DecrementWrap; 42218 break; 42219 default: 42220 error("WebGPURenderer: Invalid stencil operation.", stencilOperation); 42221 } 42222 return stencilOperation; 42223 } 42224 /** 42225 * Returns the GPU blend operation which is required for the pipeline creation. 42226 * 42227 * @private 42228 * @param {number} blendEquation - A three.js constant defining the blend equation. 42229 * @return {string} The GPU blend operation. 42230 */ 42231 _getBlendOperation(blendEquation) { 42232 let blendOperation; 42233 switch (blendEquation) { 42234 case AddEquation: 42235 blendOperation = GPUBlendOperation.Add; 42236 break; 42237 case SubtractEquation: 42238 blendOperation = GPUBlendOperation.Subtract; 42239 break; 42240 case ReverseSubtractEquation: 42241 blendOperation = GPUBlendOperation.ReverseSubtract; 42242 break; 42243 case MinEquation: 42244 blendOperation = GPUBlendOperation.Min; 42245 break; 42246 case MaxEquation: 42247 blendOperation = GPUBlendOperation.Max; 42248 break; 42249 default: 42250 error("WebGPUPipelineUtils: Blend equation not supported.", blendEquation); 42251 } 42252 return blendOperation; 42253 } 42254 /** 42255 * Returns the primitive state as a descriptor object required 42256 * for the pipeline creation. 42257 * 42258 * @private 42259 * @param {Object3D} object - The 3D object. 42260 * @param {BufferGeometry} geometry - The geometry. 42261 * @param {Material} material - The material. 42262 * @return {Object} The primitive state. 42263 */ 42264 _getPrimitiveState(object, geometry, material) { 42265 const descriptor = {}; 42266 const utils = this.backend.utils; 42267 descriptor.topology = utils.getPrimitiveTopology(object, material); 42268 if (geometry.index !== null && object.isLine === true && object.isLineSegments !== true) { 42269 descriptor.stripIndexFormat = geometry.index.array instanceof Uint16Array ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32; 42270 } 42271 let flipSided = material.side === BackSide; 42272 if (object.isMesh && object.matrixWorld.determinant() < 0) flipSided = !flipSided; 42273 descriptor.frontFace = flipSided === true ? GPUFrontFace.CW : GPUFrontFace.CCW; 42274 descriptor.cullMode = material.side === DoubleSide ? GPUCullMode.None : GPUCullMode.Back; 42275 return descriptor; 42276 } 42277 /** 42278 * Returns the GPU color write mask which is required for the pipeline creation. 42279 * 42280 * @private 42281 * @param {Material} material - The material. 42282 * @return {number} The GPU color write mask. 42283 */ 42284 _getColorWriteMask(material) { 42285 return material.colorWrite === true ? GPUColorWriteFlags.All : GPUColorWriteFlags.None; 42286 } 42287 /** 42288 * Returns the GPU depth compare function which is required for the pipeline creation. 42289 * 42290 * @private 42291 * @param {Material} material - The material. 42292 * @return {string} The GPU depth compare function. 42293 */ 42294 _getDepthCompare(material) { 42295 let depthCompare; 42296 if (material.depthTest === false) { 42297 depthCompare = GPUCompareFunction.Always; 42298 } else { 42299 const depthFunc = this.backend.parameters.reversedDepthBuffer ? ReversedDepthFuncs[material.depthFunc] : material.depthFunc; 42300 switch (depthFunc) { 42301 case NeverDepth: 42302 depthCompare = GPUCompareFunction.Never; 42303 break; 42304 case AlwaysDepth: 42305 depthCompare = GPUCompareFunction.Always; 42306 break; 42307 case LessDepth: 42308 depthCompare = GPUCompareFunction.Less; 42309 break; 42310 case LessEqualDepth: 42311 depthCompare = GPUCompareFunction.LessEqual; 42312 break; 42313 case EqualDepth: 42314 depthCompare = GPUCompareFunction.Equal; 42315 break; 42316 case GreaterEqualDepth: 42317 depthCompare = GPUCompareFunction.GreaterEqual; 42318 break; 42319 case GreaterDepth: 42320 depthCompare = GPUCompareFunction.Greater; 42321 break; 42322 case NotEqualDepth: 42323 depthCompare = GPUCompareFunction.NotEqual; 42324 break; 42325 default: 42326 error("WebGPUPipelineUtils: Invalid depth function.", depthFunc); 42327 } 42328 } 42329 return depthCompare; 42330 } 42331}; 42332var WebGPUTimestampQueryPool = class extends TimestampQueryPool { 42333 /** 42334 * Creates a new WebGPU timestamp query pool. 42335 * 42336 * @param {GPUDevice} device - The WebGPU device to create queries on. 42337 * @param {string} type - The type identifier for this query pool. 42338 * @param {number} [maxQueries=2048] - Maximum number of queries this pool can hold. 42339 */ 42340 constructor(device, type, maxQueries = 2048) { 42341 super(maxQueries); 42342 this.device = device; 42343 this.type = type; 42344 this.querySet = this.device.createQuerySet({ 42345 type: "timestamp", 42346 count: this.maxQueries, 42347 label: `queryset_global_timestamp_${type}` 42348 }); 42349 const bufferSize = this.maxQueries * 8; 42350 this.resolveBuffer = this.device.createBuffer({ 42351 label: `buffer_timestamp_resolve_${type}`, 42352 size: bufferSize, 42353 usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC 42354 }); 42355 this.resultBuffer = this.device.createBuffer({ 42356 label: `buffer_timestamp_result_${type}`, 42357 size: bufferSize, 42358 usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 42359 }); 42360 } 42361 /** 42362 * Allocates a pair of queries for a given render context. 42363 * 42364 * @param {string} uid - A unique identifier for the render context. 42365 * @returns {?number} The base offset for the allocated queries, or null if allocation failed. 42366 */ 42367 allocateQueriesForContext(uid) { 42368 if (!this.trackTimestamp || this.isDisposed) return null; 42369 if (this.currentQueryIndex + 2 > this.maxQueries) { 42370 warnOnce(`WebGPUTimestampQueryPool [${this.type}]: Maximum number of queries exceeded, when using trackTimestamp it is necessary to resolves the queries via renderer.resolveTimestampsAsync( THREE.TimestampQuery.${this.type.toUpperCase()} ).`); 42371 return null; 42372 } 42373 const baseOffset = this.currentQueryIndex; 42374 this.currentQueryIndex += 2; 42375 this.queryOffsets.set(uid, baseOffset); 42376 return baseOffset; 42377 } 42378 /** 42379 * Asynchronously resolves all pending queries and returns the total duration. 42380 * If there's already a pending resolve operation, returns that promise instead. 42381 * 42382 * @async 42383 * @returns {Promise<number>} The total duration in milliseconds, or the last valid value if resolution fails. 42384 */ 42385 async resolveQueriesAsync() { 42386 if (!this.trackTimestamp || this.currentQueryIndex === 0 || this.isDisposed) { 42387 return this.lastValue; 42388 } 42389 if (this.pendingResolve) { 42390 return this.pendingResolve; 42391 } 42392 this.pendingResolve = this._resolveQueries(); 42393 try { 42394 const result = await this.pendingResolve; 42395 return result; 42396 } finally { 42397 this.pendingResolve = null; 42398 } 42399 } 42400 /** 42401 * Internal method to resolve queries and calculate total duration. 42402 * 42403 * @async 42404 * @private 42405 * @returns {Promise<number>} The total duration in milliseconds. 42406 */ 42407 async _resolveQueries() { 42408 if (this.isDisposed) { 42409 return this.lastValue; 42410 } 42411 try { 42412 if (this.resultBuffer.mapState !== "unmapped") { 42413 return this.lastValue; 42414 } 42415 const currentOffsets = new Map(this.queryOffsets); 42416 const queryCount = this.currentQueryIndex; 42417 const bytesUsed = queryCount * 8; 42418 this.currentQueryIndex = 0; 42419 this.queryOffsets.clear(); 42420 const commandEncoder = this.device.createCommandEncoder(); 42421 commandEncoder.resolveQuerySet( 42422 this.querySet, 42423 0, 42424 queryCount, 42425 this.resolveBuffer, 42426 0 42427 ); 42428 commandEncoder.copyBufferToBuffer( 42429 this.resolveBuffer, 42430 0, 42431 this.resultBuffer, 42432 0, 42433 bytesUsed 42434 ); 42435 const commandBuffer = commandEncoder.finish(); 42436 this.device.queue.submit([commandBuffer]); 42437 if (this.resultBuffer.mapState !== "unmapped") { 42438 return this.lastValue; 42439 } 42440 await this.resultBuffer.mapAsync(GPUMapMode.READ, 0, bytesUsed); 42441 if (this.isDisposed) { 42442 if (this.resultBuffer.mapState === "mapped") { 42443 this.resultBuffer.unmap(); 42444 } 42445 return this.lastValue; 42446 } 42447 const times = new BigUint64Array(this.resultBuffer.getMappedRange(0, bytesUsed)); 42448 const framesDuration = {}; 42449 const frames = []; 42450 for (const [uid, baseOffset] of currentOffsets) { 42451 const match = uid.match(/^(.*):f(\d+)$/); 42452 const frame = parseInt(match[2]); 42453 if (frames.includes(frame) === false) { 42454 frames.push(frame); 42455 } 42456 if (framesDuration[frame] === void 0) framesDuration[frame] = 0; 42457 const startTime = times[baseOffset]; 42458 const endTime = times[baseOffset + 1]; 42459 const duration = Number(endTime - startTime) / 1e6; 42460 this.timestamps.set(uid, duration); 42461 framesDuration[frame] += duration; 42462 } 42463 const totalDuration = framesDuration[frames[frames.length - 1]]; 42464 this.resultBuffer.unmap(); 42465 this.lastValue = totalDuration; 42466 this.frames = frames; 42467 return totalDuration; 42468 } catch (e) { 42469 error("Error resolving queries:", e); 42470 if (this.resultBuffer.mapState === "mapped") { 42471 this.resultBuffer.unmap(); 42472 } 42473 return this.lastValue; 42474 } 42475 } 42476 /** 42477 * Dispose of the query pool. 42478 * 42479 * @async 42480 * @returns {Promise} A Promise that resolves when the dispose has been executed. 42481 */ 42482 async dispose() { 42483 if (this.isDisposed) { 42484 return; 42485 } 42486 this.isDisposed = true; 42487 if (this.pendingResolve) { 42488 try { 42489 await this.pendingResolve; 42490 } catch (e) { 42491 error("Error waiting for pending resolve:", e); 42492 } 42493 } 42494 if (this.resultBuffer && this.resultBuffer.mapState === "mapped") { 42495 try { 42496 this.resultBuffer.unmap(); 42497 } catch (e) { 42498 error("Error unmapping buffer:", e); 42499 } 42500 } 42501 if (this.querySet) { 42502 this.querySet.destroy(); 42503 this.querySet = null; 42504 } 42505 if (this.resolveBuffer) { 42506 this.resolveBuffer.destroy(); 42507 this.resolveBuffer = null; 42508 } 42509 if (this.resultBuffer) { 42510 this.resultBuffer.destroy(); 42511 this.resultBuffer = null; 42512 } 42513 this.queryOffsets.clear(); 42514 this.pendingResolve = null; 42515 } 42516}; 42517var _clearValue = { r: 0, g: 0, b: 0, a: 1 }; 42518var WebGPUBackend = class extends Backend { 42519 /** 42520 * WebGPUBackend options. 42521 * 42522 * @typedef {Object} WebGPUBackend~Options 42523 * @property {boolean} [logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. 42524 * @property {boolean} [reversedDepthBuffer=false] - Whether reversed depth buffer is enabled or not. 42525 * @property {boolean} [alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. 42526 * @property {boolean} [depth=true] - Whether the default framebuffer should have a depth buffer or not. 42527 * @property {boolean} [stencil=false] - Whether the default framebuffer should have a stencil buffer or not. 42528 * @property {boolean} [antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. 42529 * @property {number} [samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. 42530 * @property {boolean} [forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. 42531 * @property {boolean} [trackTimestamp=false] - Whether to track timestamps with a Timestamp Query API or not. 42532 * @property {string} [powerPreference=undefined] - The power preference. 42533 * @property {Object} [requiredLimits=undefined] - Specifies the limits that are required by the device request. The request will fail if the adapter cannot provide these limits. 42534 * @property {GPUDevice} [device=undefined] - If there is an existing GPU device on app level, it can be passed to the renderer as a parameter. 42535 * @property {number} [outputType=undefined] - Texture type for output to canvas. By default, device's preferred format is used; other formats may incur overhead. 42536 */ 42537 /** 42538 * Constructs a new WebGPU backend. 42539 * 42540 * @param {WebGPUBackend~Options} [parameters] - The configuration parameter. 42541 */ 42542 constructor(parameters = {}) { 42543 super(parameters); 42544 this.isWebGPUBackend = true; 42545 this.parameters.alpha = parameters.alpha === void 0 ? true : parameters.alpha; 42546 this.parameters.requiredLimits = parameters.requiredLimits === void 0 ? {} : parameters.requiredLimits; 42547 this.compatibilityMode = null; 42548 this.device = null; 42549 this.defaultRenderPassdescriptor = null; 42550 this.utils = new WebGPUUtils(this); 42551 this.attributeUtils = new WebGPUAttributeUtils(this); 42552 this.bindingUtils = new WebGPUBindingUtils(this); 42553 this.capabilities = new WebGPUCapabilities(this); 42554 this.pipelineUtils = new WebGPUPipelineUtils(this); 42555 this.textureUtils = new WebGPUTextureUtils(this); 42556 this.occludedResolveCache = /* @__PURE__ */ new Map(); 42557 const compatibilityTextureCompare = typeof navigator === "undefined" ? true : /Android/.test(navigator.userAgent) === false; 42558 this._compatibility = { 42559 [Compatibility.TEXTURE_COMPARE]: compatibilityTextureCompare 42560 }; 42561 } 42562 /** 42563 * Initializes the backend so it is ready for usage. 42564 * 42565 * @async 42566 * @param {Renderer} renderer - The renderer. 42567 * @return {Promise} A Promise that resolves when the backend has been initialized. 42568 */ 42569 async init(renderer) { 42570 await super.init(renderer); 42571 const parameters = this.parameters; 42572 let device; 42573 if (parameters.device === void 0) { 42574 const adapterOptions = { 42575 powerPreference: parameters.powerPreference, 42576 featureLevel: "compatibility" 42577 }; 42578 const adapter = typeof navigator !== "undefined" ? await navigator.gpu.requestAdapter(adapterOptions) : null; 42579 if (adapter === null) { 42580 throw new Error("WebGPUBackend: Unable to create WebGPU adapter."); 42581 } 42582 const features = Object.values(GPUFeatureName); 42583 const supportedFeatures = []; 42584 for (const name of features) { 42585 if (adapter.features.has(name)) { 42586 supportedFeatures.push(name); 42587 } 42588 } 42589 const deviceDescriptor = { 42590 requiredFeatures: supportedFeatures, 42591 requiredLimits: parameters.requiredLimits 42592 }; 42593 device = await adapter.requestDevice(deviceDescriptor); 42594 } else { 42595 device = parameters.device; 42596 } 42597 this.compatibilityMode = !device.features.has("core-features-and-limits"); 42598 if (this.compatibilityMode) { 42599 renderer._samples = 0; 42600 } 42601 device.lost.then((info) => { 42602 if (info.reason === "destroyed") return; 42603 const deviceLossInfo = { 42604 api: "WebGPU", 42605 message: info.message || "Unknown reason", 42606 reason: info.reason || null, 42607 originalEvent: info 42608 }; 42609 renderer.onDeviceLost(deviceLossInfo); 42610 }); 42611 this.device = device; 42612 this.trackTimestamp = this.trackTimestamp && this.hasFeature(GPUFeatureName.TimestampQuery); 42613 this.updateSize(); 42614 } 42615 /** 42616 * A reference to the context. 42617 * 42618 * @type {?GPUCanvasContext} 42619 * @default null 42620 */ 42621 get context() { 42622 const canvasTarget = this.renderer.getCanvasTarget(); 42623 const canvasData = this.get(canvasTarget); 42624 let context3 = canvasData.context; 42625 if (context3 === void 0) { 42626 const parameters = this.parameters; 42627 if (canvasTarget.isDefaultCanvasTarget === true && parameters.context !== void 0) { 42628 context3 = parameters.context; 42629 } else { 42630 context3 = canvasTarget.domElement.getContext("webgpu"); 42631 } 42632 if ("setAttribute" in canvasTarget.domElement) canvasTarget.domElement.setAttribute("data-engine", `three.js r${REVISION} webgpu`); 42633 const alphaMode = parameters.alpha ? "premultiplied" : "opaque"; 42634 const toneMappingMode = parameters.outputType === HalfFloatType ? "extended" : "standard"; 42635 context3.configure({ 42636 device: this.device, 42637 format: this.utils.getPreferredCanvasFormat(), 42638 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, 42639 alphaMode, 42640 toneMapping: { 42641 mode: toneMappingMode 42642 } 42643 }); 42644 canvasData.context = context3; 42645 } 42646 return context3; 42647 } 42648 /** 42649 * The coordinate system of the backend. 42650 * 42651 * @type {number} 42652 * @readonly 42653 */ 42654 get coordinateSystem() { 42655 return WebGPUCoordinateSystem; 42656 } 42657 /** 42658 * This method performs a readback operation by moving buffer data from 42659 * a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can 42660 * be used to retain and reuse handles to the intermediate buffers and prevent 42661 * new allocation. 42662 * 42663 * @async 42664 * @param {BufferAttribute} attribute - The storage buffer attribute to read frm. 42665 * @param {number} count - The offset from which to start reading the 42666 * @param {number} offset - The storage buffer attribute. 42667 * @param {ReadbackBuffer|ArrayBuffer} target - The storage buffer attribute. 42668 * @return {Promise<ArrayBuffer|ReadbackBuffer>} A promise that resolves with the buffer data when the data are ready. 42669 */ 42670 async getArrayBufferAsync(attribute3, target = null, offset3 = 0, count = -1) { 42671 return await this.attributeUtils.getArrayBufferAsync(attribute3, target, offset3, count); 42672 } 42673 /** 42674 * Returns the backend's rendering context. 42675 * 42676 * @return {GPUCanvasContext} The rendering context. 42677 */ 42678 getContext() { 42679 return this.context; 42680 } 42681 /** 42682 * Returns the default render pass descriptor. 42683 * 42684 * In WebGPU, the default framebuffer must be configured 42685 * like custom framebuffers so the backend needs a render 42686 * pass descriptor even when rendering directly to screen. 42687 * 42688 * @private 42689 * @return {Object} The render pass descriptor. 42690 */ 42691 _getDefaultRenderPassDescriptor() { 42692 const renderer = this.renderer; 42693 const canvasTarget = renderer.getCanvasTarget(); 42694 const canvasData = this.get(canvasTarget); 42695 const samples = renderer.currentSamples; 42696 let descriptor = canvasData.descriptor; 42697 if (descriptor === void 0 || canvasData.samples !== samples) { 42698 descriptor = { 42699 colorAttachments: [{ 42700 view: null 42701 }] 42702 }; 42703 if (renderer.depth === true || renderer.stencil === true) { 42704 descriptor.depthStencilAttachment = { 42705 view: this.textureUtils.getDepthBuffer(renderer.depth, renderer.stencil).createView() 42706 }; 42707 } 42708 const colorAttachment2 = descriptor.colorAttachments[0]; 42709 if (samples > 0) { 42710 colorAttachment2.view = this.textureUtils.getColorBuffer().createView(); 42711 } else { 42712 colorAttachment2.resolveTarget = void 0; 42713 } 42714 canvasData.descriptor = descriptor; 42715 canvasData.samples = samples; 42716 } 42717 const colorAttachment = descriptor.colorAttachments[0]; 42718 if (samples > 0) { 42719 colorAttachment.resolveTarget = this.context.getCurrentTexture().createView(); 42720 } else { 42721 colorAttachment.view = this.context.getCurrentTexture().createView(); 42722 } 42723 return descriptor; 42724 } 42725 /** 42726 * Internal to determine if the current render target is a render target array with depth 2D array texture. 42727 * 42728 * @param {RenderContext} renderContext - The render context. 42729 * @return {boolean} Whether the render target is a render target array with depth 2D array texture. 42730 * 42731 * @private 42732 */ 42733 _isRenderCameraDepthArray(renderContext) { 42734 return renderContext.depthTexture && renderContext.depthTexture.image.depth > 1 && renderContext.camera.isArrayCamera; 42735 } 42736 /** 42737 * Returns the render pass descriptor for the given render context. 42738 * 42739 * @private 42740 * @param {RenderContext} renderContext - The render context. 42741 * @param {Object} colorAttachmentsConfig - Configuration object for the color attachments. 42742 * @return {Object} The render pass descriptor. 42743 */ 42744 _getRenderPassDescriptor(renderContext, colorAttachmentsConfig = {}) { 42745 const renderTarget = renderContext.renderTarget; 42746 const renderTargetData = this.get(renderTarget); 42747 let descriptors = renderTargetData.descriptors; 42748 if (descriptors === void 0 || renderTargetData.width !== renderTarget.width || renderTargetData.height !== renderTarget.height || renderTargetData.samples !== renderTarget.samples) { 42749 descriptors = {}; 42750 renderTargetData.descriptors = descriptors; 42751 } 42752 const cacheKey = renderContext.getCacheKey(); 42753 let descriptorBase = descriptors[cacheKey]; 42754 if (descriptorBase === void 0) { 42755 const textures = renderContext.textures; 42756 const textureViews = []; 42757 let sliceIndex; 42758 const isRenderCameraDepthArray = this._isRenderCameraDepthArray(renderContext); 42759 for (let i = 0; i < textures.length; i++) { 42760 const textureData = this.get(textures[i]); 42761 const viewDescriptor = { 42762 label: `colorAttachment_${i}`, 42763 baseMipLevel: renderContext.activeMipmapLevel, 42764 mipLevelCount: 1, 42765 baseArrayLayer: renderContext.activeCubeFace, 42766 arrayLayerCount: 1, 42767 dimension: GPUTextureViewDimension.TwoD 42768 }; 42769 if (renderTarget.isRenderTarget3D) { 42770 sliceIndex = renderContext.activeCubeFace; 42771 viewDescriptor.baseArrayLayer = 0; 42772 viewDescriptor.dimension = GPUTextureViewDimension.ThreeD; 42773 viewDescriptor.depthOrArrayLayers = textures[i].image.depth; 42774 } else if (renderTarget.isRenderTarget && textures[i].image.depth > 1) { 42775 if (isRenderCameraDepthArray === true) { 42776 const cameras = renderContext.camera.cameras; 42777 for (let layer = 0; layer < cameras.length; layer++) { 42778 const layerViewDescriptor = { 42779 ...viewDescriptor, 42780 baseArrayLayer: layer, 42781 arrayLayerCount: 1, 42782 dimension: GPUTextureViewDimension.TwoD 42783 }; 42784 const textureView = textureData.texture.createView(layerViewDescriptor); 42785 textureViews.push({ 42786 view: textureView, 42787 resolveTarget: void 0, 42788 depthSlice: void 0 42789 }); 42790 } 42791 } else { 42792 viewDescriptor.dimension = GPUTextureViewDimension.TwoDArray; 42793 viewDescriptor.depthOrArrayLayers = textures[i].image.depth; 42794 } 42795 } 42796 if (isRenderCameraDepthArray !== true) { 42797 const textureView = textureData.texture.createView(viewDescriptor); 42798 let view, resolveTarget; 42799 if (textureData.msaaTexture !== void 0) { 42800 view = textureData.msaaTexture.createView(); 42801 resolveTarget = textureView; 42802 } else { 42803 view = textureView; 42804 resolveTarget = void 0; 42805 } 42806 textureViews.push({ 42807 view, 42808 resolveTarget, 42809 depthSlice: sliceIndex 42810 }); 42811 } 42812 } 42813 descriptorBase = { textureViews }; 42814 if (renderContext.depth) { 42815 const depthTextureData = this.get(renderContext.depthTexture); 42816 const options = {}; 42817 if (renderContext.depthTexture.isArrayTexture || renderContext.depthTexture.isCubeTexture) { 42818 options.dimension = GPUTextureViewDimension.TwoD; 42819 options.arrayLayerCount = 1; 42820 options.baseArrayLayer = renderContext.activeCubeFace; 42821 } 42822 descriptorBase.depthStencilView = depthTextureData.texture.createView(options); 42823 } 42824 descriptors[cacheKey] = descriptorBase; 42825 renderTargetData.width = renderTarget.width; 42826 renderTargetData.height = renderTarget.height; 42827 renderTargetData.samples = renderTarget.samples; 42828 renderTargetData.activeMipmapLevel = renderContext.activeMipmapLevel; 42829 renderTargetData.activeCubeFace = renderContext.activeCubeFace; 42830 } 42831 const descriptor = { 42832 colorAttachments: [] 42833 }; 42834 for (let i = 0; i < descriptorBase.textureViews.length; i++) { 42835 const viewInfo = descriptorBase.textureViews[i]; 42836 let clearValue = { r: 0, g: 0, b: 0, a: 1 }; 42837 if (i === 0 && colorAttachmentsConfig.clearValue) { 42838 clearValue = colorAttachmentsConfig.clearValue; 42839 } 42840 descriptor.colorAttachments.push({ 42841 view: viewInfo.view, 42842 depthSlice: viewInfo.depthSlice, 42843 resolveTarget: viewInfo.resolveTarget, 42844 loadOp: colorAttachmentsConfig.loadOp || GPULoadOp.Load, 42845 storeOp: colorAttachmentsConfig.storeOp || GPUStoreOp.Store, 42846 clearValue 42847 }); 42848 } 42849 if (descriptorBase.depthStencilView) { 42850 descriptor.depthStencilAttachment = { 42851 view: descriptorBase.depthStencilView 42852 }; 42853 } 42854 return descriptor; 42855 } 42856 /** 42857 * This method is executed at the beginning of a render call and prepares 42858 * the WebGPU state for upcoming render calls 42859 * 42860 * @param {RenderContext} renderContext - The render context. 42861 */ 42862 beginRender(renderContext) { 42863 const renderContextData = this.get(renderContext); 42864 const device = this.device; 42865 const occlusionQueryCount = renderContext.occlusionQueryCount; 42866 let occlusionQuerySet; 42867 if (occlusionQueryCount > 0) { 42868 if (renderContextData.currentOcclusionQuerySet) renderContextData.currentOcclusionQuerySet.destroy(); 42869 if (renderContextData.currentOcclusionQueryBuffer) renderContextData.currentOcclusionQueryBuffer.destroy(); 42870 renderContextData.currentOcclusionQuerySet = renderContextData.occlusionQuerySet; 42871 renderContextData.currentOcclusionQueryBuffer = renderContextData.occlusionQueryBuffer; 42872 renderContextData.currentOcclusionQueryObjects = renderContextData.occlusionQueryObjects; 42873 occlusionQuerySet = device.createQuerySet({ type: "occlusion", count: occlusionQueryCount, label: `occlusionQuerySet_${renderContext.id}` }); 42874 renderContextData.occlusionQuerySet = occlusionQuerySet; 42875 renderContextData.occlusionQueryIndex = 0; 42876 renderContextData.occlusionQueryObjects = new Array(occlusionQueryCount); 42877 renderContextData.lastOcclusionObject = null; 42878 } 42879 let descriptor; 42880 if (renderContext.textures === null) { 42881 descriptor = this._getDefaultRenderPassDescriptor(); 42882 } else { 42883 descriptor = this._getRenderPassDescriptor(renderContext, { loadOp: GPULoadOp.Load }); 42884 } 42885 this.initTimestampQuery(TimestampQuery.RENDER, this.getTimestampUID(renderContext), descriptor); 42886 descriptor.occlusionQuerySet = occlusionQuerySet; 42887 const depthStencilAttachment = descriptor.depthStencilAttachment; 42888 if (renderContext.textures !== null) { 42889 const colorAttachments = descriptor.colorAttachments; 42890 for (let i = 0; i < colorAttachments.length; i++) { 42891 const colorAttachment = colorAttachments[i]; 42892 if (renderContext.clearColor) { 42893 if (i === 0) { 42894 colorAttachment.clearValue = renderContext.clearColorValue; 42895 } else { 42896 _clearValue.r = 0; 42897 _clearValue.g = 0; 42898 _clearValue.b = 0; 42899 _clearValue.a = 1; 42900 colorAttachment.clearValue = _clearValue; 42901 } 42902 colorAttachment.loadOp = GPULoadOp.Clear; 42903 } else { 42904 colorAttachment.loadOp = GPULoadOp.Load; 42905 } 42906 colorAttachment.storeOp = GPUStoreOp.Store; 42907 } 42908 } else { 42909 const colorAttachment = descriptor.colorAttachments[0]; 42910 if (renderContext.clearColor) { 42911 colorAttachment.clearValue = renderContext.clearColorValue; 42912 colorAttachment.loadOp = GPULoadOp.Clear; 42913 } else { 42914 colorAttachment.loadOp = GPULoadOp.Load; 42915 } 42916 colorAttachment.storeOp = GPUStoreOp.Store; 42917 } 42918 if (renderContext.depth) { 42919 if (renderContext.clearDepth) { 42920 depthStencilAttachment.depthClearValue = renderContext.clearDepthValue; 42921 depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; 42922 } else { 42923 depthStencilAttachment.depthLoadOp = GPULoadOp.Load; 42924 } 42925 depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; 42926 } 42927 if (renderContext.stencil) { 42928 if (renderContext.clearStencil) { 42929 depthStencilAttachment.stencilClearValue = renderContext.clearStencilValue; 42930 depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; 42931 } else { 42932 depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; 42933 } 42934 depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; 42935 } 42936 const encoder = device.createCommandEncoder({ label: "renderContext_" + renderContext.id }); 42937 if (this._isRenderCameraDepthArray(renderContext) === true) { 42938 const cameras = renderContext.camera.cameras; 42939 if (!renderContextData.layerDescriptors || renderContextData.layerDescriptors.length !== cameras.length) { 42940 this._createDepthLayerDescriptors(renderContext, renderContextData, descriptor, cameras); 42941 } else { 42942 this._updateDepthLayerDescriptors(renderContext, renderContextData, cameras); 42943 } 42944 renderContextData.bundleEncoders = []; 42945 renderContextData.bundleSets = []; 42946 for (let i = 0; i < cameras.length; i++) { 42947 const bundleEncoder = this.pipelineUtils.createBundleEncoder( 42948 renderContext, 42949 "renderBundleArrayCamera_" + i 42950 ); 42951 const bundleSets = { 42952 attributes: {}, 42953 bindingGroups: [], 42954 pipeline: null, 42955 index: null 42956 }; 42957 renderContextData.bundleEncoders.push(bundleEncoder); 42958 renderContextData.bundleSets.push(bundleSets); 42959 } 42960 renderContextData.currentPass = null; 42961 } else { 42962 const currentPass = encoder.beginRenderPass(descriptor); 42963 renderContextData.currentPass = currentPass; 42964 if (renderContext.viewport) { 42965 this.updateViewport(renderContext); 42966 } 42967 if (renderContext.scissor) { 42968 this.updateScissor(renderContext); 42969 } 42970 } 42971 renderContextData.descriptor = descriptor; 42972 renderContextData.encoder = encoder; 42973 renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; 42974 renderContextData.renderBundles = []; 42975 } 42976 /** 42977 * This method creates layer descriptors for each camera in an array camera 42978 * to prepare for rendering to a depth array texture. 42979 * 42980 * @param {RenderContext} renderContext - The render context. 42981 * @param {Object} renderContextData - The render context data. 42982 * @param {Object} descriptor - The render pass descriptor. 42983 * @param {ArrayCamera} cameras - The array camera. 42984 * 42985 * @private 42986 */ 42987 _createDepthLayerDescriptors(renderContext, renderContextData, descriptor, cameras) { 42988 const depthStencilAttachment = descriptor.depthStencilAttachment; 42989 renderContextData.layerDescriptors = []; 42990 const depthTextureData = this.get(renderContext.depthTexture); 42991 if (!depthTextureData.viewCache) { 42992 depthTextureData.viewCache = []; 42993 } 42994 for (let i = 0; i < cameras.length; i++) { 42995 const layerDescriptor = { 42996 ...descriptor, 42997 colorAttachments: [{ 42998 ...descriptor.colorAttachments[0], 42999 view: descriptor.colorAttachments[i].view 43000 }] 43001 }; 43002 if (descriptor.depthStencilAttachment) { 43003 const layerIndex = i; 43004 if (!depthTextureData.viewCache[layerIndex]) { 43005 depthTextureData.viewCache[layerIndex] = depthTextureData.texture.createView({ 43006 dimension: GPUTextureViewDimension.TwoD, 43007 baseArrayLayer: i, 43008 arrayLayerCount: 1 43009 }); 43010 } 43011 layerDescriptor.depthStencilAttachment = { 43012 view: depthTextureData.viewCache[layerIndex], 43013 depthLoadOp: depthStencilAttachment.depthLoadOp || GPULoadOp.Clear, 43014 depthStoreOp: depthStencilAttachment.depthStoreOp || GPUStoreOp.Store, 43015 depthClearValue: depthStencilAttachment.depthClearValue || 1 43016 }; 43017 if (renderContext.stencil) { 43018 layerDescriptor.depthStencilAttachment.stencilLoadOp = depthStencilAttachment.stencilLoadOp; 43019 layerDescriptor.depthStencilAttachment.stencilStoreOp = depthStencilAttachment.stencilStoreOp; 43020 layerDescriptor.depthStencilAttachment.stencilClearValue = depthStencilAttachment.stencilClearValue; 43021 } 43022 } else { 43023 layerDescriptor.depthStencilAttachment = { ...depthStencilAttachment }; 43024 } 43025 renderContextData.layerDescriptors.push(layerDescriptor); 43026 } 43027 } 43028 /** 43029 * This method updates the layer descriptors for each camera in an array camera 43030 * to prepare for rendering to a depth array texture. 43031 * 43032 * @param {RenderContext} renderContext - The render context. 43033 * @param {Object} renderContextData - The render context data. 43034 * @param {ArrayCamera} cameras - The array camera. 43035 * 43036 */ 43037 _updateDepthLayerDescriptors(renderContext, renderContextData, cameras) { 43038 for (let i = 0; i < cameras.length; i++) { 43039 const layerDescriptor = renderContextData.layerDescriptors[i]; 43040 if (layerDescriptor.depthStencilAttachment) { 43041 const depthAttachment = layerDescriptor.depthStencilAttachment; 43042 if (renderContext.depth) { 43043 if (renderContext.clearDepth) { 43044 depthAttachment.depthClearValue = renderContext.clearDepthValue; 43045 depthAttachment.depthLoadOp = GPULoadOp.Clear; 43046 } else { 43047 depthAttachment.depthLoadOp = GPULoadOp.Load; 43048 } 43049 } 43050 if (renderContext.stencil) { 43051 if (renderContext.clearStencil) { 43052 depthAttachment.stencilClearValue = renderContext.clearStencilValue; 43053 depthAttachment.stencilLoadOp = GPULoadOp.Clear; 43054 } else { 43055 depthAttachment.stencilLoadOp = GPULoadOp.Load; 43056 } 43057 } 43058 } 43059 } 43060 } 43061 /** 43062 * This method is executed at the end of a render call and finalizes work 43063 * after draw calls. 43064 * 43065 * @param {RenderContext} renderContext - The render context. 43066 */ 43067 finishRender(renderContext) { 43068 const renderContextData = this.get(renderContext); 43069 const occlusionQueryCount = renderContext.occlusionQueryCount; 43070 if (renderContextData.renderBundles.length > 0) { 43071 renderContextData.currentPass.executeBundles(renderContextData.renderBundles); 43072 } 43073 if (occlusionQueryCount > renderContextData.occlusionQueryIndex) { 43074 renderContextData.currentPass.endOcclusionQuery(); 43075 } 43076 const encoder = renderContextData.encoder; 43077 if (this._isRenderCameraDepthArray(renderContext) === true) { 43078 const bundles = []; 43079 for (let i = 0; i < renderContextData.bundleEncoders.length; i++) { 43080 const bundleEncoder = renderContextData.bundleEncoders[i]; 43081 bundles.push(bundleEncoder.finish()); 43082 } 43083 for (let i = 0; i < renderContextData.layerDescriptors.length; i++) { 43084 if (i < bundles.length) { 43085 const layerDescriptor = renderContextData.layerDescriptors[i]; 43086 const renderPass = encoder.beginRenderPass(layerDescriptor); 43087 if (renderContext.viewport) { 43088 const { x, y, width, height, minDepth, maxDepth } = renderContext.viewportValue; 43089 renderPass.setViewport(x, y, width, height, minDepth, maxDepth); 43090 } 43091 if (renderContext.scissor) { 43092 const { x, y, width, height } = renderContext.scissorValue; 43093 renderPass.setScissorRect(x, y, width, height); 43094 } 43095 renderPass.executeBundles([bundles[i]]); 43096 renderPass.end(); 43097 } 43098 } 43099 } else if (renderContextData.currentPass) { 43100 renderContextData.currentPass.end(); 43101 } 43102 if (occlusionQueryCount > 0) { 43103 const bufferSize = occlusionQueryCount * 8; 43104 let queryResolveBuffer = this.occludedResolveCache.get(bufferSize); 43105 if (queryResolveBuffer === void 0) { 43106 queryResolveBuffer = this.device.createBuffer( 43107 { 43108 size: bufferSize, 43109 usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC 43110 } 43111 ); 43112 this.occludedResolveCache.set(bufferSize, queryResolveBuffer); 43113 } 43114 const readBuffer = this.device.createBuffer( 43115 { 43116 size: bufferSize, 43117 usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 43118 } 43119 ); 43120 renderContextData.encoder.resolveQuerySet(renderContextData.occlusionQuerySet, 0, occlusionQueryCount, queryResolveBuffer, 0); 43121 renderContextData.encoder.copyBufferToBuffer(queryResolveBuffer, 0, readBuffer, 0, bufferSize); 43122 renderContextData.occlusionQueryBuffer = readBuffer; 43123 this.resolveOccludedAsync(renderContext); 43124 } 43125 this.device.queue.submit([renderContextData.encoder.finish()]); 43126 if (renderContext.textures !== null) { 43127 const textures = renderContext.textures; 43128 for (let i = 0; i < textures.length; i++) { 43129 const texture3 = textures[i]; 43130 if (texture3.generateMipmaps === true) { 43131 this.textureUtils.generateMipmaps(texture3); 43132 } 43133 } 43134 } 43135 } 43136 /** 43137 * Returns `true` if the given 3D object is fully occluded by other 43138 * 3D objects in the scene. 43139 * 43140 * @param {RenderContext} renderContext - The render context. 43141 * @param {Object3D} object - The 3D object to test. 43142 * @return {boolean} Whether the 3D object is fully occluded or not. 43143 */ 43144 isOccluded(renderContext, object) { 43145 const renderContextData = this.get(renderContext); 43146 return renderContextData.occluded && renderContextData.occluded.has(object); 43147 } 43148 /** 43149 * This method processes the result of occlusion queries and writes it 43150 * into render context data. 43151 * 43152 * @async 43153 * @param {RenderContext} renderContext - The render context. 43154 * @return {Promise} A Promise that resolves when the occlusion query results have been processed. 43155 */ 43156 async resolveOccludedAsync(renderContext) { 43157 const renderContextData = this.get(renderContext); 43158 const { currentOcclusionQueryBuffer, currentOcclusionQueryObjects } = renderContextData; 43159 if (currentOcclusionQueryBuffer && currentOcclusionQueryObjects) { 43160 const occluded = /* @__PURE__ */ new WeakSet(); 43161 renderContextData.currentOcclusionQueryObjects = null; 43162 renderContextData.currentOcclusionQueryBuffer = null; 43163 await currentOcclusionQueryBuffer.mapAsync(GPUMapMode.READ); 43164 const buffer3 = currentOcclusionQueryBuffer.getMappedRange(); 43165 const results = new BigUint64Array(buffer3); 43166 for (let i = 0; i < currentOcclusionQueryObjects.length; i++) { 43167 if (results[i] === BigInt(0)) { 43168 occluded.add(currentOcclusionQueryObjects[i]); 43169 } 43170 } 43171 currentOcclusionQueryBuffer.destroy(); 43172 renderContextData.occluded = occluded; 43173 } 43174 } 43175 /** 43176 * Updates the viewport with the values from the given render context. 43177 * 43178 * @param {RenderContext} renderContext - The render context. 43179 */ 43180 updateViewport(renderContext) { 43181 const { currentPass } = this.get(renderContext); 43182 const { x, y, width, height, minDepth, maxDepth } = renderContext.viewportValue; 43183 currentPass.setViewport(x, y, width, height, minDepth, maxDepth); 43184 } 43185 /** 43186 * Updates the scissor with the values from the given render context. 43187 * 43188 * @param {RenderContext} renderContext - The render context. 43189 */ 43190 updateScissor(renderContext) { 43191 const { currentPass } = this.get(renderContext); 43192 const { x, y, width, height } = renderContext.scissorValue; 43193 currentPass.setScissorRect(x, y, width, height); 43194 } 43195 /** 43196 * Returns the clear color and alpha into a single 43197 * color object. 43198 * 43199 * @return {Color4} The clear color. 43200 */ 43201 getClearColor() { 43202 const clearColor = super.getClearColor(); 43203 if (this.renderer.alpha === true) { 43204 clearColor.r *= clearColor.a; 43205 clearColor.g *= clearColor.a; 43206 clearColor.b *= clearColor.a; 43207 } 43208 return clearColor; 43209 } 43210 /** 43211 * Performs a clear operation. 43212 * 43213 * @param {boolean} color - Whether the color buffer should be cleared or not. 43214 * @param {boolean} depth - Whether the depth buffer should be cleared or not. 43215 * @param {boolean} stencil - Whether the stencil buffer should be cleared or not. 43216 * @param {?RenderContext} [renderTargetContext=null] - The render context of the current set render target. 43217 */ 43218 clear(color3, depth3, stencil, renderTargetContext = null) { 43219 const device = this.device; 43220 const renderer = this.renderer; 43221 let colorAttachments = []; 43222 let depthStencilAttachment; 43223 let supportsDepth; 43224 let supportsStencil; 43225 if (color3) { 43226 const clearColor = this.getClearColor(); 43227 _clearValue.r = clearColor.r; 43228 _clearValue.g = clearColor.g; 43229 _clearValue.b = clearColor.b; 43230 _clearValue.a = clearColor.a; 43231 } 43232 if (renderTargetContext === null) { 43233 supportsDepth = renderer.depth; 43234 supportsStencil = renderer.stencil; 43235 const descriptor = this._getDefaultRenderPassDescriptor(); 43236 if (color3) { 43237 colorAttachments = descriptor.colorAttachments; 43238 const colorAttachment = colorAttachments[0]; 43239 colorAttachment.clearValue = _clearValue; 43240 colorAttachment.loadOp = GPULoadOp.Clear; 43241 colorAttachment.storeOp = GPUStoreOp.Store; 43242 } 43243 if (supportsDepth || supportsStencil) { 43244 depthStencilAttachment = descriptor.depthStencilAttachment; 43245 } 43246 } else { 43247 supportsDepth = renderTargetContext.depth; 43248 supportsStencil = renderTargetContext.stencil; 43249 const clearConfig = { 43250 loadOp: color3 ? GPULoadOp.Clear : GPULoadOp.Load, 43251 clearValue: color3 ? _clearValue : void 0 43252 }; 43253 if (supportsDepth) { 43254 clearConfig.depthLoadOp = depth3 ? GPULoadOp.Clear : GPULoadOp.Load; 43255 clearConfig.depthClearValue = depth3 ? renderer.getClearDepth() : void 0; 43256 clearConfig.depthStoreOp = GPUStoreOp.Store; 43257 } 43258 if (supportsStencil) { 43259 clearConfig.stencilLoadOp = stencil ? GPULoadOp.Clear : GPULoadOp.Load; 43260 clearConfig.stencilClearValue = stencil ? renderer.getClearStencil() : void 0; 43261 clearConfig.stencilStoreOp = GPUStoreOp.Store; 43262 } 43263 const descriptor = this._getRenderPassDescriptor(renderTargetContext, clearConfig); 43264 colorAttachments = descriptor.colorAttachments; 43265 depthStencilAttachment = descriptor.depthStencilAttachment; 43266 } 43267 if (supportsDepth && depthStencilAttachment) { 43268 if (depth3) { 43269 depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; 43270 depthStencilAttachment.depthClearValue = renderer.getClearDepth(); 43271 depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; 43272 } else { 43273 depthStencilAttachment.depthLoadOp = GPULoadOp.Load; 43274 depthStencilAttachment.depthStoreOp = GPUStoreOp.Store; 43275 } 43276 } 43277 if (supportsStencil && depthStencilAttachment) { 43278 if (stencil) { 43279 depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; 43280 depthStencilAttachment.stencilClearValue = renderer.getClearStencil(); 43281 depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; 43282 } else { 43283 depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; 43284 depthStencilAttachment.stencilStoreOp = GPUStoreOp.Store; 43285 } 43286 } 43287 const encoder = device.createCommandEncoder({ label: "clear" }); 43288 const currentPass = encoder.beginRenderPass({ 43289 colorAttachments, 43290 depthStencilAttachment 43291 }); 43292 currentPass.end(); 43293 device.queue.submit([encoder.finish()]); 43294 } 43295 // compute 43296 /** 43297 * This method is executed at the beginning of a compute call and 43298 * prepares the state for upcoming compute tasks. 43299 * 43300 * @param {Node|Array<Node>} computeGroup - The compute node(s). 43301 */ 43302 beginCompute(computeGroup) { 43303 const groupGPU = this.get(computeGroup); 43304 const descriptor = { 43305 label: "computeGroup_" + computeGroup.id 43306 }; 43307 this.initTimestampQuery(TimestampQuery.COMPUTE, this.getTimestampUID(computeGroup), descriptor); 43308 groupGPU.cmdEncoderGPU = this.device.createCommandEncoder({ label: "computeGroup_" + computeGroup.id }); 43309 groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass(descriptor); 43310 } 43311 /** 43312 * Executes a compute command for the given compute node. 43313 * 43314 * @param {Node|Array<Node>} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. 43315 * @param {Node} computeNode - The compute node. 43316 * @param {Array<BindGroup>} bindings - The bindings. 43317 * @param {ComputePipeline} pipeline - The compute pipeline. 43318 * @param {number|Array<number>|IndirectStorageBufferAttribute} [dispatchSize=null] 43319 * - A single number representing count, or 43320 * - An array [x, y, z] representing dispatch size, or 43321 * - A IndirectStorageBufferAttribute for indirect dispatch size. 43322 */ 43323 compute(computeGroup, computeNode, bindings, pipeline, dispatchSize = null) { 43324 const computeNodeData = this.get(computeNode); 43325 const { passEncoderGPU } = this.get(computeGroup); 43326 const pipelineGPU = this.get(pipeline).pipeline; 43327 this.pipelineUtils.setPipeline(passEncoderGPU, pipelineGPU); 43328 for (let i = 0, l = bindings.length; i < l; i++) { 43329 const bindGroup = bindings[i]; 43330 const bindingsData = this.get(bindGroup); 43331 passEncoderGPU.setBindGroup(i, bindingsData.group); 43332 } 43333 if (dispatchSize === null) { 43334 dispatchSize = computeNode.dispatchSize || computeNode.count; 43335 } 43336 if (dispatchSize && dispatchSize.isIndirectStorageBufferAttribute) { 43337 const dispatchBuffer = this.get(dispatchSize).buffer; 43338 passEncoderGPU.dispatchWorkgroupsIndirect(dispatchBuffer, 0); 43339 return; 43340 } 43341 if (typeof dispatchSize === "number") { 43342 const count = dispatchSize; 43343 if (computeNodeData.dispatchSize === void 0 || computeNodeData.count !== count) { 43344 computeNodeData.dispatchSize = [0, 1, 1]; 43345 computeNodeData.count = count; 43346 const workgroupSize = computeNode.workgroupSize; 43347 let size3 = workgroupSize[0]; 43348 for (let i = 1; i < workgroupSize.length; i++) 43349 size3 *= workgroupSize[i]; 43350 const dispatchCount = Math.ceil(count / size3); 43351 const maxComputeWorkgroupsPerDimension = this.device.limits.maxComputeWorkgroupsPerDimension; 43352 dispatchSize = [dispatchCount, 1, 1]; 43353 if (dispatchCount > maxComputeWorkgroupsPerDimension) { 43354 dispatchSize[0] = Math.min(dispatchCount, maxComputeWorkgroupsPerDimension); 43355 dispatchSize[1] = Math.ceil(dispatchCount / maxComputeWorkgroupsPerDimension); 43356 } 43357 computeNodeData.dispatchSize = dispatchSize; 43358 } 43359 dispatchSize = computeNodeData.dispatchSize; 43360 } 43361 passEncoderGPU.dispatchWorkgroups( 43362 dispatchSize[0], 43363 dispatchSize[1] || 1, 43364 dispatchSize[2] || 1 43365 ); 43366 } 43367 /** 43368 * This method is executed at the end of a compute call and 43369 * finalizes work after compute tasks. 43370 * 43371 * @param {Node|Array<Node>} computeGroup - The compute node(s). 43372 */ 43373 finishCompute(computeGroup) { 43374 const groupData = this.get(computeGroup); 43375 groupData.passEncoderGPU.end(); 43376 this.device.queue.submit([groupData.cmdEncoderGPU.finish()]); 43377 } 43378 /** 43379 * Internal draw function that performs the draw with the given pass encoder. 43380 * 43381 * @private 43382 * @param {RenderObject} renderObject - The render object. 43383 * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. 43384 * @param {Object} renderContextData - The render context data object, holding current pass state and occlusion query tracking. 43385 * @param {GPURenderPipeline} pipelineGPU - The GPU render pipeline. 43386 * @param {Array<BindGroup>} bindings - The bind groups. 43387 * @param {Array<BufferAttribute>} vertexBuffers - The vertex buffers. 43388 * @param {{vertexCount: number, firstVertex: number, instanceCount: number, firstInstance: number}} drawParams - The draw parameters. 43389 * @param {GPURenderPassEncoder|GPURenderBundleEncoder} passEncoderGPU - The GPU pass encoder used for recording draw commands. 43390 * @param {Object} currentSets - Tracking object for currently set pipeline, attributes, bind groups, and index state. 43391 */ 43392 _draw(renderObject, info, renderContextData, pipelineGPU, bindings, vertexBuffers, drawParams, passEncoderGPU, currentSets) { 43393 const { object, material, context: context3 } = renderObject; 43394 const index = renderObject.getIndex(); 43395 const hasIndex = index !== null; 43396 this.pipelineUtils.setPipeline(passEncoderGPU, pipelineGPU); 43397 currentSets.pipeline = pipelineGPU; 43398 const currentBindingGroups = currentSets.bindingGroups; 43399 for (let i = 0, l = bindings.length; i < l; i++) { 43400 const bindGroup = bindings[i]; 43401 const bindingsData = this.get(bindGroup); 43402 if (currentBindingGroups[i] !== bindGroup.id) { 43403 passEncoderGPU.setBindGroup(i, bindingsData.group); 43404 currentBindingGroups[i] = bindGroup.id; 43405 } 43406 } 43407 if (hasIndex === true) { 43408 if (currentSets.index !== index) { 43409 const buffer3 = this.get(index).buffer; 43410 const indexFormat = index.array instanceof Uint16Array ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32; 43411 passEncoderGPU.setIndexBuffer(buffer3, indexFormat); 43412 currentSets.index = index; 43413 } 43414 } 43415 for (let i = 0, l = vertexBuffers.length; i < l; i++) { 43416 const vertexBuffer = vertexBuffers[i]; 43417 if (currentSets.attributes[i] !== vertexBuffer) { 43418 const buffer3 = this.get(vertexBuffer).buffer; 43419 passEncoderGPU.setVertexBuffer(i, buffer3); 43420 currentSets.attributes[i] = vertexBuffer; 43421 } 43422 } 43423 if (context3.stencil === true && material.stencilWrite === true && renderContextData.currentStencilRef !== material.stencilRef) { 43424 passEncoderGPU.setStencilReference(material.stencilRef); 43425 renderContextData.currentStencilRef = material.stencilRef; 43426 } 43427 if (object.isBatchedMesh === true) { 43428 const starts = object._multiDrawStarts; 43429 const counts = object._multiDrawCounts; 43430 const drawCount = object._multiDrawCount; 43431 let bytesPerElement = hasIndex === true ? index.array.BYTES_PER_ELEMENT : 1; 43432 if (material.wireframe) { 43433 bytesPerElement = object.geometry.attributes.position.count > 65535 ? 4 : 2; 43434 } 43435 for (let i = 0; i < drawCount; i++) { 43436 if (hasIndex === true) { 43437 passEncoderGPU.drawIndexed(counts[i], 1, starts[i] / bytesPerElement, 0, i); 43438 } else { 43439 passEncoderGPU.draw(counts[i], 1, starts[i], i); 43440 } 43441 info.update(object, counts[i], 1); 43442 } 43443 } else if (hasIndex === true) { 43444 const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParams; 43445 const indirect = renderObject.getIndirect(); 43446 if (indirect !== null) { 43447 const buffer3 = this.get(indirect).buffer; 43448 const indirectOffset = renderObject.getIndirectOffset(); 43449 const indirectOffsets = Array.isArray(indirectOffset) ? indirectOffset : [indirectOffset]; 43450 for (let i = 0; i < indirectOffsets.length; i++) { 43451 passEncoderGPU.drawIndexedIndirect(buffer3, indirectOffsets[i]); 43452 } 43453 } else { 43454 passEncoderGPU.drawIndexed(indexCount, instanceCount, firstIndex, 0, 0); 43455 } 43456 info.update(object, indexCount, instanceCount); 43457 } else { 43458 const { vertexCount, instanceCount, firstVertex } = drawParams; 43459 const indirect = renderObject.getIndirect(); 43460 if (indirect !== null) { 43461 const buffer3 = this.get(indirect).buffer; 43462 const indirectOffset = renderObject.getIndirectOffset(); 43463 const indirectOffsets = Array.isArray(indirectOffset) ? indirectOffset : [indirectOffset]; 43464 for (let i = 0; i < indirectOffsets.length; i++) { 43465 passEncoderGPU.drawIndirect(buffer3, indirectOffsets[i]); 43466 } 43467 } else { 43468 passEncoderGPU.draw(vertexCount, instanceCount, firstVertex, 0); 43469 } 43470 info.update(object, vertexCount, instanceCount); 43471 } 43472 } 43473 // render object 43474 /** 43475 * Executes a draw command for the given render object. 43476 * 43477 * @param {RenderObject} renderObject - The render object to draw. 43478 * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. 43479 */ 43480 draw(renderObject, info) { 43481 const { object, context: context3, pipeline } = renderObject; 43482 const renderContextData = this.get(context3); 43483 const pipelineData = this.get(pipeline); 43484 const pipelineGPU = pipelineData.pipeline; 43485 if (pipelineData.error === true) return; 43486 const drawParams = renderObject.getDrawParameters(); 43487 if (drawParams === null) return; 43488 const bindings = renderObject.getBindings(); 43489 const vertexBuffers = renderObject.getVertexBuffers(); 43490 if (renderObject.camera.isArrayCamera && renderObject.camera.cameras.length > 0) { 43491 const cameraData = this.get(renderObject.camera); 43492 const cameras = renderObject.camera.cameras; 43493 const cameraIndex3 = renderObject.getBindingGroup("cameraIndex"); 43494 if (cameraData.indexesGPU === void 0 || cameraData.indexesGPU.length !== cameras.length) { 43495 const bindingsData = this.get(cameraIndex3); 43496 const indexesGPU = []; 43497 const data = new Uint32Array([0, 0, 0, 0]); 43498 for (let i = 0, len = cameras.length; i < len; i++) { 43499 data[0] = i; 43500 const { layoutGPU } = bindingsData.layout; 43501 const bindGroupIndex = this.bindingUtils.createBindGroupIndex(data, layoutGPU); 43502 indexesGPU.push(bindGroupIndex); 43503 } 43504 cameraData.indexesGPU = indexesGPU; 43505 } 43506 const pixelRatio = this.renderer.getPixelRatio(); 43507 for (let i = 0, len = cameras.length; i < len; i++) { 43508 const subCamera = cameras[i]; 43509 if (object.layers.test(subCamera.layers)) { 43510 const vp = subCamera.viewport; 43511 let pass3 = renderContextData.currentPass; 43512 let sets = renderContextData.currentSets; 43513 if (renderContextData.bundleEncoders) { 43514 const bundleEncoder = renderContextData.bundleEncoders[i]; 43515 const bundleSets = renderContextData.bundleSets[i]; 43516 pass3 = bundleEncoder; 43517 sets = bundleSets; 43518 } 43519 if (vp) { 43520 pass3.setViewport( 43521 Math.floor(vp.x * pixelRatio), 43522 Math.floor(vp.y * pixelRatio), 43523 Math.floor(vp.width * pixelRatio), 43524 Math.floor(vp.height * pixelRatio), 43525 context3.viewportValue.minDepth, 43526 context3.viewportValue.maxDepth 43527 ); 43528 } 43529 if (cameraIndex3 && cameraData.indexesGPU) { 43530 const indexPos = bindings.indexOf(cameraIndex3); 43531 pass3.setBindGroup(indexPos, cameraData.indexesGPU[i]); 43532 sets.bindingGroups[indexPos] = cameraIndex3.id; 43533 } 43534 this._draw(renderObject, info, renderContextData, pipelineGPU, bindings, vertexBuffers, drawParams, pass3, sets); 43535 } 43536 } 43537 } else { 43538 if (renderContextData.currentPass) { 43539 if (renderContextData.occlusionQuerySet !== void 0) { 43540 const lastObject = renderContextData.lastOcclusionObject; 43541 if (lastObject !== object) { 43542 if (lastObject !== null && lastObject.occlusionTest === true) { 43543 renderContextData.currentPass.endOcclusionQuery(); 43544 renderContextData.occlusionQueryIndex++; 43545 } 43546 if (object.occlusionTest === true) { 43547 renderContextData.currentPass.beginOcclusionQuery(renderContextData.occlusionQueryIndex); 43548 renderContextData.occlusionQueryObjects[renderContextData.occlusionQueryIndex] = object; 43549 } 43550 renderContextData.lastOcclusionObject = object; 43551 } 43552 } 43553 this._draw(renderObject, info, renderContextData, pipelineGPU, bindings, vertexBuffers, drawParams, renderContextData.currentPass, renderContextData.currentSets); 43554 } 43555 } 43556 } 43557 // cache key 43558 /** 43559 * Returns `true` if the render pipeline requires an update. 43560 * 43561 * @param {RenderObject} renderObject - The render object. 43562 * @return {boolean} Whether the render pipeline requires an update or not. 43563 */ 43564 needsRenderUpdate(renderObject) { 43565 const data = this.get(renderObject); 43566 const { object, material } = renderObject; 43567 const utils = this.utils; 43568 const sampleCount = utils.getSampleCountRenderContext(renderObject.context); 43569 const colorSpace = utils.getCurrentColorSpace(renderObject.context); 43570 const colorFormat = utils.getCurrentColorFormat(renderObject.context); 43571 const depthStencilFormat = utils.getCurrentDepthStencilFormat(renderObject.context); 43572 const primitiveTopology = utils.getPrimitiveTopology(object, material); 43573 let needsUpdate = false; 43574 if (data.material !== material || data.materialVersion !== material.version || data.transparent !== material.transparent || data.blending !== material.blending || data.premultipliedAlpha !== material.premultipliedAlpha || data.blendSrc !== material.blendSrc || data.blendDst !== material.blendDst || data.blendEquation !== material.blendEquation || data.blendSrcAlpha !== material.blendSrcAlpha || data.blendDstAlpha !== material.blendDstAlpha || data.blendEquationAlpha !== material.blendEquationAlpha || data.colorWrite !== material.colorWrite || data.depthWrite !== material.depthWrite || data.depthTest !== material.depthTest || data.depthFunc !== material.depthFunc || data.stencilWrite !== material.stencilWrite || data.stencilFunc !== material.stencilFunc || data.stencilFail !== material.stencilFail || data.stencilZFail !== material.stencilZFail || data.stencilZPass !== material.stencilZPass || data.stencilFuncMask !== material.stencilFuncMask || data.stencilWriteMask !== material.stencilWriteMask || data.side !== material.side || data.alphaToCoverage !== material.alphaToCoverage || data.sampleCount !== sampleCount || data.colorSpace !== colorSpace || data.colorFormat !== colorFormat || data.depthStencilFormat !== depthStencilFormat || data.primitiveTopology !== primitiveTopology || data.clippingContextCacheKey !== renderObject.clippingContextCacheKey) { 43575 data.material = material; 43576 data.materialVersion = material.version; 43577 data.transparent = material.transparent; 43578 data.blending = material.blending; 43579 data.premultipliedAlpha = material.premultipliedAlpha; 43580 data.blendSrc = material.blendSrc; 43581 data.blendDst = material.blendDst; 43582 data.blendEquation = material.blendEquation; 43583 data.blendSrcAlpha = material.blendSrcAlpha; 43584 data.blendDstAlpha = material.blendDstAlpha; 43585 data.blendEquationAlpha = material.blendEquationAlpha; 43586 data.colorWrite = material.colorWrite; 43587 data.depthWrite = material.depthWrite; 43588 data.depthTest = material.depthTest; 43589 data.depthFunc = material.depthFunc; 43590 data.stencilWrite = material.stencilWrite; 43591 data.stencilFunc = material.stencilFunc; 43592 data.stencilFail = material.stencilFail; 43593 data.stencilZFail = material.stencilZFail; 43594 data.stencilZPass = material.stencilZPass; 43595 data.stencilFuncMask = material.stencilFuncMask; 43596 data.stencilWriteMask = material.stencilWriteMask; 43597 data.side = material.side; 43598 data.alphaToCoverage = material.alphaToCoverage; 43599 data.sampleCount = sampleCount; 43600 data.colorSpace = colorSpace; 43601 data.colorFormat = colorFormat; 43602 data.depthStencilFormat = depthStencilFormat; 43603 data.primitiveTopology = primitiveTopology; 43604 data.clippingContextCacheKey = renderObject.clippingContextCacheKey; 43605 needsUpdate = true; 43606 } 43607 return needsUpdate; 43608 } 43609 /** 43610 * Returns a cache key that is used to identify render pipelines. 43611 * 43612 * @param {RenderObject} renderObject - The render object. 43613 * @return {string} The cache key. 43614 */ 43615 getRenderCacheKey(renderObject) { 43616 const { object, material } = renderObject; 43617 const utils = this.utils; 43618 const renderContext = renderObject.context; 43619 const frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0; 43620 return [ 43621 material.transparent, 43622 material.blending, 43623 material.premultipliedAlpha, 43624 material.blendSrc, 43625 material.blendDst, 43626 material.blendEquation, 43627 material.blendSrcAlpha, 43628 material.blendDstAlpha, 43629 material.blendEquationAlpha, 43630 material.colorWrite, 43631 material.depthWrite, 43632 material.depthTest, 43633 material.depthFunc, 43634 material.stencilWrite, 43635 material.stencilFunc, 43636 material.stencilFail, 43637 material.stencilZFail, 43638 material.stencilZPass, 43639 material.stencilFuncMask, 43640 material.stencilWriteMask, 43641 material.side, 43642 frontFaceCW, 43643 utils.getSampleCountRenderContext(renderContext), 43644 utils.getCurrentColorSpace(renderContext), 43645 utils.getCurrentColorFormat(renderContext), 43646 utils.getCurrentDepthStencilFormat(renderContext), 43647 utils.getPrimitiveTopology(object, material), 43648 renderObject.getGeometryCacheKey(), 43649 renderObject.clippingContextCacheKey 43650 ].join(); 43651 } 43652 // textures 43653 /** 43654 * Updates a GPU sampler for the given texture. 43655 * 43656 * @param {Texture} texture - The texture to update the sampler for. 43657 * @return {string} The current sampler key. 43658 */ 43659 updateSampler(texture3) { 43660 return this.textureUtils.updateSampler(texture3); 43661 } 43662 /** 43663 * Creates a default texture for the given texture that can be used 43664 * as a placeholder until the actual texture is ready for usage. 43665 * 43666 * @param {Texture} texture - The texture to create a default texture for. 43667 * @return {boolean} Whether the sampler has been updated or not. 43668 */ 43669 createDefaultTexture(texture3) { 43670 return this.textureUtils.createDefaultTexture(texture3); 43671 } 43672 /** 43673 * Defines a texture on the GPU for the given texture object. 43674 * 43675 * @param {Texture} texture - The texture. 43676 * @param {Object} [options={}] - Optional configuration parameter. 43677 */ 43678 createTexture(texture3, options) { 43679 this.textureUtils.createTexture(texture3, options); 43680 } 43681 /** 43682 * Uploads the updated texture data to the GPU. 43683 * 43684 * @param {Texture} texture - The texture. 43685 * @param {Object} [options={}] - Optional configuration parameter. 43686 */ 43687 updateTexture(texture3, options) { 43688 this.textureUtils.updateTexture(texture3, options); 43689 } 43690 /** 43691 * Generates mipmaps for the given texture. 43692 * 43693 * @param {Texture} texture - The texture. 43694 */ 43695 generateMipmaps(texture3) { 43696 this.textureUtils.generateMipmaps(texture3); 43697 } 43698 /** 43699 * Destroys the GPU data for the given texture object. 43700 * 43701 * @param {Texture} texture - The texture. 43702 * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. 43703 */ 43704 destroyTexture(texture3, isDefaultTexture = false) { 43705 this.textureUtils.destroyTexture(texture3, isDefaultTexture); 43706 } 43707 /** 43708 * Returns texture data as a typed array. 43709 * 43710 * @async 43711 * @param {Texture} texture - The texture to copy. 43712 * @param {number} x - The x coordinate of the copy origin. 43713 * @param {number} y - The y coordinate of the copy origin. 43714 * @param {number} width - The width of the copy. 43715 * @param {number} height - The height of the copy. 43716 * @param {number} faceIndex - The face index. 43717 * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished. 43718 */ 43719 async copyTextureToBuffer(texture3, x, y, width, height, faceIndex) { 43720 return this.textureUtils.copyTextureToBuffer(texture3, x, y, width, height, faceIndex); 43721 } 43722 /** 43723 * Inits a time stamp query for the given render context. 43724 * 43725 * @param {string} type - The type of the timestamp query (e.g. 'render', 'compute'). 43726 * @param {number} uid - Unique id for the context (e.g. render context id). 43727 * @param {Object} descriptor - The query descriptor. 43728 */ 43729 initTimestampQuery(type, uid, descriptor) { 43730 if (!this.trackTimestamp) return; 43731 if (!this.timestampQueryPool[type]) { 43732 this.timestampQueryPool[type] = new WebGPUTimestampQueryPool(this.device, type, 2048); 43733 } 43734 const timestampQueryPool = this.timestampQueryPool[type]; 43735 const baseOffset = timestampQueryPool.allocateQueriesForContext(uid); 43736 descriptor.timestampWrites = { 43737 querySet: timestampQueryPool.querySet, 43738 beginningOfPassWriteIndex: baseOffset, 43739 endOfPassWriteIndex: baseOffset + 1 43740 }; 43741 } 43742 // node builder 43743 /** 43744 * Returns a node builder for the given render object. 43745 * 43746 * @param {RenderObject} object - The render object. 43747 * @param {Renderer} renderer - The renderer. 43748 * @return {WGSLNodeBuilder} The node builder. 43749 */ 43750 createNodeBuilder(object, renderer) { 43751 return new WGSLNodeBuilder(object, renderer); 43752 } 43753 // program 43754 /** 43755 * Creates a shader program from the given programmable stage. 43756 * 43757 * @param {ProgrammableStage} program - The programmable stage. 43758 */ 43759 createProgram(program) { 43760 const programGPU = this.get(program); 43761 programGPU.module = { 43762 module: this.device.createShaderModule({ code: program.code, label: program.stage + (program.name !== "" ? `_${program.name}` : "") }), 43763 entryPoint: "main" 43764 }; 43765 } 43766 /** 43767 * Destroys the shader program of the given programmable stage. 43768 * 43769 * @param {ProgrammableStage} program - The programmable stage. 43770 */ 43771 destroyProgram(program) { 43772 this.delete(program); 43773 } 43774 // pipelines 43775 /** 43776 * Creates a render pipeline for the given render object. 43777 * 43778 * @param {RenderObject} renderObject - The render object. 43779 * @param {Array<Promise>} promises - An array of compilation promises which are used in `compileAsync()`. 43780 */ 43781 createRenderPipeline(renderObject, promises) { 43782 this.pipelineUtils.createRenderPipeline(renderObject, promises); 43783 } 43784 /** 43785 * Creates a compute pipeline for the given compute node. 43786 * 43787 * @param {ComputePipeline} computePipeline - The compute pipeline. 43788 * @param {Array<BindGroup>} bindings - The bindings. 43789 */ 43790 createComputePipeline(computePipeline, bindings) { 43791 this.pipelineUtils.createComputePipeline(computePipeline, bindings); 43792 } 43793 /** 43794 * Prepares the state for encoding render bundles. 43795 * 43796 * @param {RenderContext} renderContext - The render context. 43797 */ 43798 beginBundle(renderContext) { 43799 const renderContextData = this.get(renderContext); 43800 renderContextData._currentPass = renderContextData.currentPass; 43801 renderContextData._currentSets = renderContextData.currentSets; 43802 renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; 43803 renderContextData.currentPass = this.pipelineUtils.createBundleEncoder(renderContext); 43804 } 43805 /** 43806 * After processing render bundles this method finalizes related work. 43807 * 43808 * @param {RenderContext} renderContext - The render context. 43809 * @param {RenderBundle} bundle - The render bundle. 43810 */ 43811 finishBundle(renderContext, bundle) { 43812 const renderContextData = this.get(renderContext); 43813 const bundleEncoder = renderContextData.currentPass; 43814 const bundleGPU = bundleEncoder.finish(); 43815 this.get(bundle).bundleGPU = bundleGPU; 43816 renderContextData.currentSets = renderContextData._currentSets; 43817 renderContextData.currentPass = renderContextData._currentPass; 43818 } 43819 /** 43820 * Adds a render bundle to the render context data. 43821 * 43822 * @param {RenderContext} renderContext - The render context. 43823 * @param {RenderBundle} bundle - The render bundle to add. 43824 */ 43825 addBundle(renderContext, bundle) { 43826 const renderContextData = this.get(renderContext); 43827 renderContextData.renderBundles.push(this.get(bundle).bundleGPU); 43828 } 43829 // bindings 43830 /** 43831 * Creates bindings from the given bind group definition. 43832 * 43833 * @param {BindGroup} bindGroup - The bind group. 43834 * @param {Array<BindGroup>} bindings - Array of bind groups. 43835 * @param {number} cacheIndex - The cache index. 43836 * @param {number} version - The version. 43837 */ 43838 createBindings(bindGroup, bindings, cacheIndex, version) { 43839 this.bindingUtils.createBindings(bindGroup, bindings, cacheIndex, version); 43840 } 43841 /** 43842 * Updates the given bind group definition. 43843 * 43844 * @param {BindGroup} bindGroup - The bind group. 43845 * @param {Array<BindGroup>} bindings - Array of bind groups. 43846 * @param {number} cacheIndex - The cache index. 43847 * @param {number} version - The version. 43848 */ 43849 updateBindings(bindGroup, bindings, cacheIndex, version) { 43850 this.bindingUtils.createBindings(bindGroup, bindings, cacheIndex, version); 43851 } 43852 /** 43853 * Updates a buffer binding. 43854 * 43855 * @param {Buffer} binding - The buffer binding to update. 43856 */ 43857 updateBinding(binding) { 43858 this.bindingUtils.updateBinding(binding); 43859 } 43860 /** 43861 * Delete data associated with the current bind group. 43862 * 43863 * @param {BindGroup} bindGroup - The bind group. 43864 */ 43865 deleteBindGroupData(bindGroup) { 43866 this.bindingUtils.deleteBindGroupData(bindGroup); 43867 } 43868 // attributes 43869 /** 43870 * Creates the buffer of an indexed shader attribute. 43871 * 43872 * @param {BufferAttribute} attribute - The indexed buffer attribute. 43873 */ 43874 createIndexAttribute(attribute3) { 43875 let usage = GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST; 43876 if (attribute3.isStorageBufferAttribute || attribute3.isStorageInstancedBufferAttribute) { 43877 usage |= GPUBufferUsage.STORAGE; 43878 } 43879 this.attributeUtils.createAttribute(attribute3, usage); 43880 } 43881 /** 43882 * Creates the GPU buffer of a shader attribute. 43883 * 43884 * @param {BufferAttribute} attribute - The buffer attribute. 43885 */ 43886 createAttribute(attribute3) { 43887 this.attributeUtils.createAttribute(attribute3, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST); 43888 } 43889 /** 43890 * Creates the GPU buffer of a storage attribute. 43891 * 43892 * @param {BufferAttribute} attribute - The buffer attribute. 43893 */ 43894 createStorageAttribute(attribute3) { 43895 this.attributeUtils.createAttribute(attribute3, GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST); 43896 } 43897 /** 43898 * Creates the GPU buffer of an indirect storage attribute. 43899 * 43900 * @param {BufferAttribute} attribute - The buffer attribute. 43901 */ 43902 createIndirectStorageAttribute(attribute3) { 43903 this.attributeUtils.createAttribute(attribute3, GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST); 43904 } 43905 /** 43906 * Updates the GPU buffer of a shader attribute. 43907 * 43908 * @param {BufferAttribute} attribute - The buffer attribute to update. 43909 */ 43910 updateAttribute(attribute3) { 43911 this.attributeUtils.updateAttribute(attribute3); 43912 } 43913 /** 43914 * Destroys the GPU buffer of a shader attribute. 43915 * 43916 * @param {BufferAttribute} attribute - The buffer attribute to destroy. 43917 */ 43918 destroyAttribute(attribute3) { 43919 this.attributeUtils.destroyAttribute(attribute3); 43920 } 43921 // canvas 43922 /** 43923 * Triggers an update of the default render pass descriptor. 43924 */ 43925 updateSize() { 43926 this.delete(this.renderer.getCanvasTarget()); 43927 } 43928 // utils public 43929 /** 43930 * Checks if the given feature is supported by the backend. 43931 * 43932 * @param {string} name - The feature's name. 43933 * @return {boolean} Whether the feature is supported or not. 43934 */ 43935 hasFeature(name) { 43936 if (GPUFeatureMap[name] !== void 0) name = GPUFeatureMap[name]; 43937 return this.device.features.has(name); 43938 } 43939 /** 43940 * Copies data of the given source texture to the given destination texture. 43941 * 43942 * @param {Texture} srcTexture - The source texture. 43943 * @param {Texture} dstTexture - The destination texture. 43944 * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy. 43945 * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy. 43946 * @param {number} [srcLevel=0] - The mipmap level to copy. 43947 * @param {number} [dstLevel=0] - The destination mip level to copy to. 43948 */ 43949 copyTextureToTexture(srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0) { 43950 let dstX = 0; 43951 let dstY = 0; 43952 let dstZ = 0; 43953 let srcX = 0; 43954 let srcY = 0; 43955 let srcZ = 0; 43956 let srcWidth = srcTexture.image.width; 43957 let srcHeight = srcTexture.image.height; 43958 let srcDepth = 1; 43959 if (srcRegion !== null) { 43960 if (srcRegion.isBox3 === true) { 43961 srcX = srcRegion.min.x; 43962 srcY = srcRegion.min.y; 43963 srcZ = srcRegion.min.z; 43964 srcWidth = srcRegion.max.x - srcRegion.min.x; 43965 srcHeight = srcRegion.max.y - srcRegion.min.y; 43966 srcDepth = srcRegion.max.z - srcRegion.min.z; 43967 } else { 43968 srcX = srcRegion.min.x; 43969 srcY = srcRegion.min.y; 43970 srcWidth = srcRegion.max.x - srcRegion.min.x; 43971 srcHeight = srcRegion.max.y - srcRegion.min.y; 43972 srcDepth = 1; 43973 } 43974 } 43975 if (dstPosition !== null) { 43976 dstX = dstPosition.x; 43977 dstY = dstPosition.y; 43978 dstZ = dstPosition.z || 0; 43979 } 43980 const encoder = this.device.createCommandEncoder({ label: "copyTextureToTexture_" + srcTexture.id + "_" + dstTexture.id }); 43981 const sourceGPU = this.get(srcTexture).texture; 43982 const destinationGPU = this.get(dstTexture).texture; 43983 encoder.copyTextureToTexture( 43984 { 43985 texture: sourceGPU, 43986 mipLevel: srcLevel, 43987 origin: { x: srcX, y: srcY, z: srcZ } 43988 }, 43989 { 43990 texture: destinationGPU, 43991 mipLevel: dstLevel, 43992 origin: { x: dstX, y: dstY, z: dstZ } 43993 }, 43994 [ 43995 srcWidth, 43996 srcHeight, 43997 srcDepth 43998 ] 43999 ); 44000 this.device.queue.submit([encoder.finish()]); 44001 if (dstLevel === 0 && dstTexture.generateMipmaps) { 44002 this.textureUtils.generateMipmaps(dstTexture); 44003 } 44004 } 44005 /** 44006 * Copies the current bound framebuffer to the given texture. 44007 * 44008 * @param {Texture} texture - The destination texture. 44009 * @param {RenderContext} renderContext - The render context. 44010 * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. 44011 */ 44012 copyFramebufferToTexture(texture3, renderContext, rectangle) { 44013 const renderContextData = this.get(renderContext); 44014 let sourceGPU = null; 44015 if (renderContext.renderTarget) { 44016 if (texture3.isDepthTexture) { 44017 sourceGPU = this.get(renderContext.depthTexture).texture; 44018 } else { 44019 sourceGPU = this.get(renderContext.textures[0]).texture; 44020 } 44021 } else { 44022 if (texture3.isDepthTexture) { 44023 sourceGPU = this.textureUtils.getDepthBuffer(renderContext.depth, renderContext.stencil); 44024 } else { 44025 sourceGPU = this.context.getCurrentTexture(); 44026 } 44027 } 44028 const destinationGPU = this.get(texture3).texture; 44029 if (sourceGPU.format !== destinationGPU.format) { 44030 error("WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.", sourceGPU.format, destinationGPU.format); 44031 return; 44032 } 44033 let encoder; 44034 if (renderContextData.currentPass) { 44035 renderContextData.currentPass.end(); 44036 encoder = renderContextData.encoder; 44037 } else { 44038 encoder = this.device.createCommandEncoder({ label: "copyFramebufferToTexture_" + texture3.id }); 44039 } 44040 encoder.copyTextureToTexture( 44041 { 44042 texture: sourceGPU, 44043 origin: [rectangle.x, rectangle.y, 0] 44044 }, 44045 { 44046 texture: destinationGPU 44047 }, 44048 [ 44049 rectangle.z, 44050 rectangle.w 44051 ] 44052 ); 44053 if (texture3.generateMipmaps) { 44054 this.textureUtils.generateMipmaps(texture3, encoder); 44055 } 44056 if (renderContextData.currentPass) { 44057 const { descriptor } = renderContextData; 44058 for (let i = 0; i < descriptor.colorAttachments.length; i++) { 44059 descriptor.colorAttachments[i].loadOp = GPULoadOp.Load; 44060 } 44061 if (renderContext.depth) descriptor.depthStencilAttachment.depthLoadOp = GPULoadOp.Load; 44062 if (renderContext.stencil) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; 44063 renderContextData.currentPass = encoder.beginRenderPass(descriptor); 44064 renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; 44065 if (renderContext.viewport) { 44066 this.updateViewport(renderContext); 44067 } 44068 if (renderContext.scissor) { 44069 this.updateScissor(renderContext); 44070 } 44071 } else { 44072 this.device.queue.submit([encoder.finish()]); 44073 } 44074 } 44075 /** 44076 * Checks if the given compatibility is supported by the backend. 44077 * 44078 * @param {string} name - The compatibility name. 44079 * @return {boolean} Whether the compatibility is supported or not. 44080 */ 44081 hasCompatibility(name) { 44082 if (this._compatibility[name] !== void 0) { 44083 return this._compatibility[name]; 44084 } 44085 return super.hasCompatibility(name); 44086 } 44087 dispose() { 44088 this.bindingUtils.dispose(); 44089 this.textureUtils.dispose(); 44090 if (this.occludedResolveCache) { 44091 for (const buffer3 of this.occludedResolveCache.values()) { 44092 buffer3.destroy(); 44093 } 44094 this.occludedResolveCache.clear(); 44095 } 44096 if (this.timestampQueryPool) { 44097 for (const queryPool of Object.values(this.timestampQueryPool)) { 44098 if (queryPool !== null) queryPool.dispose(); 44099 } 44100 } 44101 if (this.parameters.device === void 0 && this.device !== null) { 44102 this.device.destroy(); 44103 } 44104 } 44105}; 44106var IESSpotLight = class extends SpotLight { 44107 /** 44108 * Constructs a new IES spot light. 44109 * 44110 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 44111 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 44112 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 44113 * @param {number} [angle=Math.PI/3] - Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 44114 * @param {number} [penumbra=0] - Percent of the spotlight cone that is attenuated due to penumbra. Value range is `[0,1]`. 44115 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 44116 */ 44117 constructor(color3, intensity, distance3, angle, penumbra, decay) { 44118 super(color3, intensity, distance3, angle, penumbra, decay); 44119 this.iesMap = null; 44120 } 44121 copy(source, recursive) { 44122 super.copy(source, recursive); 44123 this.iesMap = source.iesMap; 44124 return this; 44125 } 44126}; 44127var ProjectorLight = class extends SpotLight { 44128 /** 44129 * Constructs a new projector light. 44130 * 44131 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 44132 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 44133 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 44134 * @param {number} [angle=Math.PI/3] - Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 44135 * @param {number} [penumbra=0] - Percent of the spotlight cone that is attenuated due to penumbra. Value range is `[0,1]`. 44136 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 44137 */ 44138 constructor(color3, intensity, distance3, angle, penumbra, decay) { 44139 super(color3, intensity, distance3, angle, penumbra, decay); 44140 this.aspect = null; 44141 } 44142 copy(source, recursive) { 44143 super.copy(source, recursive); 44144 this.aspect = source.aspect; 44145 return this; 44146 } 44147}; 44148var StandardNodeLibrary = class extends NodeLibrary { 44149 /** 44150 * Constructs a new standard node library. 44151 */ 44152 constructor() { 44153 super(); 44154 this.addMaterial(MeshPhongNodeMaterial, "MeshPhongMaterial"); 44155 this.addMaterial(MeshStandardNodeMaterial, "MeshStandardMaterial"); 44156 this.addMaterial(MeshPhysicalNodeMaterial, "MeshPhysicalMaterial"); 44157 this.addMaterial(MeshToonNodeMaterial, "MeshToonMaterial"); 44158 this.addMaterial(MeshBasicNodeMaterial, "MeshBasicMaterial"); 44159 this.addMaterial(MeshLambertNodeMaterial, "MeshLambertMaterial"); 44160 this.addMaterial(MeshNormalNodeMaterial, "MeshNormalMaterial"); 44161 this.addMaterial(MeshMatcapNodeMaterial, "MeshMatcapMaterial"); 44162 this.addMaterial(LineBasicNodeMaterial, "LineBasicMaterial"); 44163 this.addMaterial(LineDashedNodeMaterial, "LineDashedMaterial"); 44164 this.addMaterial(PointsNodeMaterial, "PointsMaterial"); 44165 this.addMaterial(SpriteNodeMaterial, "SpriteMaterial"); 44166 this.addMaterial(ShadowNodeMaterial, "ShadowMaterial"); 44167 this.addLight(PointLightNode, PointLight); 44168 this.addLight(DirectionalLightNode, DirectionalLight); 44169 this.addLight(RectAreaLightNode, RectAreaLight); 44170 this.addLight(SpotLightNode, SpotLight); 44171 this.addLight(AmbientLightNode, AmbientLight); 44172 this.addLight(HemisphereLightNode, HemisphereLight); 44173 this.addLight(LightProbeNode, LightProbe); 44174 this.addLight(IESSpotLightNode, IESSpotLight); 44175 this.addLight(ProjectorLightNode, ProjectorLight); 44176 this.addToneMapping(linearToneMapping, LinearToneMapping); 44177 this.addToneMapping(reinhardToneMapping, ReinhardToneMapping); 44178 this.addToneMapping(cineonToneMapping, CineonToneMapping); 44179 this.addToneMapping(acesFilmicToneMapping, ACESFilmicToneMapping); 44180 this.addToneMapping(agxToneMapping, AgXToneMapping); 44181 this.addToneMapping(neutralToneMapping, NeutralToneMapping); 44182 } 44183}; 44184var WebGPURenderer = class extends Renderer { 44185 /** 44186 * WebGPURenderer options. 44187 * 44188 * @typedef {Object} WebGPURenderer~Options 44189 * @property {boolean} [logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. 44190 * @property {boolean} [reversedDepthBuffer=false] - Whether reversed depth buffer is enabled or not. 44191 * @property {boolean} [alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. 44192 * @property {boolean} [depth=true] - Whether the default framebuffer should have a depth buffer or not. 44193 * @property {boolean} [stencil=false] - Whether the default framebuffer should have a stencil buffer or not. 44194 * @property {boolean} [antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. 44195 * @property {number} [samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. 44196 * @property {boolean} [forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. 44197 * @property {boolean} [multiview=false] - If set to `true`, the renderer will use multiview during WebXR rendering if supported. 44198 * @property {number} [outputType=undefined] - Texture type for output to canvas. By default, device's preferred format is used; other formats may incur overhead. 44199 * @property {number} [outputBufferType=HalfFloatType] - Defines the type of output buffers. The default `HalfFloatType` is recommend for best 44200 * quality. To save memory and bandwidth, `UnsignedByteType` might be used. This will reduce rendering quality though. 44201 */ 44202 /** 44203 * Constructs a new WebGPU renderer. 44204 * 44205 * @param {WebGPURenderer~Options} [parameters] - The configuration parameter. 44206 */ 44207 constructor(parameters = {}) { 44208 let BackendClass; 44209 if (parameters.forceWebGL) { 44210 BackendClass = WebGLBackend; 44211 } else { 44212 BackendClass = WebGPUBackend; 44213 parameters.getFallback = () => { 44214 warn("WebGPURenderer: WebGPU is not available, running under WebGL2 backend."); 44215 return new WebGLBackend(parameters); 44216 }; 44217 } 44218 const backend = new BackendClass(parameters); 44219 super(backend, parameters); 44220 this.library = new StandardNodeLibrary(); 44221 this.isWebGPURenderer = true; 44222 if (typeof __THREE_DEVTOOLS__ !== "undefined") { 44223 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { detail: this })); 44224 } 44225 } 44226}; 44227
vendor: 179 bytes, lines 44228-44230
44228// node_modules/@solid-primitives/resize-observer/node_modules/@solid-primitives/utils/dist/chunk/APG4HSEJ.js 44229var access = (v) => typeof v === "function" && !v.length ? v() : v; 44230
vendor: 345 bytes, lines 44231-44238
44231// node_modules/@solid-primitives/static-store/node_modules/@solid-primitives/utils/dist/chunk/APG4HSEJ.js 44232function isObject2(value) { 44233 return value !== null && (typeof value === "object" || typeof value === "function"); 44234} 44235function accessWith2(valueOrFn, ...args) { 44236 return typeof valueOrFn === "function" ? valueOrFn(...args) : valueOrFn; 44237} 44238
vendor: 1,089 bytes, lines 44239-44279
44239// node_modules/@solid-primitives/static-store/dist/index.js 44240function createStaticStore(init) { 44241 const copy = { ...init }, store = { ...init }, cache4 = {}; 44242 const getValue = (key) => { 44243 let signal = cache4[key]; 44244 if (!signal) { 44245 if (!getListener()) 44246 return copy[key]; 44247 cache4[key] = signal = createSignal(copy[key], { internal: true }); 44248 delete copy[key]; 44249 } 44250 return signal[0](); 44251 }; 44252 for (const key in init) { 44253 Object.defineProperty(store, key, { get: () => getValue(key), enumerable: true }); 44254 } 44255 const setValue = (key, value) => { 44256 const signal = cache4[key]; 44257 if (signal) 44258 return signal[1](value); 44259 if (key in copy) 44260 copy[key] = accessWith2(value, [copy[key]]); 44261 }; 44262 return [ 44263 store, 44264 (a, b) => { 44265 if (isObject2(a)) { 44266 const entries5 = untrack( 44267 () => Object.entries(accessWith2(a, store)) 44268 ); 44269 batch(() => { 44270 for (const [key, value] of entries5) 44271 setValue(key, () => value); 44272 }); 44273 } else 44274 setValue(a, b); 44275 return store; 44276 } 44277 ]; 44278} 44279
vendor: 871 bytes, lines 44280-44310
44280// node_modules/@solid-primitives/resize-observer/dist/index.js 44281var ELEMENT_SIZE_FALLBACK = { width: null, height: null }; 44282function getElementSize(target) { 44283 if (isServer || !target) { 44284 return { ...ELEMENT_SIZE_FALLBACK }; 44285 } 44286 const { width, height } = target.getBoundingClientRect(); 44287 return { width, height }; 44288} 44289function createElementSize(target) { 44290 if (isServer) { 44291 return ELEMENT_SIZE_FALLBACK; 44292 } 44293 const [size3, setSize] = createStaticStore( 44294 sharedConfig.context ? ELEMENT_SIZE_FALLBACK : getElementSize(access(target)) 44295 ); 44296 const ro = new ResizeObserver(([e]) => { 44297 const { width, height } = e.contentRect; 44298 setSize({ width, height }); 44299 }); 44300 onCleanup(() => ro.disconnect()); 44301 createEffect(() => { 44302 const el = access(target); 44303 if (el) { 44304 ro.observe(el); 44305 onCleanup(() => ro.unobserve(el)); 44306 } 44307 }); 44308 return size3; 44309} 44310
44311// src/viewer/context/webxr.jsx 44312var T2 = createT({ 44313 Group 44314}); 44315var WebXRSupport = (props) => { 44316 const { 44317 globalScale 44318 } = useCamera(); 44319 let originGroup = null; 44320 let trackball = null; 44321 const [originGroupReady, setOriginGroupReady] = createSignal(null); 44322 const captureOriginGroup = (g) => { 44323 originGroup = g; 44324 setOriginGroupReady(g); 44325 }; 44326 const setTrackball = (tb) => { 44327 trackball = tb; 44328 }; 44329 const StartXRButton = lazy(() => import("./vzome-viewer-xr.js")); 44330 const setRootScene = (scene) => { 44331 originGroup.clear(); 44332 originGroup.add(scene); 44333 const children2 = [...scene.children]; 44334 for (const child of children2) { 44335 originGroup.add(child); 44336 } 44337 }; 44338 return [createComponent(T2.Group, { 44339 ref: captureOriginGroup, 44340 scale: globalScale, 44341 get children() { 44342 return createComponent(WebXRContext.Provider, { 44343 value: { 44344 setRootScene, 44345 setTrackball, 44346 originGroupReady 44347 }, 44348 get children() { 44349 return props.children; 44350 } 44351 }); 44352 } 44353 }), createComponent(Suspense, { 44354 get children() { 44355 return createComponent(Show, { 44356 get when() { 44357 return memo(() => !!props.xrSupported)() && props.xrSupported(); 44358 }, 44359 get children() { 44360 return createComponent(StartXRButton, { 44361 getRootGroup: () => originGroup, 44362 trackball 44363 }); 44364 } 44365 }); 44366 } 44367 })]; 44368}; 44369var WebXRContext = createContext({}); 44370var useWebXRClient = () => { 44371 return useContext(WebXRContext); 44372}; 44373
44374// src/viewer/trackballcontrols.jsx 44375var TrackballControls2 = (props) => { 44376 props = mergeProps({ 44377 rotateSpeed: 4.5, 44378 zoomSpeed: 3, 44379 panSpeed: 1 44380 }, props); 44381 const { 44382 perspectiveProps, 44383 trackballProps, 44384 name, 44385 cancelTweens 44386 } = useCamera(); 44387 const [tool] = useInteractionTool(); 44388 const { 44389 canvas, 44390 bounds 44391 } = useThree(); 44392 const { 44393 setTrackball 44394 } = useWebXRClient(); 44395 createEffect(() => { 44396 if (bounds.height < 0) 44397 console.log("height is", bounds.height); 44398 trackballControls().connect(canvas); 44399 }); 44400 const trackballControls = createMemo(() => { 44401 const controls = new TrackballControls(trackballProps.camera); 44402 setTrackball(controls); 44403 return controls; 44404 }); 44405 useFrame(() => { 44406 let controls = trackballControls(); 44407 if (controls.enabled) { 44408 controls.update(); 44409 } 44410 }); 44411 createEffect(() => { 44412 trackballControls().enabled = tool === void 0 || tool.allowTrackball(); 44413 }); 44414 createEffect(() => { 44415 const controls = trackballControls(); 44416 controls.staticMoving = true; 44417 if (props.rotationOnly) { 44418 controls.noZoom = true; 44419 controls.noPan = true; 44420 } else { 44421 controls.noZoom = props.zoomSpeed === 0; 44422 controls.zoomSpeed = props.zoomSpeed; 44423 controls.noPan = props.panSpeed === 0; 44424 controls.panSpeed = props.panSpeed; 44425 } 44426 controls.rotateSpeed = props.rotateSpeed; 44427 controls.connect(canvas); 44428 const onStart = () => cancelTweens(); 44429 const onChange = () => trackballProps.sync(controls.target, name); 44430 const onEnd = () => tool !== void 0 && tool.onTrackballEnd(); 44431 controls.addEventListener("start", onStart); 44432 controls.addEventListener("change", onChange); 44433 controls.addEventListener("end", onEnd); 44434 onCleanup(() => { 44435 controls.removeEventListener("start", onStart); 44436 controls.removeEventListener("change", onChange); 44437 controls.removeEventListener("end", onEnd); 44438 controls.dispose(); 44439 }); 44440 }); 44441 createEffect(() => { 44442 const [x, y, z] = perspectiveProps.target; 44443 trackballControls().target.set(x, y, z); 44444 }); 44445 return null; 44446}; 44447
44448// src/viewer/perspectivecamera.jsx 44449var T3 = createT({ 44450 PerspectiveCamera 44451}); 44452var ControlledPerspectiveCamera = (props) => { 44453 const { 44454 perspectiveProps, 44455 state: cameraConfig, 44456 globalScale 44457 } = useCamera(); 44458 let cam; 44459 const { 44460 setCamera, 44461 scene 44462 } = useThree(); 44463 createEffect(() => { 44464 if (cameraConfig.outlines) cam.layers.enable(4); 44465 else cam.layers.disable(4); 44466 }); 44467 createEffect(() => { 44468 const [x, y, z] = perspectiveProps.target; 44469 cam.lookAt(x * globalScale, y * globalScale, z * globalScale); 44470 }); 44471 createEffect(() => { 44472 cam.near = perspectiveProps.near * globalScale; 44473 cam.far = perspectiveProps.far * globalScale; 44474 cam.fov = perspectiveProps.fov(props.aspect); 44475 cam.aspect = props.aspect; 44476 cam.updateProjectionMatrix(); 44477 }); 44478 createEffect(() => { 44479 setCamera(cam); 44480 scene.add(cam); 44481 onCleanup(() => scene.remove(cam)); 44482 }); 44483 return createComponent(T3.PerspectiveCamera, { 44484 ref(r$) { 44485 const _ref$ = cam; 44486 typeof _ref$ === "function" ? _ref$(r$) : cam = r$; 44487 }, 44488 get position() { 44489 return perspectiveProps.position.map((e) => e * globalScale); 44490 }, 44491 get up() { 44492 return perspectiveProps.up; 44493 }, 44494 get children() { 44495 return props.children; 44496 } 44497 }); 44498}; 44499
44500// src/viewer/orthographiccamera.jsx 44501var T4 = createT({ 44502 OrthographicCamera 44503}); 44504var ControlledOrthographicCamera = (props) => { 44505 const { 44506 perspectiveProps, 44507 state, 44508 globalScale 44509 } = useCamera(); 44510 const halfWidth = () => perspectiveProps.width / 2; 44511 let cam; 44512 const { 44513 scene, 44514 setCamera 44515 } = useThree(); 44516 createEffect(() => { 44517 if (state.outlines) cam.layers.enable(4); 44518 else cam.layers.disable(4); 44519 }); 44520 createEffect(() => { 44521 cam.near = perspectiveProps.near * globalScale; 44522 cam.far = perspectiveProps.far * globalScale; 44523 cam.left = -halfWidth() * globalScale; 44524 cam.right = halfWidth() * globalScale; 44525 const halfHeight = halfWidth() / props.aspect; 44526 cam.top = halfHeight * globalScale; 44527 cam.bottom = -halfHeight * globalScale; 44528 cam.updateProjectionMatrix(); 44529 }); 44530 createEffect(() => { 44531 const [x, y, z] = perspectiveProps.target; 44532 cam.lookAt(x * globalScale, y * globalScale, z * globalScale); 44533 }); 44534 createEffect(() => { 44535 setCamera(cam); 44536 scene.add(cam); 44537 onCleanup(() => scene.remove(cam)); 44538 }); 44539 return createComponent(T4.OrthographicCamera, { 44540 ref(r$) { 44541 const _ref$ = cam; 44542 typeof _ref$ === "function" ? _ref$(r$) : cam = r$; 44543 }, 44544 get position() { 44545 return perspectiveProps.position.map((e) => e * globalScale); 44546 }, 44547 get up() { 44548 return perspectiveProps.up; 44549 }, 44550 get children() { 44551 return props.children; 44552 } 44553 }); 44554}; 44555
44556// src/viewer/labels.jsx 44557var Labels = (props) => { 44558 const three = useThree(); 44559 const { 44560 scene, 44561 canvas 44562 } = three; 44563 let labelRenderer; 44564 onMount(() => { 44565 labelRenderer = new CSS2DRenderer(); 44566 const labelsElem = labelRenderer.domElement; 44567 labelsElem.style.isolation = "isolate"; 44568 labelsElem.style.position = "absolute"; 44569 labelsElem.style.pointerEvents = "none"; 44570 labelsElem.style.inset = "0px"; 44571 labelsElem.style.width = "100%"; 44572 labelsElem.style.height = "100%"; 44573 labelsElem.classList.add("labels"); 44574 canvas.insertAdjacentElement("beforebegin", labelsElem); 44575 }); 44576 createEffect(() => { 44577 props.size && labelRenderer.setSize(props.size.width, props.size.height); 44578 }); 44579 useFrame(() => { 44580 labelRenderer.render(scene, three.camera); 44581 }); 44582 return null; 44583}; 44584var Label = (props) => { 44585 let label3; 44586 onMount(() => { 44587 const elem = document.createElement("div"); 44588 elem.className = "vzome-label"; 44589 elem.id = `vzome-label-${props.text}`; 44590 elem.textContent = props.text; 44591 label3 = new CSS2DObject(elem); 44592 props.parent.add(label3); 44593 }); 44594 onCleanup(() => label3?.parent?.remove(label3)); 44595 createEffect(() => { 44596 const { 44597 x, 44598 y, 44599 z 44600 } = props.position; 44601 label3.position.set(x, y, z); 44602 }); 44603 return label3; 44604}; 44605
44606// src/viewer/ltcanvas.jsx 44607var _tmpl$ = /* @__PURE__ */ template(`<button>START AR`); 44608var _tmpl$2 = /* @__PURE__ */ template(`<div>`); 44609var T5 = createT({ 44610 Group, 44611 Mesh, 44612 AmbientLight, 44613 DirectionalLight 44614}); 44615var Lighting2 = () => { 44616 const { 44617 state, 44618 perspectiveProps 44619 } = useCamera(); 44620 const mapColor = (color3) => new Color().setStyle(color3).multiplyScalar(Math.PI); 44621 useFrame(({ 44622 scene 44623 }) => { 44624 scene.background = new Color().setStyle(state.lighting.backgroundColor); 44625 }); 44626 let centerObject; 44627 return createComponent(T5.Group, { 44628 get position() { 44629 return perspectiveProps.position; 44630 }, 44631 get up() { 44632 return perspectiveProps.up; 44633 }, 44634 get target() { 44635 return perspectiveProps.target; 44636 }, 44637 get children() { 44638 return [createComponent(T5.Mesh, { 44639 ref(r$) { 44640 const _ref$ = centerObject; 44641 typeof _ref$ === "function" ? _ref$(r$) : centerObject = r$; 44642 }, 44643 visible: false 44644 }), createComponent(T5.AmbientLight, { 44645 get color() { 44646 return mapColor(state.lighting.ambientColor); 44647 } 44648 }), createComponent(For, { 44649 get each() { 44650 return state.lighting.directionalLights; 44651 }, 44652 children: ({ 44653 direction, 44654 color: color3 44655 }) => createComponent(T5.DirectionalLight, { 44656 target: centerObject, 44657 intensity: 1.4, 44658 get color() { 44659 return mapColor(color3); 44660 }, 44661 get position() { 44662 return direction.map((x) =>
44662 -x); 44663 } 44664 }) 44665 })]; 44666 } 44667 }); 44668}; 44669var ControlledCamera = (props) => { 44670 const { 44671 state 44672 } = useCamera(); 44673 return createComponent(Show, { 44674 get when() { 44675 return state.camera.perspective; 44676 }, 44677 get fallback() { 44678 return createComponent(ControlledOrthographicCamera, { 44679 get aspect() { 44680 return props.aspect; 44681 }, 44682 get children() { 44683 return props.children; 44684 } 44685 }); 44686 }, 44687 get children() { 44688 return createComponent(ControlledPerspectiveCamera, { 44689 get aspect() { 44690 return props.aspect; 44691 }, 44692 get children() { 44693 return props.children; 44694 } 44695 }); 44696 } 44697 }); 44698}; 44699var isLeftMouseButton = (e) => { 44700 e = e || window.event; 44701 if ("which" in e) 44702 return e.which === 1; 44703 else if ("button" in e) 44704 return e.button === 0; 44705 return false; 44706}; 44707var LightedTrackballCanvas = (props) => { 44708 let size3; 44709 const aspect = () => size3 && size3.height ? size3.width / size3.height : 1; 44710 const canvasSize = () => size3; 44711 const { 44712 labels 44713 } = useViewer(); 44714 const xr = createXR(); 44715 const [xrSupported] = createResource(() => xr.isSupported("immersive-ar")); 44716 const [canvasEl, setCanvasEl] = createSignal(null); 44717 size3 = createElementSize(canvasEl); 44718 const connectRef = (ctx) => { 44719 setCanvasEl(ctx.gl.domElement); 44720 return xr.connect(ctx); 44721 }; 44722 const [tool] = useInteractionTool(); 44723 const handlePointerMove = (e) => { 44724 const handler = tool?.onDrag; 44725 if (isLeftMouseButton(e) && handler) { 44726 e.stopPropagation(); 44727 handler(e); 44728 } 44729 }; 44730 const handlePointerUp = (e) => { 44731 if (props.symmetryRenderer) return; 44732 const handler = tool?.onDragEnd; 44733 if (isLeftMouseButton(e) && handler) { 44734 handler(e); 44735 } 44736 }; 44737 const handleWheel = (e) => { 44738 const handler = tool?.onWheel; 44739 if (handler) { 44740 e.preventDefault(); 44741 handler(e.deltaY); 44742 } 44743 }; 44744 const handlePointerMissed = (e) => { 44745 if (props.symmetryRenderer) return; 44746 const handler = tool?.bkgdClick; 44747 if (isLeftMouseButton(e.nativeEvent) && handler) { 44748 handler(e); 44749 } 44750 }; 44751 const makeCustomRenderer = (canvas) => { 44752 if (props.useWebGL) { 44753 const renderer2 = new WebGLRenderer({ 44754 powerPreference: "high-performance", 44755 canvas, 44756 antialias: true, 44757 alpha: true, 44758 preserveDrawingBuffer: true 44759 }); 44760 return renderer2; 44761 } 44762 const renderer = new WebGPURenderer({ 44763 powerPreference: "high-performance", 44764 canvas, 44765 antialias: true, 44766 alpha: true, 44767 preserveDrawingBuffer: true, 44768 forceWebGL: true 44769 }); 44770 return renderer; 44771 }; 44772 createRenderEffect(() => { 44773 const el = canvasEl(); 44774 if (el) el.style.cursor = tool?.cursor() || "auto"; 44775 }); 44776 onMount(() => { 44777 const el = canvasEl(); 44778 if (el) { 44779 el.addEventListener("pointerup", handlePointerUp); 44780 el.addEventListener("wheel", handleWheel); 44781 } 44782 }); 44783 return createComponent(xr.Provider, { 44784 get children() { 44785 const _el$ = _tmpl$2(); 44786 _el$.style.setProperty("position", "relative"); 44787 insert(_el$, createComponent(Canvas, { 44788 ref: connectRef, 44789 "class": "canvas3d", 44790 get dpr() { 44791 return window.devicePixelRatio; 44792 }, 44793 gl: makeCustomRenderer, 44794 style: { 44795 height: "100%", 44796 width: "100%", 44797 display: "flex" 44798 }, 44799 frameloop: "always", 44800 onClickMissed: handlePointerMissed, 44801 get children() { 44802 return createComponent(WebXRSupport, { 44803 xrSupported, 44804 get children() { 44805 return [createComponent(ControlledCamera, { 44806 get aspect() { 44807 return aspect(); 44808 }, 44809 get children() { 44810 return createComponent(Lighting2, {}); 44811 } 44812 }), createComponent(TrackballControls2, { 44813 get rotationOnly() { 44814 return props.rotationOnly; 44815 }, 44816 get rotateSpeed() { 44817 return props.rotateSpeed; 44818 }, 44819 get zoomSpeed() { 44820 return props.zoomSpeed; 44821 }, 44822 get panSpeed() { 44823 return props.panSpeed; 44824 } 44825 }), memo(() => props.children), memo(() => memo(() => !!(labels && labels()))() && createComponent(Labels, { 44826 get size() { 44827 return canvasSize(); 44828 } 44829 }))]; 44830 } 44831 }); 44832 } 44833 }), null);
44834 insert(_el$, createComponent(Suspense, { 44835 get children() { 44836 return createComponent(Show, { 44837 get when() { 44838 return xrSupported(); 44839 }, 44840 get children() { 44841 const _el$2 = _tmpl$(); 44842 _el$2.$$click = () => xr.enter("immersive-ar", { 44843 optionalFeatures: ["local-floor", "hand-tracking"] 44844 }); 44845 _el$2.style.setProperty("position", "absolute"); 44846 _el$2.style.setProperty("bottom", "20px"); 44847 _el$2.style.setProperty("left", "50%"); 44848 _el$2.style.setProperty("transform", "translateX(-50%)"); 44849 _el$2.style.setProperty("padding", "12px 24px"); 44850 _el$2.style.setProperty("border-radius", "4px"); 44851 _el$2.style.setProperty("border", "none"); 44852 _el$2.style.setProperty("background", "rgba(0,0,0,0.7)"); 44853 _el$2.style.setProperty("color", "white"); 44854 _el$2.style.setProperty("cursor", "pointer"); 44855 _el$2.style.setProperty("font-size", "13px"); 44856 _el$2.style.setProperty("font-family", "sans-serif"); 44857 return _el$2; 44858 } 44859 }); 44860 } 44861 }), null); 44862 createRenderEffect((_p$) => { 44863 const _v$ = props.height ?? "100%", _v$2 = props.width ?? "100%"; 44864 _v$ !== _p$._v$ && ((_p$._v$ = _v$) != null ? _el$.style.setProperty("height", _v$) : _el$.style.removeProperty("height")); 44865 _v$2 !== _p$._v$2 && ((_p$._v$2 = _v$2) != null ? _el$.style.setProperty("width", _v$2) : _el$.style.removeProperty("width")); 44866 return _p$; 44867 }, { 44868 _v$: void 0, 44869 _v$2: void 0 44870 }); 44871 return _el$; 44872 } 44873 }); 44874}; 44875delegateEvents(["click"]); 44876
44877// src/viewer/geometry.jsx 44878var T6 = createT({ 44879 Group, 44880 Mesh, 44881 MeshLambertMaterial, 44882 LineSegments, 44883 LineBasicMaterial 44884}); 44885var Instance = (props) => { 44886 let meshRef, linesRef; 44887 createEffect(() => { 44888 const m = new Matrix4(); 44889 m.set(...props.rotation); 44890 meshRef.matrix = m; 44891 if (!!linesRef) linesRef.matrix = m.clone(); 44892 }); 44893 const [tool] = useInteractionTool(); 44894 const handleHover = (value) => (e) => { 44895 const handler = tool?.onHover; 44896 if (handler) { 44897 e.stopPropagation(); 44898 handler(props.id, props.position, props.type, value); 44899 } 44900 }; 44901 const handleContextMenu = (e) => { 44902 const handler = tool?.onContextMenu; 44903 if (handler) { 44904 e.stopPropagation(); 44905 handler(props.id, props.position, props.type, props.selected, props.label); 44906 } 44907 }; 44908 const handlePointerDown = (e) => { 44909 if (e.nativeEvent.button !== 0) 44910 return; 44911 const handler = tool?.onDragStart; 44912 if (handler) { 44913 e.stopPropagation(); 44914 handler(e.nativeEvent, props.id, props.position, props.type, props.selected); 44915 } 44916 }; 44917 const handlePointerMove = (e) => { 44918 const handler = tool?.onDrag; 44919 if (handler) { 44920 e.stopPropagation(); 44921 handler(e.nativeEvent, props.id, props.position, props.type, props.selected); 44922 } 44923 }; 44924 const handlePointerUp = (e) => { 44925 if (e.nativeEvent.button !== 0) 44926 return; 44927 const handler = tool?.onDragEnd; 44928 if (handler) { 44929 e.stopPropagation(); 44930 handler(e.nativeEvent, props.id, props.position, props.type, props.selected, props.label); 44931 } 44932 }; 44933 const handleClick = (e) => { 44934 if (e.nativeEvent.button !== 0) 44935 return; 44936 const handler = tool?.onClick; 44937 if (handler) { 44938 e.stopPropagation(); 44939 handler(e.nativeEvent, props.id, props.position, props.type, props.selected, props.label); 44940 } 44941 }; 44942 onMount(() => linesRef && linesRef.layers.set(4)); 44943 const color3 = new Color().setStyle(props.color); 44944 const emissive3 = () => props.selected ? "#c8c8c8" : "black"; 44945 return createComponent(T6.Group, { 44946 get position() { 44947 return props.position; 44948 }, 44949 get name() { 44950 return props.id; 44951 }, 44952 get children() { 44953 return [createComponent(T6.Mesh, { 44954 matrixAutoUpdate: false, 44955 ref(r$) { 44956 const _ref$ = meshRef; 44957 typeof _ref$ === "function" ? _ref$(r$) : meshRef = r$; 44958 }, 44959 get geometry() { 44960 return props.geometry; 44961 }, 44962 get onPointerEnter() { 44963 return handleHover(true); 44964 }, 44965 get onPointerLeave() { 44966 return handleHover(false); 44967 }, 44968 onPointerMove: handlePointerMove, 44969 onClick: handleClick, 44970 onPointerDown: handlePointerDown, 44971 onPointerUp: handlePointerUp, 44972 onContextMenu: handleContextMenu, 44973 get children() { 44974 return createComponent(T6.MeshLambertMaterial, { 44975 attach: "material", 44976 color: color3, 44977 get emissive() { 44978 return emissive3(); 44979 } 44980 }); 44981 } 44982 }), memo(() => memo(() => !!!!props.outlineGeometry)() && createComponent(T6.LineSegments, { 44983 matrixAutoUpdate: false, 44984 ref(r$) { 44985 const _ref$2 = linesRef; 44986 typeof _ref$2 === "function" ? _ref$2(r$) : linesRef = r$; 44987 }, 44988 get geometry() { 44989 return props.outlineGeometry; 44990 }, 44991 get children() { 44992 return createComponent(T6.LineBasicMaterial, { 44993 attach: "material", 44994 linewidth: 4.4, 44995 color: "black" 44996 }); 44997 } 44998 })), memo(() => memo(() => !!!!props.label)() && createComponent(Label, { 44999 parent: meshRef, 45000 get position() { 45001 return props.geometry.shapeCentroid; 45002 }, 45003 get text() { 45004 return props.label; 45005 } 45006 }))]; 45007 } 45008 }); 45009}; 45010var centroid = (vertices) => { 45011 let [sx, sy, sz] = [0, 0, 0]; 45012 vertices.forEach(({ 45013 x, 45014 y, 45015 z 45016 }) => { 45017 sx += x; 45018 sy += y; 45019 sz += z; 45020 }); 45021 const num = vertices.length; 45022 return { 45023 x: sx / num, 45024 y: sy / num, 45025 z: sz / num 45026 }; 45027}; 45028var buildShapeGeometry = (shape, polygons) => { 45029 const { 45030 vertices, 45031 faces 45032 } = shape; 45033 const computeNormal = ([v0, v1, v2]) => { 45034 const e1 = new Vector3().subVectors(v1, v0); 45035 const e2 = new Vector3().subVectors(v2, v0); 45036 return new Vector3().crossVectors(e1, e2).normalize(); 45037 }; 45038 let positions = []; 45039 let normals = [];
45040 faces.forEach((face) => { 45041 const corners = face.vertices.map((i) => vertices[i]); 45042 const { 45043 x: nx, 45044 y: ny, 45045 z: nz 45046 } = computeNormal(corners); 45047 const addVertex = ({ 45048 x, 45049 y, 45050 z 45051 }) => { 45052 positions.push(x, y, z); 45053 normals.push(nx, ny, nz); 45054 }; 45055 if (polygons) { 45056 for (let index = 0; index < corners.length - 2; index++) { 45057 addVertex(corners[0]); 45058 addVertex(corners[(index + 1) % corners.length]); 45059 addVertex(corners[(index + 2) % corners.length]); 45060 } 45061 } else { 45062 corners.forEach(addVertex); 45063 } 45064 }); 45065 const geometry = new BufferGeometry(); 45066 geometry.setAttribute("position", new Float32BufferAttribute(positions, 3)); 45067 geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3)); 45068 geometry.computeBoundingSphere(); 45069 geometry.shapeCentroid = centroid(vertices); 45070 return geometry; 45071}; 45072var buildOutlineGeometry = (shape) => { 45073 const { 45074 vertices, 45075 faces 45076 } = shape; 45077 let positions = []; 45078 vertices.map(({ 45079 x, 45080 y, 45081 z 45082 }) => positions.push(x, y, z)); 45083 let indices = []; 45084 faces.forEach((face) => { 45085 for (let i = 0; i < face.vertices.length; i++) { 45086 indices.push(face.vertices[i]); 45087 indices.push(face.vertices[(i + 1) % face.vertices.length]); 45088 } 45089 }); 45090 const geometry = new BufferGeometry(); 45091 geometry.setIndex(indices); 45092 geometry.setAttribute("position", new Float32BufferAttribute(positions, 3)); 45093 geometry.computeBoundingSphere(); 45094 return geometry; 45095}; 45096var InstancedShape = (props) => { 45097 const { 45098 scene 45099 } = useScene(); 45100 const showOutlines = () => scene.polygons; 45101 const geometry = createMemo(() => { 45102 const geometry2 = buildShapeGeometry(props.shape, scene.polygons); 45103 onCleanup(() => geometry2.dispose()); 45104 return geometry2; 45105 }); 45106 const outlineGeometry = createMemo(() => { 45107 const geometry2 = buildOutlineGeometry(props.shape); 45108 onCleanup(() => geometry2.dispose()); 45109 return geometry2; 45110 }); 45111 return createComponent(For, { 45112 get each() { 45113 return props.shape.instances; 45114 }, 45115 children: (instance3) => createComponent(Instance, mergeProps(instance3, { 45116 get geometry() { 45117 return geometry(); 45118 }, 45119 get outlineGeometry() { 45120 return memo(() => !!showOutlines())() && outlineGeometry(); 45121 } 45122 })) 45123 }); 45124}; 45125var CanvasExportBindings = () => { 45126 const { 45127 setExporter 45128 } = useGltfExporter(); 45129 const { 45130 setCapturer 45131 } = useImageCapture(); 45132 const three = useThree(); 45133 const exportGltf = (callback) => { 45134 const exporter = new GLTFExporter(); 45135 const onError = (error2) => { 45136 console.error("An error happened during glTF export:", error2); 45137 }; 45138 exporter.parse(three.scene, callback, onError, { 45139 onlyVisible: false, 45140 binary: true 45141 }); 45142 }; 45143 setExporter({ 45144 exportGltf 45145 }); 45146 const capture = (mimeType, saveBlob) => { 45147 three.render(); 45148 three.canvas.toBlob((blob) => { 45149 console.log(`Captured ${mimeType} image of size ${blob.size} bytes`); 45150 saveBlob(blob); 45151 }, mimeType); 45152 }; 45153 setCapturer({ 45154 capture 45155 }); 45156 return null; 45157}; 45158var ShapedGeometry = (props) => { 45159 let groupRef; 45160 createEffect(() => { 45161 if (props.embedding && groupRef && groupRef.matrix) { 45162 const m = new Matrix4(); 45163 m.set(...props.embedding); 45164 m.transpose(); 45165 groupRef.matrix.identity(); 45166 groupRef.applyMatrix4(m); 45167 } 45168 }); 45169 return ( 45170 // <Show when={ () => props.shapes }> 45171 [createComponent(CanvasExportBindings, {}), createComponent(T6.Group, { 45172 matrixAutoUpdate: false, 45173 ref(r$) { 45174 const _ref$3 = groupRef; 45175 typeof _ref$3 === "function" ? _ref$3(r$) : groupRef = r$; 45176 }, 45177 get children() { 45178 return createComponent(For, { 45179 get each() { 45180 return Object.values(props.shapes || {}); 45181 }, 45182 children: (shape) => createComponent(InstancedShape, { 45183 shape 45184 }) 45185 }); 45186 } 45187 })] 45188 ); 45189}; 45190
vendor: 23,899 bytes, lines 45191-45823
45191// node_modules/three/build/three.tsl.js 45192var BRDF_GGX2 = TSL.BRDF_GGX; 45193var BRDF_Lambert2 = TSL.BRDF_Lambert; 45194var BasicPointShadowFilter2 = TSL.BasicPointShadowFilter; 45195var BasicShadowFilter2 = TSL.BasicShadowFilter; 45196var Break2 = TSL.Break; 45197var Const2 = TSL.Const; 45198var Continue2 = TSL.Continue; 45199var DFGLUT2 = TSL.DFGLUT; 45200var D_GGX2 = TSL.D_GGX; 45201var Discard2 = TSL.Discard; 45202var EPSILON2 = TSL.EPSILON; 45203var F_Schlick2 = TSL.F_Schlick; 45204var Fn2 = TSL.Fn; 45205var INFINITY2 = TSL.INFINITY; 45206var If2 = TSL.If; 45207var Loop2 = TSL.Loop; 45208var NodeAccess2 = TSL.NodeAccess; 45209var NodeShaderStage2 = TSL.NodeShaderStage; 45210var NodeType2 = TSL.NodeType; 45211var NodeUpdateType2 = TSL.NodeUpdateType; 45212var PCFShadowFilter2 = TSL.PCFShadowFilter; 45213var PCFSoftShadowFilter2 = TSL.PCFSoftShadowFilter; 45214var PI3 = TSL.PI; 45215var PI22 = TSL.PI2; 45216var TWO_PI2 = TSL.TWO_PI; 45217var HALF_PI2 = TSL.HALF_PI; 45218var PointShadowFilter2 = TSL.PointShadowFilter; 45219var Return2 = TSL.Return; 45220var Schlick_to_F02 = TSL.Schlick_to_F0; 45221var ShaderNode2 = TSL.ShaderNode; 45222var Stack2 = TSL.Stack; 45223var Switch2 = TSL.Switch; 45224var TBNViewMatrix2 = TSL.TBNViewMatrix; 45225var VSMShadowFilter2 = TSL.VSMShadowFilter; 45226var V_GGX_SmithCorrelated2 = TSL.V_GGX_SmithCorrelated; 45227var Var2 = TSL.Var; 45228var VarIntent2 = TSL.VarIntent; 45229var abs2 = TSL.abs; 45230var acesFilmicToneMapping2 = TSL.acesFilmicToneMapping; 45231var acos2 = TSL.acos; 45232var acosh2 = TSL.acosh; 45233var add2 = TSL.add; 45234var addMethodChaining2 = TSL.addMethodChaining; 45235var addNodeElement2 = TSL.addNodeElement; 45236var agxToneMapping2 = TSL.agxToneMapping; 45237var all2 = TSL.all; 45238var alphaT2 = TSL.alphaT; 45239var and2 = TSL.and; 45240var anisotropy2 = TSL.anisotropy; 45241var anisotropyB2 = TSL.anisotropyB; 45242var anisotropyT2 = TSL.anisotropyT; 45243var any2 = TSL.any; 45244var append2 = TSL.append; 45245var array2 = TSL.array; 45246var arrayBuffer2 = TSL.arrayBuffer; 45247var asin2 = TSL.asin; 45248var asinh2 = TSL.asinh; 45249var assign2 = TSL.assign; 45250var atan2 = TSL.atan; 45251var atanh2 = TSL.atanh; 45252var atomicAdd2 = TSL.atomicAdd; 45253var atomicAnd2 = TSL.atomicAnd; 45254var atomicFunc2 = TSL.atomicFunc; 45255var atomicLoad2 = TSL.atomicLoad; 45256var atomicMax2 = TSL.atomicMax; 45257var atomicMin2 = TSL.atomicMin; 45258var atomicOr2 = TSL.atomicOr; 45259var atomicStore2 = TSL.atomicStore; 45260var atomicSub2 = TSL.atomicSub; 45261var atomicXor2 = TSL.atomicXor; 45262var attenuationColor2 = TSL.attenuationColor; 45263var attenuationDistance2 = TSL.attenuationDistance; 45264var attribute2 = TSL.attribute; 45265var attributeArray2 = TSL.attributeArray; 45266var backgroundBlurriness2 = TSL.backgroundBlurriness; 45267var backgroundIntensity2 = TSL.backgroundIntensity; 45268var backgroundRotation2 = TSL.backgroundRotation; 45269var batch3 = TSL.batch; 45270var bentNormalView2 = TSL.bentNormalView; 45271var billboarding2 = TSL.billboarding; 45272var bitAnd2 = TSL.bitAnd; 45273var bitNot2 = TSL.bitNot; 45274var bitOr2 = TSL.bitOr; 45275var bitXor2 = TSL.bitXor; 45276var bitangentGeometry2 = TSL.bitangentGeometry; 45277var bitangentLocal2 = TSL.bitangentLocal; 45278var bitangentView2 = TSL.bitangentView; 45279var bitangentWorld2 = TSL.bitangentWorld; 45280var bitcast2 = TSL.bitcast; 45281var blendBurn2 = TSL.blendBurn; 45282var blendColor2 = TSL.blendColor; 45283var blendDodge2 = TSL.blendDodge; 45284var blendOverlay2 = TSL.blendOverlay; 45285var blendScreen2 = TSL.blendScreen; 45286var blur2 = TSL.blur; 45287var bool2 = TSL.bool; 45288var buffer2 = TSL.buffer; 45289var bufferAttribute2 = TSL.bufferAttribute; 45290var bumpMap2 = TSL.bumpMap; 45291var builtin2 = TSL.builtin; 45292var builtinAOContext2 = TSL.builtinAOContext; 45293var builtinShadowContext2 = TSL.builtinShadowContext; 45294var bvec22 = TSL.bvec2; 45295var bvec32 = TSL.bvec3; 45296var bvec42 = TSL.bvec4; 45297var bypass2 = TSL.bypass; 45298var cache2 = TSL.cache; 45299var call2 = TSL.call; 45300var cameraFar2 = TSL.cameraFar; 45301var cameraIndex2 = TSL.cameraIndex; 45302var cameraNear2 = TSL.cameraNear; 45303var cameraNormalMatrix2 = TSL.cameraNormalMatrix; 45304var cameraPosition2 = TSL.cameraPosition; 45305var cameraProjectionMatrix2 = TSL.cameraProjectionMatrix; 45306var cameraProjectionMatrixInverse2 = TSL.cameraProjectionMatrixInverse; 45307var cameraViewMatrix2 = TSL.cameraViewMatrix; 45308var cameraViewport2 = TSL.cameraViewport; 45309var cameraWorldMatrix2 = TSL.cameraWorldMatrix; 45310var cbrt2 = TSL.cbrt; 45311var cdl2 = TSL.cdl; 45312var ceil2 = TSL.ceil; 45313var checker2 = TSL.checker; 45314var cineonToneMapping2 = TSL.cineonToneMapping; 45315var clamp4 = TSL.clamp; 45316var clearcoat2 = TSL.clearcoat; 45317var clearcoatNormalView2 = TSL.clearcoatNormalView; 45318var clearcoatRoughness2 = TSL.clearcoatRoughness; 45319var clipSpace2 = TSL.clipSpace; 45320var code2 = TSL.code; 45321var color2 = TSL.color; 45322var colorSpaceToWorking2 = TSL.colorSpaceToWorking; 45323var colorToDirection2 = TSL.colorToDirection; 45324var compute2 = TSL.compute; 45325var computeKernel2 = TSL.computeKernel; 45326var computeSkinning2 = TSL.computeSkinning; 45327var context2 = TSL.context; 45328var convert2 = TSL.convert; 45329var convertColorSpace2 = TSL.convertColorSpace; 45330var convertToTexture2 = TSL.convertToTexture; 45331var countLeadingZeros2 = TSL.countLeadingZeros; 45332var countOneBits2 = TSL.countOneBits; 45333var countTrailingZeros2 = TSL.countTrailingZeros; 45334var cos2 = TSL.cos; 45335var cosh2 = TSL.cosh; 45336var cross2 = TSL.cross; 45337var cubeTexture2 = TSL.cubeTexture; 45338var cubeTextureBase2 = TSL.cubeTextureBase; 45339var dFdx2 = TSL.dFdx; 45340var dFdy2 = TSL.dFdy; 45341var dashSize2 = TSL.dashSize; 45342var debug2 = TSL.debug; 45343var decrement2 = TSL.decrement; 45344var decrementBefore2 = TSL.decrementBefore; 45345var defaultBuildStages2 = TSL.defaultBuildStages; 45346var defaultShaderStages2 = TSL.defaultShaderStages; 45347var defined2 = TSL.defined; 45348var degrees2 = TSL.degrees; 45349var deltaTime2 = TSL.deltaTime; 45350var densityFog = TSL.densityFog; 45351var densityFogFactor2 = TSL.densityFogFactor; 45352var depth2 = TSL.depth; 45353var depthPass2 = TSL.depthPass; 45354var determinant2 = TSL.determinant; 45355var difference2 = TSL.difference; 45356var diffuseColor2 = TSL.diffuseColor; 45357var directPointLight2 = TSL.directPointLight; 45358var directionToColor2 = TSL.directionToColor; 45359var directionToFaceDirection2 = TSL.directionToFaceDirection; 45360var dispersion2 = TSL.dispersion; 45361var distance2 = TSL.distance; 45362var div2 = TSL.div; 45363var dot2 = TSL.dot; 45364var drawIndex2 = TSL.drawIndex; 45365var dynamicBufferAttribute2 = TSL.dynamicBufferAttribute; 45366var element2 = TSL.element; 45367var emissive2 = TSL.emissive; 45368var equal2 = TSL.equal; 45369var equirectUV2 = TSL.equirectUV; 45370var exp3 = TSL.exp; 45371var exp22 = TSL.exp2; 45372var exponentialHeightFogFactor2 = TSL.exponentialHeightFogFactor; 45373var expression2 = TSL.expression; 45374var faceDirection2 = TSL.faceDirection; 45375var faceForward2 = TSL.faceForward; 45376var faceforward2 = TSL.faceforward; 45377var float2 = TSL.float; 45378var floatBitsToInt2 = TSL.floatBitsToInt; 45379var floatBitsToUint2 = TSL.floatBitsToUint; 45380var floor2 = TSL.floor; 45381var fog2 = TSL.fog; 45382var fract2 = TSL.fract; 45383var frameGroup2 = TSL.frameGroup; 45384var frameId2 = TSL.frameId; 45385var frontFacing2 = TSL.frontFacing; 45386var fwidth2 = TSL.fwidth; 45387var gain2 = TSL.gain; 45388var gapSize2 = TSL.gapSize; 45389var getConstNodeType2 = TSL.getConstNodeType; 45390var getCurrentStack2 = TSL.getCurrentStack; 45391var getDirection2 = TSL.getDirection; 45392var getDistanceAttenuation2 = TSL.getDistanceAttenuation; 45393var getGeometryRoughness2 = TSL.getGeometryRoughness; 45394var getNormalFromDepth2 = TSL.getNormalFromDepth; 45395var interleavedGradientNoise2 = TSL.interleavedGradientNoise; 45396var vogelDiskSample2 = TSL.vogelDiskSample; 45397var getParallaxCorrectNormal2 = TSL.getParallaxCorrectNormal; 45398var getRoughness2 = TSL.getRoughness; 45399var getScreenPosition2 = TSL.getScreenPosition; 45400var getShIrradianceAt2 = TSL.getShIrradianceAt; 45401var getShadowMaterial2 = TSL.getShadowMaterial; 45402var getShadowRenderObjectFunction2 = TSL.getShadowRenderObjectFunction; 45403var getTextureIndex2 = TSL.getTextureIndex; 45404var getViewPosition2 = TSL.getViewPosition; 45405var globalId2 = TSL.globalId; 45406var glsl2 = TSL.glsl; 45407var glslFn2 = TSL.glslFn; 45408var grayscale2 = TSL.grayscale; 45409var greaterThan2 = TSL.greaterThan; 45410var greaterThanEqual2 = TSL.greaterThanEqual; 45411var hash2 = TSL.hash; 45412var highpModelNormalViewMatrix2 = TSL.highpModelNormalViewMatrix; 45413var highpModelViewMatrix2 = TSL.highpModelViewMatrix; 45414var hue2 = TSL.hue; 45415var increment2 = TSL.increment; 45416var incrementBefore2 = TSL.incrementBefore; 45417var instance2 = TSL.instance; 45418var instanceIndex2 = TSL.instanceIndex; 45419var instancedArray2 = TSL.instancedArray; 45420var instancedBufferAttribute2 = TSL.instancedBufferAttribute; 45421var instancedDynamicBufferAttribute2 = TSL.instancedDynamicBufferAttribute; 45422var instancedMesh2 = TSL.instancedMesh; 45423var int2 = TSL.int; 45424var intBitsToFloat2 = TSL.intBitsToFloat; 45425var inverse2 = TSL.inverse; 45426var inverseSqrt2 = TSL.inverseSqrt; 45427var inversesqrt2 = TSL.inversesqrt; 45428var invocationLocalIndex2 = TSL.invocationLocalIndex; 45429var invocationSubgroupIndex2 = TSL.invocationSubgroupIndex; 45430var ior2 = TSL.ior; 45431var iridescence2 = TSL.iridescence; 45432var iridescenceIOR2 = TSL.iridescenceIOR; 45433var iridescenceThickness2 = TSL.iridescenceThickness; 45434var ivec22 = TSL.ivec2; 45435var ivec32 = TSL.ivec3; 45436var ivec42 = TSL.ivec4; 45437var js2 = TSL.js; 45438var label2 = TSL.label; 45439var length2 = TSL.length; 45440var lengthSq2 = TSL.lengthSq; 45441var lessThan2 = TSL.lessThan; 45442var lessThanEqual2 = TSL.lessThanEqual; 45443var lightPosition2 = TSL.lightPosition; 45444var lightProjectionUV2 = TSL.lightProjectionUV; 45445var lightShadowMatrix2 = TSL.lightShadowMatrix; 45446var lightTargetDirection2 = TSL.lightTargetDirection; 45447var lightTargetPosition2 = TSL.lightTargetPosition; 45448var lightViewPosition2 = TSL.lightViewPosition; 45449var lightingContext2 = TSL.lightingContext; 45450var lights2 = TSL.lights; 45451var linearDepth2 = TSL.linearDepth; 45452var linearToneMapping2 = TSL.linearToneMapping; 45453var localId2 = TSL.localId; 45454var log3 = TSL.log; 45455var log23 = TSL.log2; 45456var logarithmicDepthToViewZ2 = TSL.logarithmicDepthToViewZ; 45457var luminance2 = TSL.luminance; 45458var mat22 = TSL.mat2; 45459var mat32 = TSL.mat3; 45460var mat42 = TSL.mat4; 45461var matcapUV2 = TSL.matcapUV; 45462var materialAO2 = TSL.materialAO; 45463var materialAlphaTest2 = TSL.materialAlphaTest; 45464var materialAnisotropy2 = TSL.materialAnisotropy; 45465var materialAnisotropyVector2 = TSL.materialAnisotropyVector; 45466var materialAttenuationColor2 = TSL.materialAttenuationColor; 45467var materialAttenuationDistance2 = TSL.materialAttenuationDistance; 45468var materialClearcoat2 = TSL.materialClearcoat; 45469var materialClearcoatNormal2 = TSL.materialClearcoatNormal; 45470var materialClearcoatRoughness2 = TSL.materialClearcoatRoughness; 45471var materialColor2 = TSL.materialColor; 45472var materialDispersion2 = TSL.materialDispersion; 45473var materialEmissive2 = TSL.materialEmissive; 45474var materialEnvIntensity2 = TSL.materialEnvIntensity; 45475var materialEnvRotation2 = TSL.materialEnvRotation; 45476var materialIOR2 = TSL.materialIOR; 45477var materialIridescence2 = TSL.materialIridescence; 45478var materialIridescenceIOR2 = TSL.materialIridescenceIOR; 45479var materialIridescenceThickness2 = TSL.materialIridescenceThickness; 45480var materialLightMap2 = TSL.materialLightMap; 45481var materialLineDashOffset2 = TSL.materialLineDashOffset; 45482var materialLineDashSize2 = TSL.materialLineDashSize; 45483var materialLineGapSize2 = TSL.materialLineGapSize; 45484var materialLineScale2 = TSL.materialLineScale; 45485var materialLineWidth2 = TSL.materialLineWidth; 45486var materialMetalness2 = TSL.materialMetalness; 45487var materialNormal2 = TSL.materialNormal; 45488var materialOpacity2 = TSL.materialOpacity; 45489var materialPointSize2 = TSL.materialPointSize; 45490var materialReference2 = TSL.materialReference; 45491var materialReflectivity2 = TSL.materialReflectivity; 45492var materialRefractionRatio2 = TSL.materialRefractionRatio; 45493var materialRotation2 = TSL.materialRotation; 45494var materialRoughness2 = TSL.materialRoughness; 45495var materialSheen2 = TSL.materialSheen; 45496var materialSheenRoughness2 = TSL.materialSheenRoughness; 45497var materialShininess2 = TSL.materialShininess; 45498var materialSpecular2 = TSL.materialSpecular; 45499var materialSpecularColor2 = TSL.materialSpecularColor; 45500var materialSpecularIntensity2 = TSL.materialSpecularIntensity; 45501var materialSpecularStrength2 = TSL.materialSpecularStrength; 45502var materialThickness2 = TSL.materialThickness; 45503var materialTransmission2 = TSL.materialTransmission; 45504var max2 = TSL.max; 45505var maxMipLevel2 = TSL.maxMipLevel; 45506var mediumpModelViewMatrix2 = TSL.mediumpModelViewMatrix; 45507var metalness2 = TSL.metalness; 45508var min2 = TSL.min; 45509var mix2 = TSL.mix; 45510var mixElement2 = TSL.mixElement; 45511var mod2 = TSL.mod; 45512var modInt2 = TSL.modInt; 45513var modelDirection2 = TSL.modelDirection; 45514var modelNormalMatrix2 = TSL.modelNormalMatrix; 45515var modelPosition2 = TSL.modelPosition; 45516var modelRadius2 = TSL.modelRadius; 45517var modelScale2 = TSL.modelScale; 45518var modelViewMatrix2 = TSL.modelViewMatrix; 45519var modelViewPosition2 = TSL.modelViewPosition; 45520var modelViewProjection2 = TSL.modelViewProjection; 45521var modelWorldMatrix2 = TSL.modelWorldMatrix; 45522var modelWorldMatrixInverse2 = TSL.modelWorldMatrixInverse; 45523var morphReference2 = TSL.morphReference; 45524var mrt2 = TSL.mrt; 45525var mul2 = TSL.mul; 45526var mx_aastep2 = TSL.mx_aastep; 45527var mx_add2 = TSL.mx_add; 45528var mx_atan22 = TSL.mx_atan2; 45529var mx_cell_noise_float2 = TSL.mx_cell_noise_float; 45530var mx_contrast2 = TSL.mx_contrast; 45531var mx_divide2 = TSL.mx_divide; 45532var mx_fractal_noise_float2 = TSL.mx_fractal_noise_float; 45533var mx_fractal_noise_vec22 = TSL.mx_fractal_noise_vec2; 45534var mx_fractal_noise_vec32 = TSL.mx_fractal_noise_vec3; 45535var mx_fractal_noise_vec42 = TSL.mx_fractal_noise_vec4; 45536var mx_frame2 = TSL.mx_frame; 45537var mx_heighttonormal2 = TSL.mx_heighttonormal; 45538var mx_hsvtorgb2 = TSL.mx_hsvtorgb; 45539var mx_ifequal2 = TSL.mx_ifequal; 45540var mx_ifgreater2 = TSL.mx_ifgreater; 45541var mx_ifgreatereq2 = TSL.mx_ifgreatereq; 45542var mx_invert2 = TSL.mx_invert; 45543var mx_modulo2 = TSL.mx_modulo; 45544var mx_multiply2 = TSL.mx_multiply; 45545var mx_noise_float2 = TSL.mx_noise_float; 45546var mx_noise_vec32 = TSL.mx_noise_vec3; 45547var mx_noise_vec42 = TSL.mx_noise_vec4; 45548var mx_place2d2 = TSL.mx_place2d; 45549var mx_power2 = TSL.mx_power; 45550var mx_ramp42 = TSL.mx_ramp4; 45551var mx_ramplr2 = TSL.mx_ramplr; 45552var mx_ramptb2 = TSL.mx_ramptb; 45553var mx_rgbtohsv2 = TSL.mx_rgbtohsv; 45554var mx_rotate2d2 = TSL.mx_rotate2d; 45555var mx_rotate3d2 = TSL.mx_rotate3d; 45556var mx_safepower2 = TSL.mx_safepower; 45557var mx_separate2 = TSL.mx_separate; 45558var mx_splitlr2 = TSL.mx_splitlr; 45559var mx_splittb2 = TSL.mx_splittb; 45560var mx_srgb_texture_to_lin_rec7092 = TSL.mx_srgb_texture_to_lin_rec709; 45561var mx_subtract2 = TSL.mx_subtract; 45562var mx_timer2 = TSL.mx_timer; 45563var mx_transform_uv2 = TSL.mx_transform_uv; 45564var mx_unifiednoise2d2 = TSL.mx_unifiednoise2d; 45565var mx_unifiednoise3d2 = TSL.mx_unifiednoise3d; 45566var mx_worley_noise_float2 = TSL.mx_worley_noise_float; 45567var mx_worley_noise_vec22 = TSL.mx_worley_noise_vec2; 45568var mx_worley_noise_vec32 = TSL.mx_worley_noise_vec3; 45569var negate2 = TSL.negate; 45570var neutralToneMapping2 = TSL.neutralToneMapping; 45571var nodeArray2 = TSL.nodeArray; 45572var nodeImmutable2 = TSL.nodeImmutable; 45573var nodeObject2 = TSL.nodeObject; 45574var nodeObjectIntent2 = TSL.nodeObjectIntent; 45575var nodeObjects2 = TSL.nodeObjects; 45576var nodeProxy2 = TSL.nodeProxy; 45577var nodeProxyIntent2 = TSL.nodeProxyIntent; 45578var normalFlat2 = TSL.normalFlat; 45579var normalGeometry2 = TSL.normalGeometry; 45580var normalLocal2 = TSL.normalLocal; 45581var normalMap2 = TSL.normalMap; 45582var normalView2 = TSL.normalView; 45583var normalViewGeometry2 = TSL.normalViewGeometry; 45584var normalWorld2 = TSL.normalWorld; 45585var normalWorldGeometry2 = TSL.normalWorldGeometry; 45586var normalize2 = TSL.normalize; 45587var not2 = TSL.not; 45588var notEqual2 = TSL.notEqual; 45589var numWorkgroups2 = TSL.numWorkgroups; 45590var objectDirection2 = TSL.objectDirection; 45591var objectGroup2 = TSL.objectGroup; 45592var objectPosition2 = TSL.objectPosition; 45593var objectRadius2 = TSL.objectRadius; 45594var objectScale2 = TSL.objectScale; 45595var objectViewPosition2 = TSL.objectViewPosition; 45596var objectWorldMatrix2 = TSL.objectWorldMatrix; 45597var OnBeforeObjectUpdate2 = TSL.OnBeforeObjectUpdate; 45598var OnBeforeMaterialUpdate2 = TSL.OnBeforeMaterialUpdate; 45599var OnObjectUpdate2 = TSL.OnObjectUpdate; 45600var OnMaterialUpdate2 = TSL.OnMaterialUpdate; 45601var oneMinus2 = TSL.oneMinus; 45602var or2 = TSL.or; 45603var orthographicDepthToViewZ2 = TSL.orthographicDepthToViewZ; 45604var oscSawtooth2 = TSL.oscSawtooth; 45605var oscSine2 = TSL.oscSine; 45606var oscSquare2 = TSL.oscSquare; 45607var oscTriangle2 = TSL.oscTriangle; 45608var output2 = TSL.output; 45609var outputStruct2 = TSL.outputStruct; 45610var overloadingFn2 = TSL.overloadingFn; 45611var packHalf2x162 = TSL.packHalf2x16; 45612var packSnorm2x162 = TSL.packSnorm2x16; 45613var packUnorm2x162 = TSL.packUnorm2x16; 45614var parabola2 = TSL.parabola; 45615var parallaxDirection2 = TSL.parallaxDirection; 45616var parallaxUV2 = TSL.parallaxUV; 45617var parameter2 = TSL.parameter; 45618var pass2 = TSL.pass; 45619var passTexture2 = TSL.passTexture; 45620var pcurve2 = TSL.pcurve; 45621var perspectiveDepthToViewZ2 = TSL.perspectiveDepthToViewZ; 45622var pmremTexture2 = TSL.pmremTexture; 45623var pointShadow2 = TSL.pointShadow; 45624var pointUV2 = TSL.pointUV; 45625var pointWidth2 = TSL.pointWidth; 45626var positionGeometry2 = TSL.positionGeometry; 45627var positionLocal2 = TSL.positionLocal; 45628var positionPrevious2 = TSL.positionPrevious; 45629var positionView2 = TSL.positionView; 45630var positionViewDirection2 = TSL.positionViewDirection; 45631var positionWorld2 = TSL.positionWorld; 45632var positionWorldDirection2 = TSL.positionWorldDirection; 45633var posterize2 = TSL.posterize; 45634var pow5 = TSL.pow; 45635var pow22 = TSL.pow2; 45636var pow32 = TSL.pow3; 45637var pow42 = TSL.pow4; 45638var premultiplyAlpha2 = TSL.premultiplyAlpha; 45639var property2 = TSL.property; 45640var radians2 = TSL.radians; 45641var rand2 = TSL.rand; 45642var range2 = TSL.range; 45643var rangeFog = TSL.rangeFog; 45644var rangeFogFactor2 = TSL.rangeFogFactor; 45645var reciprocal2 = TSL.reciprocal; 45646var reference2 = TSL.reference; 45647var referenceBuffer2 = TSL.referenceBuffer; 45648var reflect2 = TSL.reflect; 45649var reflectVector2 = TSL.reflectVector; 45650var reflectView2 = TSL.reflectView; 45651var reflector2 = TSL.reflector; 45652var refract2 = TSL.refract; 45653var refractVector2 = TSL.refractVector; 45654var refractView2 = TSL.refractView; 45655var reinhardToneMapping2 = TSL.reinhardToneMapping; 45656var remap2 = TSL.remap; 45657var remapClamp2 = TSL.remapClamp; 45658var renderGroup2 = TSL.renderGroup; 45659var renderOutput2 = TSL.renderOutput; 45660var rendererReference2 = TSL.rendererReference; 45661var replaceDefaultUV2 = TSL.replaceDefaultUV; 45662var rotate2 = TSL.rotate; 45663var rotateUV2 = TSL.rotateUV; 45664var roughness2 = TSL.roughness; 45665var round2 = TSL.round; 45666var rtt2 = TSL.rtt; 45667var sRGBTransferEOTF2 = TSL.sRGBTransferEOTF; 45668var sRGBTransferOETF2 = TSL.sRGBTransferOETF; 45669var sample2 = TSL.sample; 45670var sampler2 = TSL.sampler; 45671var samplerComparison2 = TSL.samplerComparison; 45672var saturate2 = TSL.saturate; 45673var saturation2 = TSL.saturation; 45674var screen = TSL.screen; 45675var screenCoordinate2 = TSL.screenCoordinate; 45676var screenDPR2 = TSL.screenDPR; 45677var screenSize2 = TSL.screenSize; 45678var screenUV2 = TSL.screenUV; 45679var select2 = TSL.select; 45680var setCurrentStack2 = TSL.setCurrentStack; 45681var setName2 = TSL.setName; 45682var shaderStages2 = TSL.shaderStages; 45683var shadow2 = TSL.shadow; 45684var shadowPositionWorld2 = TSL.shadowPositionWorld; 45685var shapeCircle2 = TSL.shapeCircle; 45686var sharedUniformGroup2 = TSL.sharedUniformGroup; 45687var sheen2 = TSL.sheen; 45688var sheenRoughness2 = TSL.sheenRoughness; 45689var shiftLeft2 = TSL.shiftLeft; 45690var shiftRight2 = TSL.shiftRight; 45691var shininess2 = TSL.shininess; 45692var sign2 = TSL.sign; 45693var sin2 = TSL.sin; 45694var sinh2 = TSL.sinh; 45695var sinc2 = TSL.sinc; 45696var skinning2 = TSL.skinning; 45697var smoothstep2 = TSL.smoothstep; 45698var smoothstepElement2 = TSL.smoothstepElement; 45699var specularColor2 = TSL.specularColor; 45700var specularF902 = TSL.specularF90; 45701var spherizeUV2 = TSL.spherizeUV; 45702var split2 = TSL.split; 45703var spritesheetUV2 = TSL.spritesheetUV; 45704var sqrt2 = TSL.sqrt; 45705var stack2 = TSL.stack; 45706var step2 = TSL.step; 45707var stepElement2 = TSL.stepElement; 45708var storage2 = TSL.storage; 45709var storageBarrier2 = TSL.storageBarrier; 45710var storageTexture2 = TSL.storageTexture; 45711var string2 = TSL.string; 45712var struct2 = TSL.struct; 45713var sub2 = TSL.sub; 45714var subgroupAdd2 = TSL.subgroupAdd; 45715var subgroupAll2 = TSL.subgroupAll; 45716var subgroupAnd2 = TSL.subgroupAnd; 45717var subgroupAny2 = TSL.subgroupAny; 45718var subgroupBallot2 = TSL.subgroupBallot; 45719var subgroupBroadcast2 = TSL.subgroupBroadcast; 45720var subgroupBroadcastFirst2 = TSL.subgroupBroadcastFirst; 45721var subBuild2 = TSL.subBuild; 45722var subgroupElect2 = TSL.subgroupElect; 45723var subgroupExclusiveAdd2 = TSL.subgroupExclusiveAdd; 45724var subgroupExclusiveMul2 = TSL.subgroupExclusiveMul; 45725var subgroupInclusiveAdd2 = TSL.subgroupInclusiveAdd; 45726var subgroupInclusiveMul2 = TSL.subgroupInclusiveMul; 45727var subgroupIndex2 = TSL.subgroupIndex; 45728var subgroupMax2 = TSL.subgroupMax; 45729var subgroupMin2 = TSL.subgroupMin; 45730var subgroupMul2 = TSL.subgroupMul; 45731var subgroupOr2 = TSL.subgroupOr; 45732var subgroupShuffle2 = TSL.subgroupShuffle; 45733var subgroupShuffleDown2 = TSL.subgroupShuffleDown; 45734var subgroupShuffleUp2 = TSL.subgroupShuffleUp; 45735var subgroupShuffleXor2 = TSL.subgroupShuffleXor; 45736var subgroupSize2 = TSL.subgroupSize; 45737var subgroupXor2 = TSL.subgroupXor; 45738var tan2 = TSL.tan; 45739var tanh2 = TSL.tanh; 45740var tangentGeometry2 = TSL.tangentGeometry; 45741var tangentLocal2 = TSL.tangentLocal; 45742var tangentView2 = TSL.tangentView; 45743var tangentWorld2 = TSL.tangentWorld; 45744var texture2 = TSL.texture; 45745var texture3D2 = TSL.texture3D; 45746var textureBarrier2 = TSL.textureBarrier; 45747var textureBicubic2 = TSL.textureBicubic; 45748var textureBicubicLevel2 = TSL.textureBicubicLevel; 45749var textureCubeUV2 = TSL.textureCubeUV; 45750var textureLoad2 = TSL.textureLoad; 45751var textureSize2 = TSL.textureSize; 45752var textureLevel2 = TSL.textureLevel; 45753var textureStore2 = TSL.textureStore; 45754var thickness2 = TSL.thickness; 45755var time2 = TSL.time; 45756var toneMapping2 = TSL.toneMapping; 45757var toneMappingExposure2 = TSL.toneMappingExposure; 45758var toonOutlinePass2 = TSL.toonOutlinePass; 45759var transformDirection2 = TSL.transformDirection; 45760var transformNormal2 = TSL.transformNormal; 45761var transformNormalToView2 = TSL.transformNormalToView; 45762var transformedClearcoatNormalView2 = TSL.transformedClearcoatNormalView; 45763var transformedNormalView2 = TSL.transformedNormalView; 45764var transformedNormalWorld2 = TSL.transformedNormalWorld; 45765var transmission2 = TSL.transmission; 45766var transpose2 = TSL.transpose; 45767var triNoise3D2 = TSL.triNoise3D; 45768var triplanarTexture2 = TSL.triplanarTexture; 45769var triplanarTextures2 = TSL.triplanarTextures; 45770var trunc2 = TSL.trunc; 45771var uint2 = TSL.uint; 45772var uintBitsToFloat2 = TSL.uintBitsToFloat; 45773var uniform2 = TSL.uniform; 45774var uniformArray2 = TSL.uniformArray; 45775var uniformCubeTexture2 = TSL.uniformCubeTexture; 45776var uniformGroup2 = TSL.uniformGroup; 45777var uniformFlow2 = TSL.uniformFlow; 45778var uniformTexture2 = TSL.uniformTexture; 45779var unpackHalf2x162 = TSL.unpackHalf2x16; 45780var unpackSnorm2x162 = TSL.unpackSnorm2x16; 45781var unpackUnorm2x162 = TSL.unpackUnorm2x16; 45782var unpremultiplyAlpha2 = TSL.unpremultiplyAlpha; 45783var userData2 = TSL.userData; 45784var uv2 = TSL.uv; 45785var uvec22 = TSL.uvec2; 45786var uvec32 = TSL.uvec3; 45787var uvec42 = TSL.uvec4; 45788var varying2 = TSL.varying; 45789var varyingProperty2 = TSL.varyingProperty; 45790var vec22 = TSL.vec2; 45791var vec32 = TSL.vec3; 45792var vec42 = TSL.vec4; 45793var vectorComponents2 = TSL.vectorComponents; 45794var velocity2 = TSL.velocity; 45795var vertexColor2 = TSL.vertexColor; 45796var vertexIndex2 = TSL.vertexIndex; 45797var vertexStage2 = TSL.vertexStage; 45798var vibrance2 = TSL.vibrance; 45799var viewZToLogarithmicDepth2 = TSL.viewZToLogarithmicDepth; 45800var viewZToOrthographicDepth2 = TSL.viewZToOrthographicDepth; 45801var viewZToPerspectiveDepth2 = TSL.viewZToPerspectiveDepth; 45802var viewZToReversedOrthographicDepth2 = TSL.viewZToReversedOrthographicDepth; 45803var viewZToReversedPerspectiveDepth2 = TSL.viewZToReversedPerspectiveDepth; 45804var viewport2 = TSL.viewport; 45805var viewportCoordinate2 = TSL.viewportCoordinate; 45806var viewportDepthTexture2 = TSL.viewportDepthTexture; 45807var viewportLinearDepth2 = TSL.viewportLinearDepth; 45808var viewportMipTexture2 = TSL.viewportMipTexture; 45809var viewportOpaqueMipTexture2 = TSL.viewportOpaqueMipTexture; 45810var viewportResolution2 = TSL.viewportResolution; 45811var viewportSafeUV2 = TSL.viewportSafeUV; 45812var viewportSharedTexture2 = TSL.viewportSharedTexture; 45813var viewportSize2 = TSL.viewportSize; 45814var viewportTexture2 = TSL.viewportTexture; 45815var viewportUV2 = TSL.viewportUV; 45816var wgsl2 = TSL.wgsl; 45817var wgslFn2 = TSL.wgslFn; 45818var workgroupArray2 = TSL.workgroupArray; 45819var workgroupBarrier2 = TSL.workgroupBarrier; 45820var workgroupId2 = TSL.workgroupId; 45821var workingToColorSpace2 = TSL.workingToColorSpace; 45822var xor2 = TSL.xor; 45823
45824// src/viewer/context/symmetry-renderer.js 45825var INITIAL_SHAPE_CAPACITY = 64; 45826var COLOR_PALETTE_CAPACITY = 256; 45827function createSymmetryRenderer(parent) { 45828 const originGroup = new Group(); 45829 originGroup.matrixAutoUpdate = false; 45830 parent.add(originGroup); 45831 const colorMatrices = Array.from({ length: COLOR_PALETTE_CAPACITY }, () => new Vector3()); 45832 let colorCount = 0; 45833 const colorPalette = uniformArray2(colorMatrices); 45834 const symmetryGroups = /* @__PURE__ */ new Map(); 45835 let activeGroupId = null; 45836 let discardInactiveShaders = false; 45837 let pickingRendererPromise = null; 45838 async function getPickingRenderer() { 45839 if (!pickingRendererPromise) { 45840 pickingRendererPromise = (async () => { 45841 const canvas = document.createElement("canvas"); 45842 const renderer = new WebGPURenderer({ 45843 canvas, 45844 antialias: false, 45845 alpha: true, 45846 forceWebGL: true 45847 }); 45848 await renderer.init(); 45849 return renderer; 45850 })(); 45851 } 45852 return pickingRendererPromise; 45853 } 45854 function registerSymmetryGroup(groupId, orientations) { 45855 if (symmetryGroups.has(groupId)) { 45856 throw new Error(`Symmetry group '${groupId}' already exists.`); 45857 } 45858 if (!Array.isArray(orientations) || orientations.length === 0) { 45859 throw new Error("A symmetry group needs at least one orientation."); 45860 } 45861 const orientationMatrices = orientations.map((item) => { 45862 if (item instanceof Matrix4) { 45863 return item.clone(); 45864 } 45865 if (item instanceof Euler) { 45866 return new Matrix4().makeRotationFromEuler(item); 45867 } 45868 throw new Error("Orientation must be a Euler or Matrix4."); 45869 }); 45870 const group = { 45871 id: groupId, 45872 orientations: orientationMatrices, 45873 styles: /* @__PURE__ */ new Map(), 45874 slots: /* @__PURE__ */ new Set(), 45875 activeStyleId: null, 45876 instancesByShape: /* @__PURE__ */ new Map(), 45877 nextInstanceId: 1, 45878 gpu: null 45879 }; 45880 symmetryGroups.set(groupId, group); 45881 return group; 45882 } 45883 function registerStyle(groupId, styleId) { 45884 const group = getSymmetryGroup(groupId); 45885 if (group.styles.has(styleId)) { 45886 throw new Error(`Style '${styleId}' is already registered in group '${groupId}'.`); 45887 } 45888 group.styles.set(styleId, { id: styleId, geometries: /* @__PURE__ */ new Map() }); 45889 if (group.activeStyleId === null) { 45890 group.activeStyleId = styleId; 45891 } 45892 } 45893 function registerShape(groupId, styleId, slotId, geometry) { 45894 if (!(geometry instanceof BufferGeometry)) { 45895 throw new Error("Shape geometry must be a BufferGeometry."); 45896 } 45897 const group = getSymmetryGroup(groupId); 45898 const style2 = getStyle(group, styleId); 45899 if (style2.geometries.has(slotId)) { 45900 throw new Error(`Geometry for slot '${slotId}' is already registered in style '${styleId}'.`); 45901 } 45902 style2.geometries.set(slotId, geometry); 45903 group.slots.add(slotId); 45904 if (group.gpu) { 45905 let slotCache = group.gpu.cachedGeometries.get(slotId); 45906 if (!slotCache) { 45907 slotCache = /* @__PURE__ */ new Map(); 45908 group.gpu.cachedGeometries.set(slotId, slotCache); 45909 } 45910 slotCache.set(styleId, geometry.clone()); 45911 if (!group.gpu.shapeEntries.has(slotId)) { 45912 const activeGeom = (group.activeStyleId && slotCache.get(group.activeStyleId)) ?? slotCache.values().next().value; 45913 const outlineGeom = group.gpu.outlineGeometries.get(slotId) ?? null; 45914 const entry = createShapeEntry(slotId, activeGeom, outlineGeom, group.gpu.material, group.gpu.pickingMaterial, group.gpu.outlineMaterial); 45915 group.gpu.shapeEntries.set(slotId, entry); 45916 if (group.id === activeGroupId) { 45917 originGroup.add(entry.mesh); 45918 group.gpu.pickingOriginGroup.add(entry.pickingMesh); 45919 if (entry.outlineMesh) { 45920 originGroup.add(entry.outlineMesh); 45921 } 45922 } 45923 } 45924 } 45925 } 45926 function registerOutline(groupId, slotId, outlineGeometry) { 45927 if (!(outlineGeometry instanceof BufferGeometry)) { 45928 throw new Error("Outline geometry must be a BufferGeometry."); 45929 } 45930 const group = getSymmetryGroup(groupId); 45931 if (group.gpu && group.gpu.outlineGeometries.has(slotId)) { 45932 throw new Error(`Outline geometry for slot '${slotId}' is already registered in group '${groupId}'.`); 45933 } 45934 if (group.gpu) { 45935 group.gpu.outlineGeometries.set(slotId, outlineGeometry.clone()); 45936 const entry = group.gpu.shapeEntries.get(slotId); 45937 if (entry && !entry.outlineMesh) { 45938 attachOutlineMeshToEntry(group, entry, slotId); 45939 } 45940 } else { 45941 group.pendingOutlineGeometries = group.pendingOutlineGeometries ?? /* @__P
45941URE__ */ new Map(); 45942 group.pendingOutlineGeometries.set(slotId, outlineGeometry.clone()); 45943 } 45944 } 45945 function switchSymmetryGroup(groupId, options = {}) { 45946 const { 45947 discardUnusedShaders = discardInactiveShaders 45948 } = options; 45949 const nextGroup = getSymmetryGroup(groupId); 45950 if (activeGroupId === groupId) { 45951 return; 45952 } 45953 if (activeGroupId !== null) { 45954 const previous = symmetryGroups.get(activeGroupId); 45955 setGroupMeshesCount(previous, 0); 45956 } 45957 ensureGroupGpu(nextGroup); 45958 ensureGroupHasActiveStyle(nextGroup); 45959 addGroupMeshesToScene(nextGroup); 45960 activeGroupId = groupId; 45961 syncAllInstancesForGroup(nextGroup); 45962 if (discardUnusedShaders) { 45963 for (const group of symmetryGroups.values()) { 45964 if (group.id !== activeGroupId) { 45965 disposeGroupGpu(group); 45966 } 45967 } 45968 } 45969 } 45970 function setDiscardInactiveShaders(enabled) { 45971 discardInactiveShaders = Boolean(enabled); 45972 } 45973 function switchStyle(styleId) { 45974 const group = getActiveGroup(); 45975 getStyle(group, styleId); 45976 if (group.activeStyleId === styleId) { 45977 return; 45978 } 45979 group.activeStyleId = styleId; 45980 if (group.gpu) { 45981 swapGeometriesForStyle(group, styleId); 45982 } 45983 } 45984 function swapGeometriesForStyle(group, styleId) { 45985 for (const [slotId, entry] of group.gpu.shapeEntries) { 45986 swapBaseGeometry(entry, slotId, styleId, group.gpu.cachedGeometries); 45987 } 45988 } 45989 function setOutlinesVisible(visible) { 45990 const group = getActiveGroup(); 45991 if (!group.gpu) return; 45992 for (const entry of group.gpu.shapeEntries.values()) { 45993 if (entry.outlineMesh) { 45994 entry.outlineMesh.visible = visible; 45995 } 45996 } 45997 } 45998 function swapBaseGeometry(entry, slotId, newStyleId, cachedGeometries) { 45999 const slotCache = cachedGeometries.get(slotId); 46000 if (!slotCache) return; 46001 const newGeom = slotCache.get(newStyleId); 46002 if (!newGeom) return; 46003 const oldGeom = entry.mesh.geometry; 46004 if (oldGeom === newGeom) return; 46005 for (const name of ["orientationIndex", "instanceTranslation", "colorIndex", "highlightIntensity", "pickingId"]) { 46006 const attr = oldGeom.getAttribute(name); 46007 if (attr) { 46008 oldGeom.deleteAttribute(name); 46009 newGeom.setAttribute(name, attr); 46010 } 46011 } 46012 entry.mesh.geometry = newGeom; 46013 if (entry.pickingMesh) { 46014 entry.pickingMesh.geometry = newGeom; 46015 } 46016 } 46017 function registerColor(colorInput) { 46018 if (colorCount >= COLOR_PALETTE_CAPACITY) { 46019 throw new Error(`Color palette is full (capacity ${COLOR_PALETTE_CAPACITY}).`); 46020 } 46021 const color3 = normalizeColorInput(colorInput); 46022 colorMatrices[colorCount].copy(color3); 46023 return colorCount++; 46024 } 46025 function addInstance(styleId, shapeId, instanceOptions = {}) { 46026 const group = getActiveGroup(); 46027 getStyle(group, styleId); 46028 ensureStyleIsActiveForInstances(group, styleId); 46029 const shapeMap = getOrCreateShapeInstanceMap(group, shapeId); 46030 const position = instanceOptions.position ?? new Vector3(); 46031 const orientationIndex = normalizeOrientationIndex(group, instanceOptions.orientationIndex); 46032 const colorIndex = normalizeColorIndex(instanceOptions.colorIndex); 46033 const highlight = instanceOptions.highlight ?? 0; 46034 const id = group.nextInstanceId; 46035 group.nextInstanceId += 1; 46036 shapeMap.set(id, { 46037 position, 46038 orientationIndex, 46039 colorIndex, 46040 highlight 46041 }); 46042 syncShapeInstances(group, shapeId); 46043 return id; 46044 } 46045 function removeInstance(styleId, shapeId, instanceId) { 46046 const group = getActiveGroup(); 46047 const shapeMap = group.instancesByShape.get(shapeId); 46048 if (!shapeMap) { 46049 return false; 46050 } 46051 const removed = shapeMap.delete(instanceId); 46052 if (removed) { 46053 syncShapeInstances(group, shapeId); 46054 } 46055 return removed; 46056 } 46057 function removeAllInstances(styleId, shapeId) { 46058 const group = getActiveGroup(); 46059 group.instancesByShape.delete(shapeId); 46060 syncShapeInstances(group, shapeId); 46061 } 46062 function replaceShapeInstances(styleId, shapeId, instances) { 46063 const group = getActiveGroup(); 46064 getStyle(group, styleId); 46065 ensureStyleIsActiveForInstances(group, styleId); 46066 const shapeMap = /* @__PURE__ */ new Map(); 46067 const assignedIds = new Array(instances.length); 46068 for (let i = 0; i < instances.length; i += 1) { 46069 const instanceOptions = instances[i]; 46070 const id = group.nextInstanceId; 46071 group.nextInstanceId += 1; 46072 shapeMap.set(id, { 46073 position: instanceOptions.position ?? new Vector3(), 46074 orientationIndex: normalizeOrientationIndex(group, instanceOptions.orientationIndex), 46075 colorIndex: normalizeColorIndex(instanceOptions.colorIndex), 46076 highlight: instanceOptions.highlight ?? 0 46077 }); 46078 assignedIds[i] = id; 46079 } 46080 group.instancesByShape.set(shapeId, shapeMap); 46081 syncShapeInstances(group, shapeId); 46082 return assignedIds; 46083 } 46084 function clearActiveInstances() { 46085 const group = getActiveGroup(); 46086 clearGroupInstances(group); 46087 setGroupMeshesCount(group, 0); 46088 } 46089 function createMaterialForGroup(group) { 46090 const orientationUniform = uniformArray2(group.orientations); 46091 const orientationIndexNode = attribute2("orientationIndex", "float"); 46092 const instanceTranslationNode = attribute2("instanceTranslation", "vec3");
46093 const colorIndexNode = attribute2("colorIndex", "float"); 46094 const highlightIntensityNode = attribute2("highlightIntensity", "float"); 46095 const rotatedPositionNode = Fn2(() => { 46096 const orientationMat = orientationUniform.element(orientationIndexNode.toInt()); 46097 return orientationMat.mul(vec42(positionLocal2, 1)).xyz.add(instanceTranslationNode); 46098 })(); 46099 const roundedColorIndexNode = floor2(colorIndexNode.add(float2(0.5))); 46100 const indexedColorNode = colorPalette.element(roundedColorIndexNode.toInt()); 46101 const material = new MeshLambertNodeMaterial({ 46102 flatShading: true 46103 }); 46104 material.positionNode = rotatedPositionNode; 46105 material.colorNode = indexedColorNode; 46106 material.emissiveNode = vec42(1, 1, 1, 1).xyz.mul(highlightIntensityNode); 46107 const pickingIdNode = floor2( 46108 attribute2("pickingId", "float").add(float2(0.5)) 46109 ); 46110 const pickingColorNode = vec32( 46111 mod2(pickingIdNode, float2(256)).div(255), 46112 mod2(floor2(pickingIdNode.div(float2(256))), float2(256)).div(255), 46113 floor2(pickingIdNode.div(float2(65536))).div(255) 46114 ); 46115 const pickingMaterial = new MeshBasicNodeMaterial({ toneMapped: false }); 46116 pickingMaterial.positionNode = rotatedPositionNode; 46117 pickingMaterial.colorNode = pickingColorNode; 46118 const outlineMaterial = new MeshBasicNodeMaterial({ toneMapped: false }); 46119 outlineMaterial.positionNode = rotatedPositionNode; 46120 outlineMaterial.colorNode = vec32(0, 0, 0); 46121 return { material, pickingMaterial, outlineMaterial }; 46122 } 46123 function createShapeEntry(slotId, meshGeometry, outlineGeometry, material, pickingMaterial, outlineMaterial) { 46124 const mesh = new InstancedMesh(meshGeometry, material, INITIAL_SHAPE_CAPACITY); 46125 const orientBuffer = new Float32Array(INITIAL_SHAPE_CAPACITY); 46126 const translationBuffer = new Float32Array(INITIAL_SHAPE_CAPACITY * 3); 46127 const colorIndexBuffer = new Float32Array(INITIAL_SHAPE_CAPACITY); 46128 const highlightBuffer = new Float32Array(INITIAL_SHAPE_CAPACITY); 46129 const pickingIdBuffer = new Float32Array(INITIAL_SHAPE_CAPACITY); 46130 attachAttributes(mesh.geometry, orientBuffer, translationBuffer, colorIndexBuffer, highlightBuffer, pickingIdBuffer); 46131 initializeIdentityMatrices(mesh, INITIAL_SHAPE_CAPACITY); 46132 mesh.count = 0; 46133 mesh.frustumCulled = false; 46134 const pickingMesh = new InstancedMesh(meshGeometry, pickingMaterial, INITIAL_SHAPE_CAPACITY); 46135 initializeIdentityMatrices(pickingMesh, INITIAL_SHAPE_CAPACITY); 46136 pickingMesh.count = 0; 46137 pickingMesh.frustumCulled = false; 46138 const outlineMesh = outlineGeometry ? makeOutlineMesh(outlineGeometry, outlineMaterial, INITIAL_SHAPE_CAPACITY, orientBuffer, translationBuffer, highlightBuffer, pickingIdBuffer) : null; 46139 return { 46140 slotId, 46141 capacity: INITIAL_SHAPE_CAPACITY, 46142 mesh, 46143 pickingMesh, 46144 outlineMesh, 46145 orientBuffer, 46146 translationBuffer, 46147 colorIndexBuffer, 46148 highlightBuffer, 46149 pickingIdBuffer 46150 }; 46151 } 46152 function makeOutlineMesh(outlineGeometry, outlineMaterial, capacity, orientBuffer, translationBuffer, highlightBuffer, pickingIdBuffer) { 46153 outlineGeometry.setAttribute("orientationIndex", new InstancedBufferAttribute(orientBuffer, 1)); 46154 outlineGeometry.setAttribute("instanceTranslation", new InstancedBufferAttribute(translationBuffer, 3)); 46155 outlineGeometry.setAttribute("highlightIntensity", new InstancedBufferAttribute(highlightBuffer, 1)); 46156 outlineGeometry.setAttribute("pickingId", new InstancedBufferAttribute(pickingIdBuffer, 1)); 46157 const outlineMesh = new InstancedMesh(outlineGeometry, outlineMaterial, capacity); 46158 outlineMesh.isLineSegments = true; 46159 initializeIdentityMatrices(outlineMesh, capacity); 46160 outlineMesh.count = 0; 46161 outlineMesh.frustumCulled = false; 46162 outlineMesh.visible = false; 46163 return outlineMesh; 46164 } 46165 function ensureGroupGpu(group) { 46166 if (group.gpu) { 46167 return; 46168 } 46169 const { material, pickingMaterial, outlineMaterial } = createMaterialForGroup(group); 46170 const cachedGeometries = /* @__PURE__ */ new Map(); 46171 for (const slotId of group.slots) { 46172 const slotCache = /* @__PURE__ */ new Map(); 46173 for (const [styleId, style2] of group.styles) { 46174 if (style2.geometries.has(slotId)) {
46175 slotCache.set(styleId, style2.geometries.get(slotId).clone()); 46176 } 46177 } 46178 cachedGeometries.set(slotId, slotCache); 46179 } 46180 const outlineGeometries = group.pendingOutlineGeometries ?? /* @__PURE__ */ new Map(); 46181 group.pendingOutlineGeometries = void 0; 46182 const shapeEntries = /* @__PURE__ */ new Map(); 46183 for (const slotId of group.slots) { 46184 const slotCache = cachedGeometries.get(slotId); 46185 if (!slotCache) continue; 46186 const geom = (group.activeStyleId && slotCache.get(group.activeStyleId)) ?? slotCache.values().next().value; 46187 if (geom) { 46188 const outlineGeom = outlineGeometries.get(slotId) ?? null; 46189 shapeEntries.set(slotId, createShapeEntry(slotId, geom, outlineGeom, material, pickingMaterial, outlineMaterial)); 46190 } 46191 } 46192 const pickingScene = new Scene(); 46193 const pickingOriginGroup = new Group(); 46194 pickingOriginGroup.matrixAutoUpdate = false; 46195 pickingScene.add(pickingOriginGroup); 46196 const pickingTarget = new RenderTarget(1, 1, { 46197 type: UnsignedByteType, 46198 format: RGBAFormat 46199 }); 46200 group.gpu = { material, pickingMaterial, outlineMaterial, shapeEntries, cachedGeometries, outlineGeometries, pickingScene, pickingOriginGroup, pickingTarget }; 46201 } 46202 function attachOutlineMeshToEntry(group, entry, slotId) { 46203 const outlineGeom = group.gpu.outlineGeometries.get(slotId); 46204 if (!outlineGeom) return; 46205 const outlineMesh = makeOutlineMesh( 46206 outlineGeom, 46207 group.gpu.outlineMaterial, 46208 entry.capacity, 46209 entry.orientBuffer, 46210 entry.translationBuffer, 46211 entry.highlightBuffer, 46212 entry.pickingIdBuffer 46213 ); 46214 outlineMesh.count = entry.mesh.count; 46215 entry.outlineMesh = outlineMesh; 46216 if (entry.mesh.parent === originGroup) { 46217 originGroup.add(outlineMesh); 46218 } 46219 } 46220 function addGroupMeshesToScene(group) { 46221 if (!group.gpu) { 46222 return; 46223 } 46224 for (const entry of group.gpu.shapeEntries.values()) { 46225 if (entry.mesh.parent !== originGroup) { 46226 originGroup.add(entry.mesh); 46227 } 46228 if (entry.outlineMesh && entry.outlineMesh.parent !== originGroup) { 46229 originGroup.add(entry.outlineMesh); 46230 } 46231 if (entry.pickingMesh && entry.pickingMesh.parent !== group.gpu.pickingOriginGroup) { 46232 group.gpu.pickingOriginGroup.add(entry.pickingMesh); 46233 } 46234 } 46235 } 46236 function setGroupMeshesCount(group, count) { 46237 if (!group || !group.gpu) { 46238 return; 46239 } 46240 for (const entry of group.gpu.shapeEntries.values()) { 46241 entry.mesh.count = count; 46242 if (entry.pickingMesh) { 46243 entry.pickingMesh.count = count; 46244 } 46245 if (entry.outlineMesh) { 46246 entry.outlineMesh.count = count; 46247 } 46248 } 46249 } 46250 function clearGroupInstances(group) { 46251 if (!group) { 46252 return; 46253 } 46254 group.instancesByShape.clear(); 46255 } 46256 function syncShapeInstances(group, slotId) { 46257 if (!group.gpu) { 46258 return; 46259 } 46260 const entry = group.gpu.shapeEntries.get(slotId); 46261 if (!entry) { 46262 throw new Error(`Shape slot '${slotId}' is not registered for active group '${group.id}'.`); 46263 } 46264 const shapeMap = group.instancesByShape.get(slotId); 46265 const instances = shapeMap ? Array.from(shapeMap.entries()) : []; 46266 ensureShapeCapacity(group, slotId, instances.length); 46267 const currentEntry = group.gpu.shapeEntries.get(slotId); 46268 currentEntry.mesh.count = instances.length; 46269 if (currentEntry.pickingMesh) { 46270 currentEntry.pickingMesh.count = instances.length; 46271 } 46272 if (currentEntry.outlineMesh) { 46273 currentEntry.outlineMesh.count = instances.length; 46274 } 46275 for (let i = 0; i < instances.length; i += 1) { 46276 const [instanceId, { position, orientationIndex, colorIndex, highlight = 0 }] = instances[i]; 46277 currentEntry.orientBuffer[i] = orientationIndex; 46278 const base = i * 3; 46279 currentEntry.translationBuffer[base] = position.x; 46280 currentEntry.translationBuffer[base + 1] = position.y; 46281 currentEntry.translationBuffer[base + 2] = position.z; 46282 currentEntry.colorIndexBuffer[i] = colorIndex; 46283 currentEntry.highlightBuffer[i] = highlight; 46284 currentEntry.pickingIdBuffer[i] = instanceId; 46285 } 46286 const geom = currentEntry.mesh.geometry; 46287 geom.getAttribute("orientationIndex").needsUpdate = true; 46288 geom.getAttribute("instanceTranslation").needsUpdate = true; 46289 geom.getAttribute("colorIndex").needsUpdate = true; 46290 geom.getAttribute("highlightIntensity").needsUpdate = true; 46291 geom.getAttribute("pickingId").needsUpdate = true; 46292 if (currentEntry.outlineMesh) { 46293 const outlineGeom = currentEntry.outlineMesh.geometry; 46294 outlineGeom.getAttribute("orientationIndex").needsUpdate = true; 46295 outlineGeom.getAttribute("instanceTranslation").needsUpdate = true; 46296 outlineGeom.getAttribute("highlightIntensity").needsUpdate = true; 46297 outlineGeom.getAttribute("pickingId").needsUpdate = true; 46298 } 46299 } 46300 function ensureShapeCapacity(group, key, needed) { 46301 const entry = group.gpu.shapeEntries.get(key); 46302 if (needed <= entry.capacity) { 46303 return; 46304 } 46305 const expandedCapacity = Math.max(needed, entry.capacity * 2); 46306 const nextOrient = new Float32Array(expandedCapacity); 46307 const nextTranslation = new Float32Array(expandedCapacity * 3); 46308 const nextColor = new Float32Array(expandedCapacity); 46309 const nextHighlight = new Float32Array(expandedCapacity); 46310 const nextPickingId = new Float32Array(expandedCapacity); 46311 nextOrient.set(entry.orientBuffer); 46312 nextTranslation.set(entry.translationBuffer); 46313 nextColor.set(entry.colorIndexBuffer); 46314 nextHighlight.set(entry.highlightBuffer); 46315 nextPickingId.set(entry.pickingIdBuffer); 46316 const previousMesh = entry.mesh; 46317 const previousGeometry = previousMesh.geometry; 46318 const activeStyle = group.styles.get(group.activeStyleId); 46319 const sourceGeom = activeStyle ? activeStyle.geometries.get(entry.slotId) : null; 46320 const nextGeometry = sourceGeom ? sourceGeom.clone() : previousGeometry.clone(); 46321 attachAttributes(nextGeometry, nextOrient, nextTranslation, nextColor, nextHighlight, nextPickingId); 46322 const slotCache = group.gpu.cachedGeometries.get(entry.slotId); 46323 if (slotCache && group.activeStyleId) {
46324 slotCache.set(group.activeStyleId, nextGeometry); 46325 } 46326 const nextMesh = new InstancedMesh(nextGeometry, group.gpu.material, expandedCapacity); 46327 initializeIdentityMatrices(nextMesh, expandedCapacity); 46328 nextMesh.count = previousMesh.count; 46329 nextMesh.frustumCulled = false; 46330 if (previousMesh.parent === originGroup) { 46331 originGroup.remove(previousMesh); 46332 originGroup.add(nextMesh); 46333 } 46334 const nextPickingMesh = new InstancedMesh(nextGeometry, group.gpu.pickingMaterial, expandedCapacity); 46335 initializeIdentityMatrices(nextPickingMesh, expandedCapacity); 46336 nextPickingMesh.count = previousMesh.count; 46337 nextPickingMesh.frustumCulled = false; 46338 const previousPickingMesh = entry.pickingMesh; 46339 if (previousPickingMesh && previousPickingMesh.parent === group.gpu.pickingOriginGroup) { 46340 group.gpu.pickingOriginGroup.remove(previousPickingMesh); 46341 group.gpu.pickingOriginGroup.add(nextPickingMesh); 46342 } 46343 let nextOutlineMesh = null; 46344 const previousOutlineMesh = entry.outlineMesh; 46345 if (previousOutlineMesh) { 46346 const sourceOutlineGeom = group.gpu.outlineGeometries.get(entry.slotId); 46347 const nextOutlineGeometry = sourceOutlineGeom ? sourceOutlineGeom.clone() : previousOutlineMesh.geometry.clone(); 46348 nextOutlineMesh = makeOutlineMesh( 46349 nextOutlineGeometry, 46350 group.gpu.outlineMaterial, 46351 expandedCapacity, 46352 nextOrient, 46353 nextTranslation, 46354 nextHighlight, 46355 nextPickingId 46356 ); 46357 nextOutlineMesh.count = previousOutlineMesh.count; 46358 nextOutlineMesh.visible = previousOutlineMesh.visible; 46359 if (previousOutlineMesh.parent === originGroup) { 46360 originGroup.remove(previousOutlineMesh); 46361 originGroup.add(nextOutlineMesh); 46362 } 46363 const previousOutlineGeometry = previousOutlineMesh.geometry; 46364 requestAnimationFrame(() => previousOutlineGeometry.dispose()); 46365 } 46366 requestAnimationFrame(() => previousGeometry.dispose()); 46367 group.gpu.shapeEntries.set(key, { 46368 ...entry, 46369 capacity: expandedCapacity, 46370 mesh: nextMesh, 46371 pickingMesh: nextPickingMesh, 46372 outlineMesh: nextOutlineMesh, 46373 orientBuffer: nextOrient, 46374 translationBuffer: nextTranslation, 46375 colorIndexBuffer: nextColor, 46376 highlightBuffer: nextHighlight, 46377 pickingIdBuffer: nextPickingId 46378 }); 46379 } 46380 function attachAttributes(geometry, orientBuffer, translationBuffer, colorIndexBuffer, highlightBuffer, pickingIdBuffer) { 46381 geometry.setAttribute("orientationIndex", new InstancedBufferAttribute(orientBuffer, 1)); 46382 geometry.setAttribute("instanceTranslation", new InstancedBufferAttribute(translationBuffer, 3)); 46383 geometry.setAttribute("colorIndex", new InstancedBufferAttribute(colorIndexBuffer, 1)); 46384 geometry.setAttribute("highlightIntensity", new InstancedBufferAttribute(highlightBuffer, 1)); 46385 geometry.setAttribute("pickingId", new InstancedBufferAttribute(pickingIdBuffer, 1)); 46386 } 46387 function initializeIdentityMatrices(mesh, capacity) { 46388 const identity = new Matrix4(); 46389 for (let i = 0; i < capacity; i += 1) { 46390 mesh.setMatrixAt(i, identity); 46391 } 46392 mesh.instanceMatrix.needsUpdate = true; 46393 } 46394 function disposeGroupGpu(group) { 46395 if (!group.gpu) { 46396 return; 46397 } 46398 for (const entry of group.gpu.shapeEntries.values()) { 46399 if (entry.mesh.parent === originGroup) { 46400 originGroup.remove(entry.mesh); 46401 } 46402 if (entry.pickingMesh && entry.pickingMesh.parent === group.gpu.pickingOriginGroup) { 46403 group.gpu.pickingOriginGroup.remove(entry.pickingMesh); 46404 } 46405 if (entry.outlineMesh) { 46406 if (entry.outlineMesh.parent === originGroup) { 46407 originGroup.remove(entry.outlineMesh); 46408 } 46409 entry.outlineMesh.geometry.dispose(); 46410 } 46411 } 46412 for (const slotCache of group.gpu.cachedGeometries.values()) { 46413 for (const geom of slotCache.values()) { 46414 geom.dispose(); 46415 } 46416 } 46417 group.gpu.material.dispose(); 46418 group.gpu.pickingMaterial.dispose(); 46419 group.gpu.outlineMaterial.dispose(); 46420 group.gpu.pickingTarget.dispose(); 46421 group.gpu = null; 46422 } 46423 function syncAllInstancesForGroup(group) { 46424 for (const slotId of group.instancesByShape.keys()) { 46425 syncShapeInstances(group, slotId); 46426 } 46427 } 46428 function getSymmetryGroup(groupId) { 46429 const group = symmetryGroups.get(groupId); 46430 if (!group) { 46431 throw new Error(`Unknown symmetry group '${groupId}'.`); 46432 } 46433 return group; 46434 } 46435 function getStyle(group, styleId) { 46436 const style2 = group.styles.get(styleId); 46437 if (!style2) { 46438 throw new Error(`Unknown style '${styleId}' in group '${group.id}'.`); 46439 } 46440 return style2; 46441 } 46442 function getGroupIds() { 46443 return [...symmetryGroups.keys()]; 46444 } 46445 function getActiveGroupId() { 46446 return activeGroupId; 46447 } 46448 function getActiveGroup() { 46449 if (activeGroupId === null) { 46450 throw new Error("No active symmetry group. Call switchSymmetryGroup() first."); 46451 } 46452 return getSymmetryGroup(activeGroupId); 46453 } 46454 function getOrCreateShapeInstanceMap(group, key) { 46455 let shapeMap = group.instancesByShape.get(key); 46456 if (!shapeMap) { 46457 shapeMap = /* @__PURE__ */ new Map(); 46458 group.instancesByShape.set(key, shapeMap); 46459 } 46460 return shapeMap; 46461 } 46462 function normalizeOrientationIndex(group, orientationIndex) { 46463 if (orientationIndex === void 0 || orientationIndex === null) { 46464 return 0; 46465 } 46466 if (!Number.isInteger(orientationIndex)) { 46467 throw new Error("orientationIndex must be an integer."); 46468 } 46469 if (orientationIndex < 0 || orientationIndex >= group.orientations.length) { 46470 throw new Error(`orientationIndex out of range for group '${group.id}'.`); 46471 } 46472 return orientationIndex; 46473 } 46474 function normalizeColorIndex(colorIndex) { 46475 if (colorIndex === void 0 || colorIndex === null) { 46476 return 0; 46477 } 46478 if (!Number.isInteger(colorIndex)) { 46479 throw new Error("colorIndex must be an integer."); 46480 } 46481 if (colorIndex < 0 || colorIndex >= colorCount) { 46482 throw new Error("colorIndex out of range."); 46483 } 46484 return colorIndex; 46485 } 46486 function normalizeColorInput(colorInput) { 46487 if (colorInput instanceof Vector3) { 46488 return colorInput.clone(); 46489 } 46490 if (colorInput instanceof Color) { 46491 return new Vector3(colorInput.r, colorInput.g, colorInput.b); 46492 } 46493 if (Array.isArray(colorInput) && colorInput.length === 3) { 46494 return new Vector3(colorInput[0], colorInput[1], colorInput[2]); 46495 } 46496 if (typeof colorInput === "object" && colorInput !== null && "r" in colorInput && "g" in colorInput && "b" in colorInput) { 46497 return new Vector3(colorInput.r, colorInput.g, colorInput.b); 46498 } 46499 if (typeof colorInput === "number" || typeof colorInput === "string") { 46500 const color3 = new Color(colorInput); 46501 return new Vector3(color3.r, color3.g, color3.b); 46502 } 46503 throw new Error("registerColor expects a Color, Vector3, [r,g,b], {r,g,b}
46503, number, or CSS color string."); 46504 } 46505 function ensureGroupHasActiveStyle(group) { 46506 if (group.activeStyleId !== null) { 46507 return; 46508 } 46509 const firstStyle = group.styles.keys().next(); 46510 group.activeStyleId = firstStyle.done ? null : firstStyle.value; 46511 } 46512 function ensureStyleIsActiveForInstances(group, styleId) { 46513 if (group.activeStyleId === null) { 46514 group.activeStyleId = styleId; 46515 return; 46516 } 46517 if (group.activeStyleId === styleId) { 46518 return; 46519 } 46520 group.activeStyleId = styleId; 46521 if (group.gpu) { 46522 swapGeometriesForStyle(group, styleId); 46523 } 46524 } 46525 function setInstanceHighlight(shapeId, instanceId, intensity = 1) { 46526 const group = getActiveGroup(); 46527 const shapeMap = group.instancesByShape.get(shapeId); 46528 if (!shapeMap || !shapeMap.has(instanceId)) { 46529 return false; 46530 } 46531 shapeMap.get(instanceId).highlight = intensity; 46532 syncShapeInstances(group, shapeId); 46533 return true; 46534 } 46535 function clearHighlights(shapeId) { 46536 const group = getActiveGroup(); 46537 if (shapeId !== void 0) { 46538 const shapeMap = group.instancesByShape.get(shapeId); 46539 if (shapeMap) { 46540 for (const inst of shapeMap.values()) { 46541 inst.highlight = 0; 46542 } 46543 syncShapeInstances(group, shapeId); 46544 } 46545 } else { 46546 for (const [sid, shapeMap] of group.instancesByShape) { 46547 for (const inst of shapeMap.values()) { 46548 inst.highlight = 0; 46549 } 46550 syncShapeInstances(group, sid); 46551 } 46552 } 46553 } 46554 function listShapeKeys(group, styleId) { 46555 const keys5 = []; 46556 for (const slotId of group.slots) { 46557 keys5.push({ styleId, shapeId: slotId }); 46558 } 46559 return keys5; 46560 } 46561 const PICK_SIZE = 3; 46562 const pickProjectionMatrix = new Matrix4(); 46563 async function pickAt(clientX, clientY, mainRenderer, camera) { 46564 if (activeGroupId === null) return null; 46565 const group = symmetryGroups.get(activeGroupId); 46566 if (!group || !group.gpu) return null; 46567 const { pickingScene, pickingOriginGroup: pickGroup, pickingTarget } = group.gpu; 46568 originGroup.updateMatrixWorld(true); 46569 pickGroup.matrix.copy(originGroup.matrixWorld); 46570 pickGroup.updateMatrixWorld(true); 46571 const pickingRenderer = await getPickingRenderer(); 46572 const canvas = mainRenderer.domElement; 46573 const w = canvas.width; 46574 const h = canvas.height; 46575 if (pickingRenderer.domElement.width !== PICK_SIZE || pickingRenderer.domElement.height !== PICK_SIZE) { 46576 pickingRenderer.setSize(PICK_SIZE, PICK_SIZE, false); 46577 } 46578 if (pickingTarget.width !== PICK_SIZE || pickingTarget.height !== PICK_SIZE) { 46579 pickingTarget.setSize(PICK_SIZE, PICK_SIZE); 46580 } 46581 const rect = canvas.getBoundingClientRect(); 46582 const scaleX = w / rect.width; 46583 const scaleY = h / rect.height; 46584 const pixelX = Math.floor((clientX - rect.left) * scaleX); 46585 const pixelY = Math.floor((clientY - rect.top) * scaleY); 46586 const ndcCenterX = (pixelX + 0.5) / w * 2 - 1; 46587 const ndcCenterY = 1 - (pixelY + 0.5) / h * 2; 46588 const scaleNdcX = w / PICK_SIZE; 46589 const scaleNdcY = h / PICK_SIZE; 46590 pickProjectionMatrix.set( 46591 scaleNdcX, 46592 0, 46593 0, 46594 -ndcCenterX * scaleNdcX, 46595 0, 46596 scaleNdcY, 46597 0, 46598 -ndcCenterY * scaleNdcY, 46599 0, 46600 0, 46601 1, 46602 0, 46603 0, 46604 0, 46605 0, 46606 1 46607 ); 46608 pickProjectionMatrix.multiply(camera.projectionMatrix); 46609 const savedProjectionMatrix = camera.projectionMatrix; 46610 camera.projectionMatrix = pickProjectionMatrix; 46611 pickingRenderer.setRenderTarget(pickingTarget); 46612 pickingRenderer.setClearColor(0, 0); 46613 pickingRenderer.clear(true, true, true); 46614 pickingRenderer.render(pickingScene, camera); 46615 pickingRenderer.setRenderTarget(null); 46616 camera.projectionMatrix = savedProjectionMatrix; 46617 const buffer3 = await pickingRenderer.readRenderTargetPixelsAsync(pickingTarget, 0, 0, PICK_SIZE, PICK_SIZE); 46618 const centerIdx = (Math.floor(PICK_SIZE / 2) * PICK_SIZE + Math.floor(PICK_SIZE / 2)) * 4; 46619 const pixelBuffer = buffer3.subarray(centerIdx, centerIdx + 4); 46620 if (pixelBuffer[3] === 0) return null; 46621 const instanceId = pixelBuffer[0] + pixelBuffer[1] * 256 + pixelBuffer[2] * 65536; 46622 if (instanceId === 0) return null; 46623 for (const [shapeId, shapeMap] of group.instancesByShape) { 46624 if (shapeMap.has(instanceId)) { 46625 return { shapeId, instanceId }; 46626 } 46627 } 46628 return null; 46629 } 46630 function setOrigin(vec33) { 46631 originGroup.position.copy(vec33); 46632 } 46633 return { 46634 registerSymmetryGroup, 46635 registerStyle, 46636 registerShape, 46637 registerOutline, 46638 registerColor, 46639 switchSymmetryGroup, 46640 switchStyle, 46641 setOutlinesVisible, 46642 setDiscardInactiveShaders, 46643 addInstance, 46644 removeInstance, 46645 removeAllInstances, 46646 replaceShapeInstances, 46647 clearActiveInstances, 46648 setInstanceHighlight, 46649 clearHighlights, 46650 getGroupIds, 46651 getActiveGroupId, 46652 getActiveGroup, 46653 listShapeKeys, 46654 pickAt, 46655 setOrigin, 46656 originGroup 46657 }; 46658} 46659
46660// src/viewer/symmetry-geometry.jsx 46661var STYLE_ID = "default"; 46662var hashOrientations = (orientations) => `g${orientations.length}:` + orientations.map((flat) => flat.join(",")).join(";"); 46663var groupKeyFor = (symmetryId, orientations) => symmetryId ? `id:${symmetryId}` : hashOrientations(orientations); 46664var SELECTED_HIGHLIGHT = 200 / 255; 46665var toMatrix4 = (flat) => new Matrix4().set(...flat); 46666var toVector3 = ([x, y, z]) => new Vector3(x, y, z); 46667var orientationIndexOf = (instance3) => instance3.orientation === null || !(instance3.orientation >= 0) ? 0 : instance3.orientation; 46668var SymmetryGeometry = (props) => { 46669 const { 46670 originGroupReady 46671 } = useWebXRClient(); 46672 return createComponent(Show, { 46673 get when() { 46674 return originGroupReady(); 46675 }, 46676 children: (parent) => createComponent(SymmetryGeometryImpl, mergeProps(props, { 46677 get parent() { 46678 return parent(); 46679 } 46680 })) 46681 }); 46682}; 46683var SymmetryGeometryImpl = (props) => { 46684 const { 46685 state: cameraState 46686 } = useCamera(); 46687 const renderer = createSymmetryRenderer(props.parent); 46688 const [activeGroupKey, setActiveGroupKey] = createSignal(null); 46689 const registeredGroupKeys = /* @__PURE__ */ new Set(); 46690 const registeredShapeIdsByGroup = /* @__PURE__ */ new Map(); 46691 const colorIndexByCss = /* @__PURE__ */ new Map(); 46692 let instanceRefById = /* @__PURE__ */ new Map(); 46693 let metadataByInstanceId = /* @__PURE__ */ new Map(); 46694 let orientationMatrices = []; 46695 const shapeCentroidById = /* @__PURE__ */ new Map(); 46696 let labelById = /* @__PURE__ */ new Map(); 46697 const colorIndexFor = (cssColor) => { 46698 let index = colorIndexByCss.get(cssColor); 46699 if (index === void 0) { 46700 index = renderer.registerColor(cssColor); 46701 colorIndexByCss.set(cssColor, index); 46702 } 46703 return index; 46704 }; 46705 createEffect(() => { 46706 const m = new Matrix4(); 46707 if (props.embedding) { 46708 m.set(...props.embedding); 46709 m.transpose(); 46710 } 46711 renderer.originGroup.matrix.copy(m); 46712 renderer.originGroup.matrixWorldNeedsUpdate = true; 46713 }); 46714 createEffect(() => { 46715 if (!props.orientations || props.orientations.length === 0) return; 46716 const key = groupKeyFor(props.symmetryId, props.orientations); 46717 if (key === untrack(activeGroupKey)) return; 46718 orientationMatrices = props.orientations.map(toMatrix4); 46719 if (!registeredGroupKeys.has(key)) { 46720 renderer.registerSymmetryGroup(key, orientationMatrices); 46721 renderer.registerStyle(key, STYLE_ID); 46722 registeredGroupKeys.add(key); 46723 } 46724 renderer.switchSymmetryGroup(key); 46725 setActiveGroupKey(key); 46726 }); 46727 createEffect(() => { 46728 const groupKey = activeGroupKey(); 46729 if (!groupKey) return; 46730 const shapes = props.shapes || {}; 46731 let registeredShapeIds = registeredShapeIdsByGroup.get(groupKey); 46732 if (!registeredShapeIds) { 46733 registeredShapeIds = /* @__PURE__ */ new Set(); 46734 registeredShapeIdsByGroup.set(groupKey, registeredShapeIds); 46735 } 46736 for (const [shapeId, shape] of Object.entries(shapes)) { 46737 if (!registeredShapeIds.has(shapeId)) { 46738 const geometry = buildShapeGeometry(shape, true); 46739 renderer.registerShape(groupKey, STYLE_ID, shapeId, geometry); 46740 renderer.registerOutline(groupKey, shapeId, buildOutlineGeometry(shape)); 46741 shapeCentroidById.set(shapeId, geometry.shapeCentroid); 46742 registeredShapeIds.add(shapeId); 46743 } 46744 } 46745 const nextInstanceRefById = /* @__PURE__ */ new Map(); 46746 const nextMetadataByInstanceId = /* @__PURE__ */ new Map(); 46747 const nextLabelById = /* @__PURE__ */ new Map(); 46748 for (const [shapeId, shape] of Object.entries(shapes)) { 46749 const centroid2 = shapeCentroidById.get(shapeId); 46750 const instanceOptionsList = shape.instances.map((instance3) => { 46751 const selected = untrack(() => !!instance3.selected); 46752 return { 46753 position: toVector3(instance3.position), 46754 // Both spellings of "no orientation" must become identity here; see 46755 // orientationIndexOf above for why a bare `< 0` test is not enough. 46756 orientationIndex: orientationIndexOf(instance3), 46757 colorIndex: colorIndexFor(instance3.color), 46758 // Set the initial highlight directly (rather than relying on a later toggle to catch 46759 // up) so an already-selected instance never flashes unhighlighted for a frame right 46760 // after a structural rebuild. The store's `selected` is the source of truth here. 46761 highlight: selected ? SELECTED_HIGHLIGHT : 0 46762 }; 46763 }); 46764 const instanceIds = renderer.replaceShapeInstances(STYLE_ID, shapeId, instanceOptionsList);
46765 shape.instances.forEach((instance3, i) => { 46766 const selected = untrack(() => !!instance3.selected); 46767 const instanceId = instanceIds[i]; 46768 nextInstanceRefById.set(instance3.id, { 46769 shapeId, 46770 instanceId 46771 }); 46772 nextMetadataByInstanceId.set(instanceId, { 46773 id: instance3.id, 46774 position: instance3.position, 46775 type: instance3.type, 46776 selected, 46777 label: instance3.label 46778 }); 46779 if (instance3.label) { 46780 const orientationIndex = orientationIndexOf(instance3); 46781 const worldPos = new Vector3(centroid2.x, centroid2.y, centroid2.z).applyMatrix4(orientationMatrices[orientationIndex]).add(toVector3(instance3.position)); 46782 let label3 = labelById.get(instance3.id); 46783 if (!label3) { 46784 const elem = document.createElement("div"); 46785 elem.className = "vzome-label"; 46786 elem.id = `vzome-label-${instance3.label}`; 46787 elem.textContent = instance3.label; 46788 label3 = new CSS2DObject(elem); 46789 renderer.originGroup.add(label3); 46790 } 46791 label3.position.copy(worldPos); 46792 nextLabelById.set(instance3.id, label3); 46793 labelById.delete(instance3.id); 46794 } 46795 }); 46796 } 46797 for (const shapeId of registeredShapeIds) { 46798 if (!(shapeId in shapes)) { 46799 renderer.removeAllInstances(STYLE_ID, shapeId); 46800 } 46801 } 46802 for (const staleLabel of labelById.values()) { 46803 renderer.originGroup.remove(staleLabel); 46804 } 46805 instanceRefById = nextInstanceRefById; 46806 labelById = nextLabelById; 46807 metadataByInstanceId = nextMetadataByInstanceId; 46808 }); 46809 const { 46810 setSelectionHighlighter 46811 } = useScene(); 46812 setSelectionHighlighter((shapeId, id, selected) => { 46813 const ref = instanceRefById.get(id); 46814 if (!ref) return; 46815 renderer.setInstanceHighlight(ref.shapeId, ref.instanceId, selected ? SELECTED_HIGHLIGHT : 0); 46816 const meta = metadataByInstanceId.get(ref.instanceId); 46817 if (meta) meta.selected = !!selected; 46818 }); 46819 onCleanup(() => setSelectionHighlighter(null)); 46820 createEffect(() => { 46821 if (!activeGroupKey()) return; 46822 renderer.setOutlinesVisible(!!props.polygons && !!cameraState.outlines); 46823 }); 46824 const three = useThree(); 46825 const [tool] = useInteractionTool(); 46826 const pick = (clientX, clientY) => renderer.pickAt(clientX, clientY, three.gl, three.camera); 46827 let draggingHit = null; 46828 let pendingGesture = null; 46829 const isLeftButton = (e) => e.button === 0; 46830 const pickingSuppressed = () => tool?.allowTrackball?.(); 46831 const onPointerDown = (e) => { 46832 if (!isLeftButton(e)) return; 46833 if (pickingSuppressed()) return; 46834 pendingGesture = (async () => { 46835 const hit = await pick(e.clientX, e.clientY); 46836 const meta = hit && metadataByInstanceId.get(hit.instanceId); 46837 if (!meta) return null; 46838 draggingHit = meta; 46839 tool?.onDragStart?.(e, meta.id, meta.position, meta.type, meta.selected); 46840 return meta; 46841 })(); 46842 }; 46843 const onPointerMove = (e) => { 46844 if (!draggingHit) return; 46845 tool?.onDrag?.(e, draggingHit.id, draggingHit.position, draggingHit.type, draggingHit.selected); 46846 }; 46847 const onPointerUp = async (e) => { 46848 if (!isLeftButton(e)) return; 46849 if (pickingSuppressed()) return; 46850 if (pendingGesture) await pendingGesture; 46851 pendingGesture = null; 46852 if (draggingHit) { 46853 const { 46854 id, 46855 position, 46856 type, 46857 selected, 46858 label: label3 46859 } = draggingHit; 46860 draggingHit = null; 46861 tool?.onDragEnd?.(e, id, position, type, selected, label3); 46862 } else { 46863 tool?.bkgdClick?.(); 46864 } 46865 }; 46866 const onContextMenu = async (e) => { 46867 if (pickingSuppressed()) return; 46868 const hit = await pick(e.clientX, e.clientY); 46869 if (!hit) return; 46870 const meta = metadataByInstanceId.get(hit.instanceId); 46871 if (!meta) return; 46872 e.preventDefault(); 46873 tool?.onContextMenu?.(meta.id, meta.position, meta.type, meta.selected, meta.label); 46874 }; 46875 const canvasEl = three.canvas; 46876 canvasEl.addEventListener("pointerdown", onPointerDown); 46877 canvasEl.addEventListener("pointermove", onPointerMove); 46878 canvasEl.addEventListener("pointerup", onPointerUp); 46879 canvasEl.addEventListener("contextmenu", onContextMenu); 46880 onCleanup(() => { 46881 canvasEl.removeEventListener("pointerdown", onPointerDown); 46882 canvasEl.removeEventListener("pointermove", onPointerMove); 46883 canvasEl.removeEventListener("pointerup", onPointerUp); 46884 canvasEl.removeEventListener("contextmenu", onContextMenu); 46885 }); 46886 return createComponent(CanvasExportBindings, {}); 46887}; 46888
46889// src/viewer/renderer-support.js 46890var STORAGE_KEY = "vzome.forceWebGLFallback"; 46891var URL_PARAM = "forceWebGL"; 46892var readStorage = () => { 46893 try { 46894 return globalThis.localStorage?.getItem(STORAGE_KEY) === "true"; 46895 } catch { 46896 return false; 46897 } 46898}; 46899var writeStorage = () => { 46900 try { 46901 globalThis.localStorage?.setItem(STORAGE_KEY, "true"); 46902 } catch { 46903 } 46904}; 46905var readUrlParam = () => { 46906 try { 46907 const value = new URLSearchParams(globalThis.location?.search).get(URL_PARAM); 46908 return value === "" || value === "1" || value === "true"; 46909 } catch { 46910 return false; 46911 } 46912}; 46913var isFallbackForced = () => { 46914 if (readUrlParam()) { 46915 writeStorage(); 46916 return true; 46917 } 46918 return readStorage(); 46919}; 46920var probePromise = null; 46921var canUseWebGPURenderer = () => { 46922 if (probePromise) 46923 return probePromise; 46924 probePromise = (async () => { 46925 if (isFallbackForced()) { 46926 console.info("[vZome] WebGL fallback forced (localStorage/URL); using classic WebGLRenderer."); 46927 return false; 46928 } 46929 let renderer; 46930 try { 46931 const canvas = document.createElement("canvas"); 46932 renderer = new WebGPURenderer({ canvas, antialias: true, alpha: true, forceWebGL: true }); 46933 await renderer.init(); 46934 return true; 46935 } catch (e) { 46936 console.warn("[vZome] WebGPURenderer init failed; using classic WebGLRenderer fallback.", e); 46937 return false; 46938 } finally { 46939 try { 46940 renderer?.dispose?.(); 46941 } catch { 46942 } 46943 } 46944 })(); 46945 return probePromise; 46946}; 46947
46948// src/viewer/scenecanvas.jsx 46949var SceneCanvas = (props) => { 46950 props = mergeProps({ 46951 rotateSpeed: 4.5, 46952 zoomSpeed: 3, 46953 panSpeed: 1 46954 }, props); 46955 const { 46956 scene 46957 } = useScene(); 46958 const [webgpuOk] = createResource(canUseWebGPURenderer); 46959 const useWebGL = () => webgpuOk() === false; 46960 const useSymmetry = () => props.symmetryRenderer && !useWebGL(); 46961 return createComponent(Show, { 46962 get when() { 46963 return webgpuOk() !== void 0; 46964 }, 46965 get children() { 46966 return createComponent(LightedTrackballCanvas, { 46967 get height() { 46968 return props.height; 46969 }, 46970 get width() { 46971 return props.width; 46972 }, 46973 get rotationOnly() { 46974 return props.rotationOnly; 46975 }, 46976 get rotateSpeed() { 46977 return props.rotateSpeed; 46978 }, 46979 get zoomSpeed() { 46980 return props.zoomSpeed; 46981 }, 46982 get panSpeed() { 46983 return props.panSpeed; 46984 }, 46985 get useWebGL() { 46986 return useWebGL(); 46987 }, 46988 get symmetryRenderer() { 46989 return useSymmetry(); 46990 }, 46991 get children() { 46992 return [createComponent(Show, { 46993 when: () => props.scene?.shapes, 46994 get children() { 46995 return memo(() => !!useSymmetry())() ? createComponent(SymmetryGeometry, { 46996 get embedding() { 46997 return scene?.embedding; 46998 }, 46999 get shapes() { 47000 return scene?.shapes; 47001 }, 47002 get orientations() { 47003 return scene?.orientations; 47004 }, 47005 get polygons() { 47006 return scene?.polygons; 47007 }, 47008 get symmetryId() { 47009 return scene?.symmetryId; 47010 } 47011 }) : createComponent(ShapedGeometry, { 47012 get embedding() { 47013 return scene?.embedding; 47014 }, 47015 get shapes() { 47016 return scene?.shapes; 47017 } 47018 }); 47019 } 47020 }), memo(() => props.children)]; 47021 } 47022 }); 47023 } 47024 }); 47025}; 47026
vendor: 489 bytes, lines 47027-47039
47027// node_modules/@solid-primitives/utils/dist/chunk/R5675YMU.js 47028var isClient3 = !isServer; 47029var isDev3 = isClient3 && !!DEV; 47030function chain3(callbacks) { 47031 return (...args) => { 47032 for (const callback of callbacks) 47033 callback && callback(...args); 47034 }; 47035} 47036var access3 = (v) => typeof v === "function" && !v.length ? v() : v; 47037var asArray3 = (value) => Array.isArray(value) ? value : value ? [value] : []; 47038var tryOnCleanup3 = isDev3 ? (fn) => getOwner() ? onCleanup(fn) : fn : onCleanup; 47039
vendor: 691 bytes, lines 47040-47059
47040// node_modules/@solid-primitives/event-listener/dist/index.js 47041function makeEventListener(target, type, handler, options) { 47042 target.addEventListener(type, handler, options); 47043 return tryOnCleanup3(target.removeEventListener.bind(target, type, handler, options)); 47044} 47045function createEventListener(targets, type, handler, options) { 47046 if (isServer) 47047 return; 47048 const attachListeners = () => { 47049 asArray3(access3(targets)).forEach((el) => { 47050 if (el) 47051 asArray3(access3(type)).forEach((type2) => makeEventListener(el, type2, handler, options)); 47052 }); 47053 }; 47054 if (typeof targets === "function") 47055 createEffect(attachListeners); 47056 else 47057 createRenderEffect(attachListeners); 47058} 47059
vendor: 2,713 bytes, lines 47060-47157
47060// node_modules/@solid-primitives/keyed/dist/index.js 47061var FALLBACK = Symbol("fallback"); 47062function dispose(list) { 47063 for (const o of list) 47064 o.dispose(); 47065} 47066function keyArray(items, keyFn, mapFn, options = {}) { 47067 if (isServer) { 47068 const itemsRef = items(); 47069 let s = []; 47070 if (itemsRef && itemsRef.length) { 47071 for (let i = 0, len = itemsRef.length; i < len; i++) 47072 s.push( 47073 mapFn( 47074 () => itemsRef[i], 47075 () => i 47076 ) 47077 ); 47078 } else if (options.fallback) 47079 s = [options.fallback()]; 47080 return () => s; 47081 } 47082 const prev = /* @__PURE__ */ new Map(); 47083 onCleanup(() => dispose(prev.values())); 47084 return () => { 47085 const list = items() || []; 47086 list[$TRACK]; 47087 return untrack(() => { 47088 if (!list.length) { 47089 dispose(prev.values()); 47090 prev.clear(); 47091 if (!options.fallback) 47092 return []; 47093 const fb2 = createRoot((dispose2) => { 47094 prev.set(FALLBACK, { dispose: dispose2 }); 47095 return options.fallback(); 47096 }); 47097 return [fb2]; 47098 } 47099 const result = new Array(list.length); 47100 const fb = prev.get(FALLBACK); 47101 if (!prev.size || fb) { 47102 fb?.dispose(); 47103 prev.delete(FALLBACK); 47104 for (let i = 0; i < list.length; i++) { 47105 const item = list[i]; 47106 const key = keyFn(item, i); 47107 addNewItem(result, item, i, key); 47108 } 47109 return result; 47110 } 47111 const prevKeys = new Set(prev.keys()); 47112 for (let i = 0; i < list.length; i++) { 47113 const item = list[i]; 47114 const key = keyFn(item, i); 47115 prevKeys.delete(key); 47116 const lookup = prev.get(key); 47117 if (lookup) { 47118 result[i] = lookup.mapped; 47119 lookup.setIndex?.(i); 47120 lookup.setItem(() => item); 47121 } else 47122 addNewItem(result, item, i, key); 47123 } 47124 for (const key of prevKeys) { 47125 prev.get(key)?.dispose(); 47126 prev.delete(key); 47127 } 47128 return result; 47129 }); 47130 }; 47131 function addNewItem(list, item, i, key) { 47132 createRoot((dispose2) => { 47133 const [getItem, setItem] = createSignal(item); 47134 const save = { setItem, dispose: dispose2 }; 47135 if (mapFn.length > 1) { 47136 const [index, setIndex] = createSignal(i); 47137 save.setIndex = setIndex; 47138 save.mapped = mapFn(getItem, index); 47139 } else 47140 save.mapped = mapFn(getItem); 47141 prev.set(key, save); 47142 list[i] = save.mapped; 47143 }); 47144 } 47145} 47146function Key(props) { 47147 const { by } = props; 47148 return createMemo( 47149 keyArray( 47150 () => props.each, 47151 typeof by === "function" ? by : (v) => v[by], 47152 props.children, 47153 "fallback" in props ? { fallback: () => props.fallback } : void 0 47154 ) 47155 ); 47156} 47157
vendor: 544 bytes, lines 47158-47178
47158// node_modules/@solid-primitives/props/dist/index.js 47159var extractCSSregex = /((?:--)?(?:\w+-?)+)\s*:\s*([^;]*)/g; 47160function stringStyleToObject(style2) { 47161 const object = {}; 47162 let match; 47163 while (match = extractCSSregex.exec(style2)) { 47164 object[match[1]] = match[2]; 47165 } 47166 return object; 47167} 47168function combineStyle(a, b) { 47169 if (typeof a === "string") { 47170 if (typeof b === "string") 47171 return `${a};${b}`; 47172 a = stringStyleToObject(a); 47173 } else if (typeof b === "string") { 47174 b = stringStyleToObject(b); 47175 } 47176 return { ...a, ...b }; 47177} 47178
vendor: 109 bytes, lines 47179-47183
47179// node_modules/@solid-primitives/refs/dist/index.js 47180function mergeRefs(...refs) { 47181 return chain3(refs); 47182} 47183
vendor: 281 bytes, lines 47184-47189
47184// node_modules/@kobalte/utils/node_modules/@solid-primitives/utils/dist/chunk/R5675YMU.js 47185var access4 = (v) => typeof v === "function" && !v.length ? v() : v; 47186function accessWith4(valueOrFn, ...args) { 47187 return typeof valueOrFn === "function" ? valueOrFn(...args) : valueOrFn; 47188} 47189
vendor: 15,888 bytes, lines 47190-47705
47190// node_modules/@kobalte/utils/dist/index.js 47191function addItemToArray(array3, item, index = -1) { 47192 if (!(index in array3)) { 47193 return [...array3, item]; 47194 } 47195 return [...array3.slice(0, index), item, ...array3.slice(index)]; 47196} 47197function removeItemFromArray(array3, item) { 47198 const updatedArray = [...array3]; 47199 const index = updatedArray.indexOf(item); 47200 if (index !== -1) { 47201 updatedArray.splice(index, 1); 47202 } 47203 return updatedArray; 47204} 47205function isNumber(value) { 47206 return typeof value === "number"; 47207} 47208function isString(value) { 47209 return Object.prototype.toString.call(value) === "[object String]"; 47210} 47211function isFunction(value) { 47212 return typeof value === "function"; 47213} 47214function createGenerateId(baseId) { 47215 return (suffix) => `${baseId()}-${suffix}`; 47216} 47217function contains(parent, child) { 47218 if (!parent) { 47219 return false; 47220 } 47221 return parent === child || parent.contains(child); 47222} 47223function getActiveElement(node, activeDescendant = false) { 47224 const { activeElement } = getDocument(node); 47225 if (!activeElement?.nodeName) { 47226 return null; 47227 } 47228 if (isFrame(activeElement) && activeElement.contentDocument) { 47229 return getActiveElement( 47230 activeElement.contentDocument.body, 47231 activeDescendant 47232 ); 47233 } 47234 if (activeDescendant) { 47235 const id = activeElement.getAttribute("aria-activedescendant"); 47236 if (id) { 47237 const element3 = getDocument(activeElement).getElementById(id); 47238 if (element3) { 47239 return element3; 47240 } 47241 } 47242 } 47243 return activeElement; 47244} 47245function getWindow(node) { 47246 return getDocument(node).defaultView || window; 47247} 47248function getDocument(node) { 47249 return node ? node.ownerDocument || node : document; 47250} 47251function isFrame(element3) { 47252 return element3.tagName === "IFRAME"; 47253} 47254var EventKey = /* @__PURE__ */ ((EventKey2) => { 47255 EventKey2["Escape"] = "Escape"; 47256 EventKey2["Enter"] = "Enter"; 47257 EventKey2["Tab"] = "Tab"; 47258 EventKey2["Space"] = " "; 47259 EventKey2["ArrowDown"] = "ArrowDown"; 47260 EventKey2["ArrowLeft"] = "ArrowLeft"; 47261 EventKey2["ArrowRight"] = "ArrowRight"; 47262 EventKey2["ArrowUp"] = "ArrowUp"; 47263 EventKey2["End"] = "End"; 47264 EventKey2["Home"] = "Home"; 47265 EventKey2["PageDown"] = "PageDown"; 47266 EventKey2["PageUp"] = "PageUp"; 47267 return EventKey2; 47268})(EventKey || {}); 47269function testUserAgent(re) { 47270 if (typeof window === "undefined" || window.navigator == null) { 47271 return false; 47272 } 47273 return ( 47274 // @ts-ignore 47275 window.navigator.userAgentData?.brands.some( 47276 (brand) => re.test(brand.brand) 47277 ) || re.test(window.navigator.userAgent) 47278 ); 47279} 47280function testPlatform(re) { 47281 return typeof window !== "undefined" && window.navigator != null ? re.test( 47282 // @ts-ignore 47283 window.navigator.userAgentData?.platform || window.navigator.platform 47284 ) : false; 47285} 47286function isMac() { 47287 return testPlatform(/^Mac/i); 47288} 47289function isIPhone() { 47290 return testPlatform(/^iPhone/i); 47291} 47292function isIPad() { 47293 return testPlatform(/^iPad/i) || // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support. 47294 isMac() && navigator.maxTouchPoints > 1; 47295} 47296function isIOS() { 47297 return isIPhone() || isIPad(); 47298} 47299function isAppleDevice() { 47300 return isMac() || isIOS(); 47301} 47302function isWebKit() { 47303 return testUserAgent(/AppleWebKit/i) && !isChrome(); 47304} 47305function isChrome() { 47306 return testUserAgent(/Chrome/i); 47307} 47308function callHandler(event, handler) { 47309 if (handler) { 47310 if (isFunction(handler)) { 47311 handler(event); 47312 } else { 47313 handler[0](handler[1], event); 47314 } 47315 } 47316 return event?.defaultPrevented; 47317} 47318function composeEventHandlers(handlers) { 47319 return (event) => { 47320 for (const handler of handlers) { 47321 callHandler(event, handler); 47322 } 47323 }; 47324} 47325function isCtrlKey(e) { 47326 if (isMac()) { 47327 return e.metaKey && !e.ctrlKey; 47328 } 47329 return e.ctrlKey && !e.metaKey; 47330} 47331function focusWithoutScrolling(element3) { 47332 if (!element3) { 47333 return; 47334 } 47335 if (supportsPreventScroll()) { 47336 element3.focus({ preventScroll: true }); 47337 } else { 47338 const scrollableElements = getScrollableElements(element3); 47339 element3.focus(); 47340 restoreScrollPosition(scrollableElements); 47341 } 47342} 47343var supportsPreventScrollCached = null; 47344function supportsPreventScroll() { 47345 if (supportsPreventScrollCached == null) { 47346 supportsPreventScrollCached = false; 47347 try { 47348 const focusElem = document.createElement("div"); 47349 focusElem.focus({ 47350 get preventScroll() { 47351 supportsPreventScrollCached = true; 47352 return true; 47353 } 47354 }); 47355 } catch (e) { 47356 } 47357 } 47358 return supportsPreventScrollCached; 47359} 47360function getScrollableElements(element3) { 47361 let parent = element3.parentNode; 47362 const scrollableElements = []; 47363 const rootScrollingElement = document.scrollingElement || document.documentElement; 47364 while (parent instanceof HTMLElement && parent !== rootScrollingElement) { 47365 if (parent.offsetHeight < parent.scrollHeight || parent.offsetWidth < parent.scrollWidth) { 47366 scrollableElements.push({ 47367 element: parent, 47368 scrollTop: parent.scrollTop, 47369 scrollLeft: parent.scrollLeft 47370 }); 47371 } 47372 parent = parent.parentNode; 47373 } 47374 if (rootScrollingElement instanceof HTMLElement) { 47375 scrollableElements.push({ 47376 element: rootScrollingElement, 47377 scrollTop: rootScrollingElement.scrollTop, 47378 scrollLeft: rootScrollingElement.scrollLeft 47379 }); 47380 } 47381 return scrollableElements; 47382} 47383function restoreScrollPosition(scrollableElements) { 47384 for (const { element: element3, scrollTop, scrollLeft } of scrollableElements) { 47385 element3.scrollTop = scrollTop; 47386 element3.scrollLeft = scrollLeft; 47387 } 47388} 47389var focusableElements = [ 47390 "input:not([type='hidden']):not([disabled])", 47391 "select:not([disabled])", 47392 "textarea:not([disabled])", 47393 "button:not([disabled])", 47394 "a[href]", 47395 "area[href]", 47396 "[tabindex]", 47397 "iframe", 47398 "object", 47399 "embed", 47400 "audio[controls]", 47401 "video[controls]", 47402 "[contenteditable]:not([contenteditable='false'])" 47403]; 47404var tabbableElements = [ 47405 ...focusableElements, 47406 '[tabindex]:not([tabindex="-1"]):not([disabled])' 47407]; 47408var FOCUSABLE_ELEMENT_SELECTOR = `${focusableElements.join( 47409 ":not([hidden])," 47410)},[tabindex]:not([disabled]):not([hidden])`; 47411var TABBABLE_ELEMENT_SELECTOR = tabbableElements.join( 47412 ':not([hidden]):not([tabindex="-1"]),' 47413); 47414function getAllTabbableIn(container, includeContainer) { 47415 const elements = Array.from( 47416 container.querySelectorAll(FOCUSABLE_ELEMENT_SELECTOR) 47417 ); 47418 const tabbableElements2 = elements.filter(isTabbable); 47419 if (includeContainer && isTabbable(container)) { 47420 tabbableElements2.unshift(container); 47421 } 47422 tabbableElements2.forEach((element3, i) => { 47423 if (isFrame(element3) && element3.contentDocument) { 47424 const frameBody = element3.contentDocument.body; 47425 const allFrameTabbable = getAllTabbableIn(frameBody, false); 47426 tabbableElements2.splice(i, 1, ...allFrameTabbable); 47427 } 47428 }); 47429 return tabbableElements2; 47430} 47431function isTabbable(element3) { 47432 return isFocusable(element3) && !hasNegativeTabIndex(element3); 47433} 47434function isFocusable(element3) { 47435 return element3.matches(FOCUSABLE_ELEMENT_SELECTOR) && isElementVisible(element3); 47436} 47437function hasNegativeTabIndex(element3) { 47438 const tabIndex = Number.parseInt(element3.getAttribute("tabindex") || "0", 10); 47439 return tabIndex < 0; 47440} 47441function isElementVisible(element3, childElement) { 47442 return element3.nodeName !== "#comment" && isStyleVisible(element3) && isAttributeVisible(element3, childElement) && (!element3.parentElement || isElementVisible(element3.parentElement, element3)); 47443} 47444function isStyleVisible(element3) { 47445 if (!(element3 instanceof HTMLElement) && !(element3 instanceof SVGElement)) { 47446 return false; 47447 } 47448 const { display, visibility } = element3.style; 47449 let isVisible = display !== "none" && visibility !== "hidden" && visibility !== "collapse"; 47450 if (isVisible) { 47451 if (!element3.ownerDocument.defaultView) { 47452 return isVisible; 47453 } 47454 const { getComputedStyle: getComputedStyle3 } = element3.ownerDocument.defaultView; 47455 const { display: computedDisplay, visibility: computedVisibility } = getComputedStyle3(element3); 47456 isVisible = computedDisplay !== "none" && computedVisibility !== "hidden" && computedVisibility !== "collapse"; 47457 } 47458 return isVisible; 47459} 47460function isAttributeVisible(element3, childElement) { 47461 return !element3.hasAttribute("hidden") && (element3.nodeName === "DETAILS" && childElement && childElement.nodeName !== "SUMMARY" ? element3.hasAttribute("open") : true); 47462} 47463function isElementInScope(element3, scope) { 47464 return scope.some((node) => node.contains(element3)); 47465} 47466function getFocusableTreeWalker(root, opts, scope) { 47467 const selector = opts?.tabbable ? TABBABLE_ELEMENT_SELECTOR : FOCUSABLE_ELEMENT_SELECTOR; 47468 const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, { 47469 acceptNode(node) { 47470 if (opts?.from?.contains(node)) { 47471 return NodeFilter.FILTER_REJECT; 47472 } 47473 if (node.matches(selector) && isElementVisible(node) && (!scope || isElementInScope(node, scope)) && (!opts?.accept || opts.accept(node))) { 47474 return NodeFilter.FILTER_ACCEPT; 47475 } 47476 return NodeFilter.FILTER_SKIP; 47477 } 47478 }); 47479 if (opts?.from) { 47480 walker.currentNode = opts.from; 47481 } 47482 return walker; 47483} 47484function getScrollParent(node) { 47485 let parentNode = node; 47486 while (parentNode && !isScrollable(parentNode)) { 47487 parentNode = parentNode.parentElement; 47488 } 47489 return parentNode || document.scrollingElement || document.documentElement; 47490} 47491function isScrollable(node) { 47492 const style2 = window.getComputedStyle(node); 47493 return /(auto|scroll)/.test( 47494 style2.overflow + style2.overflowX + style2.overflowY 47495 ); 47496} 47497function noop5() { 47498 return; 47499} 47500function clamp7(value, min5 = Number.NEGATIVE_INFINITY, max5 = Number.POSITIVE_INFINITY) { 47501 return Math.min(Math.max(value, min5), max5); 47502} 47503function snapValueToStep(value, min5, max5, step3) { 47504 const remainder = (value - (Number.isNaN(min5) ? 0 : min5)) % step3; 47505 let snappedValue = Math.abs(remainder) * 2 >= step3 ? value + Math.sign(remainder) * (step3 - Math.abs(remainder)) : value - remainder; 47506 if (!Number.isNaN(min5)) { 47507 if (snappedValue < min5) { 47508 snappedValue = min5; 47509 } else if (!Number.isNaN(max5) && snappedValue > max5) { 47510 snappedValue = min5 + Math.floor((max5 - min5) / step3) * step3; 47511 } 47512 } else if (!Number.isNaN(max5) && snappedValue > max5) { 47513 snappedValue = Math.floor(max5 / step3) * step3; 47514 } 47515 const string3 = step3.toString(); 47516 const index = string3.indexOf("."); 47517 const precision = index >= 0 ? string3.length - index : 0; 47518 if (precision > 0) { 47519 const pow6 = 10 ** precision; 47520 snappedValue = Math.round(snappedValue * pow6) / pow6; 47521 } 47522 return snappedValue; 47523} 47524function getEventPoint(event) { 47525 return [event.clientX, event.clientY]; 47526} 47527function isPointInPolygon(point, polygon) { 47528 const [x, y] = point; 47529 let inside = false; 47530 const length3 = polygon.length; 47531 for (let l = length3, i = 0, j = l - 1; i < l; j = i++) { 47532 const [xi, yi] = polygon[i]; 47533 const [xj, yj] = polygon[j]; 47534 const [, vy] = polygon[j === 0 ? l - 1 : j - 1] || [0, 0]; 47535 const where = (yi - yj) * (x - xi) - (xi - xj) * (y - yi); 47536 if (yj < yi) { 47537 if (y >= yj && y < yi) { 47538 if (where === 0) 47539 return true; 47540 if (where > 0) { 47541 if (y === yj) { 47542 if (y > vy) { 47543 inside = !inside; 47544 } 47545 } else { 47546 inside = !inside; 47547 } 47548 } 47549 } 47550 } else if (yi < yj) { 47551 if (y > yi && y <= yj) { 47552 if (where === 0) 47553 return true; 47554 if (where < 0) { 47555 if (y === yj) { 47556 if (y < vy) { 47557 inside = !inside; 47558 } 47559 } else { 47560 inside = !inside; 47561 } 47562 } 47563 } 47564 } else if (y === yi && (x >= xj && x <= xi || x >= xi && x <= xj)) { 47565 return true; 47566 } 47567 } 47568 return inside; 47569} 47570function mergeDefaultProps(defaultProps, props) { 47571 return mergeProps(defaultProps, props); 47572} 47573var transitionsByElement = /* @__PURE__ */ new Map(); 47574var transitionCallbacks = /* @__PURE__ */ new Set(); 47575function setupGlobalEvents() { 47576 if (typeof window === "undefined" || document.body === null) { 47577 return; 47578 } 47579 const onTransitionStart = (e) => { 47580 if (!e.target) { 47581 return; 47582 } 47583 let transitions = transitionsByElement.get(e.target); 47584 if (!transitions) { 47585 transitions = /* @__PURE__ */ new Set(); 47586 transitionsByElement.set(e.target, transitions); 47587 e.target.addEventListener( 47588 "transitioncancel", 47589 onTransitionEnd 47590 ); 47591 } 47592 transitions.add(e.propertyName); 47593 }; 47594 const onTransitionEnd = (e) => { 47595 if (!e.target) { 47596 return; 47597 } 47598 const properties = transitionsByElement.get(e.target); 47599 if (!properties) { 47600 return; 47601 } 47602 properties.delete(e.propertyName); 47603 if (properties.size === 0) { 47604 e.target.removeEventListener( 47605 "transitioncancel", 47606 onTransitionEnd 47607 ); 47608 transitionsByElement.delete(e.target); 47609 } 47610 if (transitionsByElement.size === 0) { 47611 for (const cb of transitionCallbacks) { 47612 cb(); 47613 } 47614 transitionCallbacks.clear(); 47615 } 47616 }; 47617 document.body.addEventListener("transitionrun", onTransitionStart); 47618 document.body.addEventListener("transitionend", onTransitionEnd); 47619} 47620if (typeof document !== "undefined") { 47621 if (document.readyState !== "loading") { 47622 setupGlobalEvents(); 47623 } else { 47624 document.addEventListener("DOMContentLoaded", setupGlobalEvents); 47625 } 47626} 47627function scrollIntoView(scrollView, element3) { 47628 const offsetX = relativeOffset(scrollView, element3, "left"); 47629 const offsetY = relativeOffset(scrollView, element3, "top"); 47630 const width = element3.offsetWidth; 47631 const height = element3.offsetHeight; 47632 let x = scrollView.scrollLeft; 47633 let y = scrollView.scrollTop; 47634 const maxX = x + scrollView.offsetWidth; 47635 const maxY = y + scrollView.offsetHeight; 47636 if (offsetX <= x) { 47637 x = offsetX; 47638 } else if (offsetX + width > maxX) { 47639 x += offsetX + width - maxX; 47640 } 47641 if (offsetY <= y) { 47642 y = offsetY; 47643 } else if (offsetY + height > maxY) { 47644 y += offsetY + height - maxY; 47645 } 47646 scrollView.scrollLeft = x; 47647 scrollView.scrollTop = y; 47648} 47649function relativeOffset(ancestor, child, axis) { 47650 const prop = axis === "left" ? "offsetLeft" : "offsetTop"; 47651 let sum = 0; 47652 while (child.offsetParent) { 47653 sum += child[prop]; 47654 if (child.offsetParent === ancestor) { 47655 break; 47656 } 47657 if (child.offsetParent.contains(ancestor)) { 47658 sum -= ancestor[prop]; 47659 break; 47660 } 47661 child = child.offsetParent; 47662 } 47663 return sum; 47664} 47665function scrollIntoViewport(targetElement, opts) { 47666 if (document.contains(targetElement)) { 47667 const root = document.scrollingElement || document.documentElement; 47668 const isScrollPrevented = window.getComputedStyle(root).overflow === "hidden"; 47669 if (!isScrollPrevented) { 47670 const { left: originalLeft, top: originalTop } = targetElement.getBoundingClientRect(); 47671 targetElement?.scrollIntoView?.({ block: "nearest" }); 47672 const { left: newLeft, top: newTop } = targetElement.getBoundingClientRect(); 47673 if (Math.abs(originalLeft - newLeft) > 1 || Math.abs(originalTop - newTop) > 1) { 47674 opts?.containingElement?.scrollIntoView?.({ 47675 block: "center", 47676 inline: "center" 47677 }); 47678 targetElement.scrollIntoView?.({ block: "nearest" }); 47679 } 47680 } else { 47681 let scrollParent = getScrollParent(targetElement); 47682 while (targetElement && scrollParent && targetElement !== root && scrollParent !== root) { 47683 scrollIntoView( 47684 scrollParent, 47685 targetElement 47686 ); 47687 targetElement = scrollParent; 47688 scrollParent = getScrollParent(targetElement); 47689 } 47690 } 47691 } 47692} 47693var visuallyHiddenStyles = { 47694 border: "0", 47695 clip: "rect(0 0 0 0)", 47696 "clip-path": "inset(50%)", 47697 height: "1px", 47698 margin: "0 -1px -1px 0", 47699 overflow: "hidden", 47700 padding: "0", 47701 position: "absolute", 47702 width: "1px", 47703 "white-space": "nowrap" 47704}; 47705
vendor: 2,155 bytes, lines 47706-47782
47706// node_modules/@kobalte/core/dist/chunk/2YCOH52P.js 47707var DATA_TOP_LAYER_ATTR = "data-kb-top-layer"; 47708var originalBodyPointerEvents; 47709var hasDisabledBodyPointerEvents = false; 47710var layers = []; 47711function indexOf(node) { 47712 return layers.findIndex((layer) => layer.node === node); 47713} 47714function find(node) { 47715 return layers[indexOf(node)]; 47716} 47717function isTopMostLayer(node) { 47718 return layers.length > 0 && layers[layers.length - 1].node === node; 47719} 47720function getPointerBlockingLayers() { 47721 return layers.filter((layer) => layer.isPointerBlocking); 47722} 47723function getTopMostPointerBlockingLayer() { 47724 return [...getPointerBlockingLayers()].slice(-1)[0]; 47725} 47726function hasPointerBlockingLayer() { 47727 return getPointerBlockingLayers().length > 0; 47728} 47729function isBelowPointerBlockingLayer(node) { 47730 const highestBlockingIndex = indexOf(getTopMostPointerBlockingLayer()?.node); 47731 return indexOf(node) < highestBlockingIndex; 47732} 47733function addLayer(layer) { 47734 layers.push(layer); 47735} 47736function removeLayer(node) { 47737 const index = indexOf(node); 47738 if (index < 0) { 47739 return; 47740 } 47741 layers.splice(index, 1); 47742} 47743function assignPointerEventToLayers() { 47744 for (const { 47745 node 47746 } of layers) { 47747 node.style.pointerEvents = isBelowPointerBlockingLayer(node) ? "none" : "auto"; 47748 } 47749} 47750function disableBodyPointerEvents(node) { 47751 if (hasPointerBlockingLayer() && !hasDisabledBodyPointerEvents) { 47752 const ownerDocument = getDocument(node); 47753 originalBodyPointerEvents = document.body.style.pointerEvents; 47754 ownerDocument.body.style.pointerEvents = "none"; 47755 hasDisabledBodyPointerEvents = true; 47756 } 47757} 47758function restoreBodyPointerEvents(node) { 47759 if (hasPointerBlockingLayer()) { 47760 return; 47761 } 47762 const ownerDocument = getDocument(node); 47763 ownerDocument.body.style.pointerEvents = originalBodyPointerEvents; 47764 if (ownerDocument.body.style.length === 0) { 47765 ownerDocument.body.removeAttribute("style"); 47766 } 47767 hasDisabledBodyPointerEvents = false; 47768} 47769var layerStack = { 47770 layers, 47771 isTopMostLayer, 47772 hasPointerBlockingLayer, 47773 isBelowPointerBlockingLayer, 47774 addLayer, 47775 removeLayer, 47776 indexOf, 47777 find, 47778 assignPointerEventToLayers, 47779 disableBodyPointerEvents, 47780 restoreBodyPointerEvents 47781}; 47782
vendor: 6,388 bytes, lines 47783-47983
47783// node_modules/@kobalte/core/dist/chunk/G3KI2B4X.js 47784var AUTOFOCUS_ON_MOUNT_EVENT = "focusScope.autoFocusOnMount"; 47785var AUTOFOCUS_ON_UNMOUNT_EVENT = "focusScope.autoFocusOnUnmount"; 47786var EVENT_OPTIONS = { 47787 bubbles: false, 47788 cancelable: true 47789}; 47790var focusScopeStack = { 47791 /** A stack of focus scopes, with the active one at the top */ 47792 stack: [], 47793 active() { 47794 return this.stack[0]; 47795 }, 47796 add(scope) { 47797 if (scope !== this.active()) { 47798 this.active()?.pause(); 47799 } 47800 this.stack = removeItemFromArray(this.stack, scope); 47801 this.stack.unshift(scope); 47802 }, 47803 remove(scope) { 47804 this.stack = removeItemFromArray(this.stack, scope); 47805 this.active()?.resume(); 47806 } 47807}; 47808function createFocusScope(props, ref) { 47809 const [isPaused, setIsPaused] = createSignal(false); 47810 const focusScope = { 47811 pause() { 47812 setIsPaused(true); 47813 }, 47814 resume() { 47815 setIsPaused(false); 47816 } 47817 }; 47818 let lastFocusedElement = null; 47819 const onMountAutoFocus = (e) => props.onMountAutoFocus?.(e); 47820 const onUnmountAutoFocus = (e) => props.onUnmountAutoFocus?.(e); 47821 const ownerDocument = () => getDocument(ref()); 47822 const createSentinel = () => { 47823 const element3 = ownerDocument().createElement("span"); 47824 element3.setAttribute("data-focus-trap", ""); 47825 element3.tabIndex = 0; 47826 Object.assign(element3.style, visuallyHiddenStyles); 47827 return element3; 47828 }; 47829 const tabbables = () => { 47830 const container = ref(); 47831 if (!container) { 47832 return []; 47833 } 47834 return getAllTabbableIn(container, true).filter((el) => !el.hasAttribute("data-focus-trap")); 47835 }; 47836 const firstTabbable = () => { 47837 const items = tabbables(); 47838 return items.length > 0 ? items[0] : null; 47839 }; 47840 const lastTabbable = () => { 47841 const items = tabbables(); 47842 return items.length > 0 ? items[items.length - 1] : null; 47843 }; 47844 const shouldPreventUnmountAutoFocus = () => { 47845 const container = ref(); 47846 if (!container) { 47847 return false; 47848 } 47849 const activeElement = getActiveElement(container); 47850 if (!activeElement) { 47851 return false; 47852 } 47853 if (contains(container, activeElement)) { 47854 return false; 47855 } 47856 return isFocusable(activeElement); 47857 }; 47858 createEffect(() => { 47859 if (isServer) { 47860 return; 47861 } 47862 const container = ref(); 47863 if (!container) { 47864 return; 47865 } 47866 focusScopeStack.add(focusScope); 47867 const previouslyFocusedElement = getActiveElement(container); 47868 const hasFocusedCandidate = contains(container, previouslyFocusedElement); 47869 if (!hasFocusedCandidate) { 47870 const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT_EVENT, EVENT_OPTIONS); 47871 container.addEventListener(AUTOFOCUS_ON_MOUNT_EVENT, onMountAutoFocus); 47872 container.dispatchEvent(mountEvent); 47873 if (!mountEvent.defaultPrevented) { 47874 setTimeout(() => { 47875 focusWithoutScrolling(firstTabbable()); 47876 if (getActiveElement(container) === previouslyFocusedElement) { 47877 focusWithoutScrolling(container); 47878 } 47879 }, 0); 47880 } 47881 } 47882 onCleanup(() => { 47883 container.removeEventListener(AUTOFOCUS_ON_MOUNT_EVENT, onMountAutoFocus); 47884 setTimeout(() => { 47885 const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT_EVENT, EVENT_OPTIONS); 47886 if (shouldPreventUnmountAutoFocus()) { 47887 unmountEvent.preventDefault(); 47888 } 47889 container.addEventListener(AUTOFOCUS_ON_UNMOUNT_EVENT, onUnmountAutoFocus); 47890 container.dispatchEvent(unmountEvent); 47891 if (!unmountEvent.defaultPrevented) { 47892 focusWithoutScrolling(previouslyFocusedElement ?? ownerDocument().body); 47893 } 47894 container.removeEventListener(AUTOFOCUS_ON_UNMOUNT_EVENT, onUnmountAutoFocus); 47895 focusScopeStack.remove(focusScope); 47896 }, 0); 47897 }); 47898 }); 47899 createEffect(() => { 47900 if (isServer) { 47901 return; 47902 } 47903 const container = ref(); 47904 if (!container || !access4(props.trapFocus) || isPaused()) { 47905 return; 47906 } 47907 const onFocusIn = (event) => { 47908 const target = event.target; 47909 if (target?.closest(`[${DATA_TOP_LAYER_ATTR}]`)) { 47910 return; 47911 } 47912 if (contains(container, target)) { 47913 lastFocusedElement = target; 47914 } else { 47915 focusWithoutScrolling(lastFocusedElement); 47916 } 47917 }; 47918 const onFocusOut = (event) => { 47919 const relatedTarget = event.relatedTarget; 47920 const target = relatedTarget ?? getActiveElement(container); 47921 if (target?.closest(`[${DATA_TOP_LAYER_ATTR}]`)) { 47922 return; 47923 } 47924 if (!contains(container, target)) { 47925 focusWithoutScrolling(lastFocusedElement); 47926 } 47927 }; 47928 ownerDocument().addEventListener("focusin", onFocusIn); 47929 ownerDocument().addEventListener("focusout", onFocusOut); 47930 onCleanup(() => { 47931 ownerDocument().removeEventListener("focusin", onFocusIn); 47932 ownerDocument().removeEventListener("focusout", onFocusOut); 47933 }); 47934 }); 47935 createEffect(() => { 47936 if (isServer) { 47937 return; 47938 } 47939 const container = ref(); 47940 if (!container || !access4(props.trapFocus) || isPaused()) { 47941 return; 47942 } 47943 const startSentinel = createSentinel(); 47944 container.insertAdjacentElement("afterbegin", startSentinel); 47945 const endSentinel = createSentinel(); 47946 container.insertAdjacentElement("beforeend", endSentinel); 47947 function onFocus(event) { 47948 const first = firstTabbable(); 47949 const last = lastTabbable(); 47950 if (event.relatedTarget === first) { 47951 focusWithoutScrolling(last); 47952 } else { 47953 focusWithoutScrolling(first); 47954 } 47955 } 47956 startSentinel.addEventListener("focusin", onFocus); 47957 endSentinel.addEventListener("focusin", onFocus); 47958 const observer = new MutationObserver((mutations) => { 47959 for (const mutation of mutations) { 47960 if (mutation.previousSibling === endSentinel) { 47961 endSentinel.remove(); 47962 container.insertAdjacentElement("beforeend", endSentinel); 47963 } 47964 if (mutation.nextSibling === startSentinel) { 47965 startSentinel.remove(); 47966 container.insertAdjacentElement("afterbegin", startSentinel); 47967 } 47968 } 47969 }); 47970 observer.observe(container, { 47971 childList: true, 47972 subtree: false 47973 }); 47974 onCleanup(() => { 47975 startSentinel.removeEventListener("focusin", onFocus); 47976 endSentinel.removeEventListener("focusin", onFocus); 47977 startSentinel.remove(); 47978 endSentinel.remove(); 47979 observer.disconnect(); 47980 }); 47981 }); 47982} 47983
vendor: 108 bytes, lines 47984-47986
47984// node_modules/@kobalte/core/dist/chunk/YA7DCYMB.js 47985var DATA_LIVE_ANNOUNCER_ATTR = "data-live-announcer"; 47986
vendor: 3,837 bytes, lines 47987-48110
47987// node_modules/@kobalte/core/dist/chunk/R4V3527Z.js 47988function createHideOutside(props) { 47989 createEffect(() => { 47990 if (access4(props.isDisabled)) { 47991 return; 47992 } 47993 onCleanup(ariaHideOutside(access4(props.targets), access4(props.root))); 47994 }); 47995} 47996var refCountMap = /* @__PURE__ */ new WeakMap(); 47997var observerStack = []; 47998function ariaHideOutside(targets, root = document.body) { 47999 const visibleNodes = new Set(targets); 48000 const hiddenNodes = /* @__PURE__ */ new Set(); 48001 const walk = (root2) => { 48002 for (const element3 of root2.querySelectorAll( 48003 `[${DATA_LIVE_ANNOUNCER_ATTR}], [${DATA_TOP_LAYER_ATTR}]` 48004 )) { 48005 visibleNodes.add(element3); 48006 } 48007 const acceptNode = (node) => { 48008 if (visibleNodes.has(node) || node.parentElement && hiddenNodes.has(node.parentElement) && node.parentElement.getAttribute("role") !== "row") { 48009 return NodeFilter.FILTER_REJECT; 48010 } 48011 for (const target of visibleNodes) { 48012 if (node.contains(target)) { 48013 return NodeFilter.FILTER_SKIP; 48014 } 48015 } 48016 return NodeFilter.FILTER_ACCEPT; 48017 }; 48018 const walker = document.createTreeWalker(root2, NodeFilter.SHOW_ELEMENT, { 48019 acceptNode 48020 }); 48021 const acceptRoot = acceptNode(root2); 48022 if (acceptRoot === NodeFilter.FILTER_ACCEPT) { 48023 hide3(root2); 48024 } 48025 if (acceptRoot !== NodeFilter.FILTER_REJECT) { 48026 let node = walker.nextNode(); 48027 while (node != null) { 48028 hide3(node); 48029 node = walker.nextNode(); 48030 } 48031 } 48032 }; 48033 const hide3 = (node) => { 48034 const refCount = refCountMap.get(node) ?? 0; 48035 if (node.getAttribute("aria-hidden") === "true" && refCount === 0) { 48036 return; 48037 } 48038 if (refCount === 0) { 48039 setTimeout( 48040 () => requestAnimationFrame(() => node.setAttribute("aria-hidden", "true")) 48041 ); 48042 } 48043 hiddenNodes.add(node); 48044 refCountMap.set(node, refCount + 1); 48045 }; 48046 if (observerStack.length) { 48047 observerStack[observerStack.length - 1].disconnect(); 48048 } 48049 walk(root); 48050 const observer = new MutationObserver((changes) => { 48051 for (const change of changes) { 48052 if (change.type !== "childList" || change.addedNodes.length === 0) { 48053 continue; 48054 } 48055 if (![...visibleNodes, ...hiddenNodes].some( 48056 (node) => node.contains(change.target) 48057 )) { 48058 for (const node of change.removedNodes) { 48059 if (node instanceof Element) { 48060 visibleNodes.delete(node); 48061 hiddenNodes.delete(node); 48062 } 48063 } 48064 for (const node of change.addedNodes) { 48065 if ((node instanceof HTMLElement || node instanceof SVGElement) && (node.dataset.liveAnnouncer === "true" || node.dataset.reactAriaTopLayer === "true")) { 48066 visibleNodes.add(node); 48067 } else if (node instanceof Element) { 48068 walk(node); 48069 } 48070 } 48071 } 48072 } 48073 }); 48074 observer.observe(root, { childList: true, subtree: true }); 48075 const observerWrapper = { 48076 observe() { 48077 observer.observe(root, { childList: true, subtree: true }); 48078 }, 48079 disconnect() { 48080 observer.disconnect(); 48081 } 48082 }; 48083 observerStack.push(observerWrapper); 48084 return () => { 48085 observer.disconnect(); 48086 for (const node of hiddenNodes) { 48087 const count = refCountMap.get(node); 48088 if (count == null) { 48089 return; 48090 } 48091 if (count === 1) { 48092 setTimeout( 48093 () => requestAnimationFrame(() => node.removeAttribute("aria-hidden")) 48094 ); 48095 refCountMap.delete(node); 48096 } else { 48097 refCountMap.set(node, count - 1); 48098 } 48099 } 48100 if (observerWrapper === observerStack[observerStack.length - 1]) { 48101 observerStack.pop(); 48102 if (observerStack.length) { 48103 observerStack[observerStack.length - 1].observe(); 48104 } 48105 } else { 48106 observerStack.splice(observerStack.indexOf(observerWrapper), 1); 48107 } 48108 }; 48109} 48110
vendor: 562 bytes, lines 48111-48132
48111// node_modules/@kobalte/core/dist/chunk/QEMPLYZX.js 48112function createEscapeKeyDown(props) { 48113 const handleKeyDown = (event) => { 48114 if (event.key === EventKey.Escape) { 48115 props.onEscapeKeyDown?.(event); 48116 } 48117 }; 48118 createEffect(() => { 48119 if (isServer) { 48120 return; 48121 } 48122 if (access4(props.isDisabled)) { 48123 return; 48124 } 48125 const document2 = props.ownerDocument?.() ?? getDocument(); 48126 document2.addEventListener("keydown", handleKeyDown); 48127 onCleanup(() => { 48128 document2.removeEventListener("keydown", handleKeyDown); 48129 }); 48130 }); 48131} 48132
vendor: 3,167 bytes, lines 48133-48234
48133// node_modules/@kobalte/core/dist/chunk/XLBXJFYN.js 48134var POINTER_DOWN_OUTSIDE_EVENT = "interactOutside.pointerDownOutside"; 48135var FOCUS_OUTSIDE_EVENT = "interactOutside.focusOutside"; 48136function createInteractOutside(props, ref) { 48137 let pointerDownTimeoutId; 48138 let clickHandler = noop5; 48139 const ownerDocument = () => getDocument(ref()); 48140 const onPointerDownOutside = (e) => props.onPointerDownOutside?.(e); 48141 const onFocusOutside = (e) => props.onFocusOutside?.(e); 48142 const onInteractOutside = (e) => props.onInteractOutside?.(e); 48143 const isEventOutside = (e) => { 48144 const target = e.target; 48145 if (!(target instanceof Element)) { 48146 return false; 48147 } 48148 if (target.closest(`[${DATA_TOP_LAYER_ATTR}]`)) { 48149 return false; 48150 } 48151 if (!contains(ownerDocument(), target)) { 48152 return false; 48153 } 48154 if (contains(ref(), target)) { 48155 return false; 48156 } 48157 return !props.shouldExcludeElement?.(target); 48158 }; 48159 const onPointerDown = (e) => { 48160 function handler() { 48161 const container = ref(); 48162 const target = e.target; 48163 if (!container || !target || !isEventOutside(e)) { 48164 return; 48165 } 48166 const handler2 = composeEventHandlers([ 48167 onPointerDownOutside, 48168 onInteractOutside 48169 ]); 48170 target.addEventListener(POINTER_DOWN_OUTSIDE_EVENT, handler2, { 48171 once: true 48172 }); 48173 const pointerDownOutsideEvent = new CustomEvent( 48174 POINTER_DOWN_OUTSIDE_EVENT, 48175 { 48176 bubbles: false, 48177 cancelable: true, 48178 detail: { 48179 originalEvent: e, 48180 isContextMenu: e.button === 2 || isCtrlKey(e) && e.button === 0 48181 } 48182 } 48183 ); 48184 target.dispatchEvent(pointerDownOutsideEvent); 48185 } 48186 if (e.pointerType === "touch") { 48187 ownerDocument().removeEventListener("click", handler); 48188 clickHandler = handler; 48189 ownerDocument().addEventListener("click", handler, { once: true }); 48190 } else { 48191 handler(); 48192 } 48193 }; 48194 const onFocusIn = (e) => { 48195 const container = ref(); 48196 const target = e.target; 48197 if (!container || !target || !isEventOutside(e)) { 48198 return; 48199 } 48200 const handler = composeEventHandlers([ 48201 onFocusOutside, 48202 onInteractOutside 48203 ]); 48204 target.addEventListener(FOCUS_OUTSIDE_EVENT, handler, { once: true }); 48205 const focusOutsideEvent = new CustomEvent(FOCUS_OUTSIDE_EVENT, { 48206 bubbles: false, 48207 cancelable: true, 48208 detail: { 48209 originalEvent: e, 48210 isContextMenu: false 48211 } 48212 }); 48213 target.dispatchEvent(focusOutsideEvent); 48214 }; 48215 createEffect(() => { 48216 if (isServer) { 48217 return; 48218 } 48219 if (access4(props.isDisabled)) { 48220 return; 48221 } 48222 pointerDownTimeoutId = window.setTimeout(() => { 48223 ownerDocument().addEventListener("pointerdown", onPointerDown, true); 48224 }, 0); 48225 ownerDocument().addEventListener("focusin", onFocusIn, true); 48226 onCleanup(() => { 48227 window.clearTimeout(pointerDownTimeoutId); 48228 ownerDocument().removeEventListener("click", clickHandler); 48229 ownerDocument().removeEventListener("pointerdown", onPointerDown, true); 48230 ownerDocument().removeEventListener("focusin", onFocusIn, true); 48231 }); 48232 }); 48233} 48234
vendor: 436 bytes, lines 48235-48250
48235// node_modules/@kobalte/core/dist/chunk/6Y7B2NEO.js 48236function Polymorphic(props) { 48237 const [local, others] = splitProps(props, ["as"]); 48238 if (!local.as) { 48239 throw new Error("[kobalte]: Polymorphic is missing the required `as` prop."); 48240 } 48241 return ( 48242 // @ts-ignore: Props are valid but not worth calculating 48243 createComponent(Dynamic, mergeProps(others, { 48244 get component() { 48245 return local.as; 48246 } 48247 })) 48248 ); 48249} 48250
vendor: 3,648 bytes, lines 48251-48369
48251// node_modules/@kobalte/core/dist/chunk/WHII6HHI.js 48252var DismissableLayerContext = createContext(); 48253function useOptionalDismissableLayerContext() { 48254 return useContext(DismissableLayerContext); 48255} 48256function DismissableLayer(props) { 48257 let ref; 48258 const parentContext = useOptionalDismissableLayerContext(); 48259 const [local, others] = splitProps(props, ["ref", "disableOutsidePointerEvents", "excludedElements", "onEscapeKeyDown", "onPointerDownOutside", "onFocusOutside", "onInteractOutside", "onDismiss", "bypassTopMostLayerCheck"]); 48260 const nestedLayers = /* @__PURE__ */ new Set([]); 48261 const registerNestedLayer = (element3) => { 48262 nestedLayers.add(element3); 48263 const parentUnregister = parentContext?.registerNestedLayer(element3); 48264 return () => { 48265 nestedLayers.delete(element3); 48266 parentUnregister?.(); 48267 }; 48268 }; 48269 const shouldExcludeElement = (element3) => { 48270 if (!ref) { 48271 return false; 48272 } 48273 return local.excludedElements?.some((node) => contains(node(), element3)) || [...nestedLayers].some((layer) => contains(layer, element3)); 48274 }; 48275 const onPointerDownOutside = (e) => { 48276 if (!ref || layerStack.isBelowPointerBlockingLayer(ref)) { 48277 return; 48278 } 48279 if (!local.bypassTopMostLayerCheck && !layerStack.isTopMostLayer(ref)) { 48280 return; 48281 } 48282 local.onPointerDownOutside?.(e); 48283 local.onInteractOutside?.(e); 48284 if (!e.defaultPrevented) { 48285 local.onDismiss?.(); 48286 } 48287 }; 48288 const onFocusOutside = (e) => { 48289 local.onFocusOutside?.(e); 48290 local.onInteractOutside?.(e); 48291 if (!e.defaultPrevented) { 48292 local.onDismiss?.(); 48293 } 48294 }; 48295 createInteractOutside({ 48296 shouldExcludeElement, 48297 onPointerDownOutside, 48298 onFocusOutside 48299 }, () => ref); 48300 createEscapeKeyDown({ 48301 ownerDocument: () => getDocument(ref), 48302 onEscapeKeyDown: (e) => { 48303 if (!ref || !layerStack.isTopMostLayer(ref)) { 48304 return; 48305 } 48306 local.onEscapeKeyDown?.(e); 48307 if (!e.defaultPrevented && local.onDismiss) { 48308 e.preventDefault(); 48309 local.onDismiss(); 48310 } 48311 } 48312 }); 48313 onMount(() => { 48314 if (!ref) { 48315 return; 48316 } 48317 layerStack.addLayer({ 48318 node: ref, 48319 isPointerBlocking: local.disableOutsidePointerEvents, 48320 dismiss: local.onDismiss 48321 }); 48322 const unregisterFromParentLayer = parentContext?.registerNestedLayer(ref); 48323 layerStack.assignPointerEventToLayers(); 48324 layerStack.disableBodyPointerEvents(ref); 48325 onCleanup(() => { 48326 if (!ref) { 48327 return; 48328 } 48329 layerStack.removeLayer(ref); 48330 unregisterFromParentLayer?.(); 48331 layerStack.assignPointerEventToLayers(); 48332 layerStack.restoreBodyPointerEvents(ref); 48333 }); 48334 }); 48335 createEffect(on([() => ref, () => local.disableOutsidePointerEvents], ([ref2, disableOutsidePointerEvents]) => { 48336 if (!ref2) { 48337 return; 48338 } 48339 const layer = layerStack.find(ref2); 48340 if (layer && layer.isPointerBlocking !== disableOutsidePointerEvents) { 48341 layer.isPointerBlocking = disableOutsidePointerEvents; 48342 layerStack.assignPointerEventToLayers(); 48343 } 48344 if (disableOutsidePointerEvents) { 48345 layerStack.disableBodyPointerEvents(ref2); 48346 } 48347 onCleanup(() => { 48348 layerStack.restoreBodyPointerEvents(ref2); 48349 }); 48350 }, { 48351 defer: true 48352 })); 48353 const context3 = { 48354 registerNestedLayer 48355 }; 48356 return createComponent(DismissableLayerContext.Provider, { 48357 value: context3, 48358 get children() { 48359 return createComponent(Polymorphic, mergeProps({ 48360 as: "div", 48361 ref(r$) { 48362 const _ref$ = mergeRefs((el) => ref = el, local.ref); 48363 typeof _ref$ === "function" && _ref$(r$); 48364 } 48365 }, others)); 48366 } 48367 }); 48368} 48369
vendor: 1,006 bytes, lines 48370-48399
48370// node_modules/@kobalte/core/dist/chunk/BLN63FDC.js 48371function createControllableSignal(props) { 48372 const [_value, _setValue] = createSignal(props.defaultValue?.()); 48373 const isControlled = createMemo(() => props.value?.() !== void 0); 48374 const value = createMemo(() => isControlled() ? props.value?.() : _value()); 48375 const setValue = (next) => { 48376 untrack(() => { 48377 const nextValue = accessWith4(next, value()); 48378 if (!Object.is(nextValue, value())) { 48379 if (!isControlled()) { 48380 _setValue(nextValue); 48381 } 48382 props.onChange?.(nextValue); 48383 } 48384 return nextValue; 48385 }); 48386 }; 48387 return [value, setValue]; 48388} 48389function createControllableBooleanSignal(props) { 48390 const [_value, setValue] = createControllableSignal(props); 48391 const value = () => _value() ?? false; 48392 return [value, setValue]; 48393} 48394function createControllableArraySignal(props) { 48395 const [_value, setValue] = createControllableSignal(props); 48396 const value = () => _value() ?? []; 48397 return [value, setValue]; 48398} 48399
vendor: 554 bytes, lines 48400-48424
48400// node_modules/@kobalte/core/dist/chunk/7LCANGHD.js 48401function createDisclosureState(props = {}) { 48402 const [isOpen, setIsOpen] = createControllableBooleanSignal({ 48403 value: () => access4(props.open), 48404 defaultValue: () => !!access4(props.defaultOpen), 48405 onChange: (value) => props.onOpenChange?.(value) 48406 }); 48407 const open = () => { 48408 setIsOpen(true); 48409 }; 48410 const close = () => { 48411 setIsOpen(false); 48412 }; 48413 const toggle = () => { 48414 isOpen() ? close() : open(); 48415 }; 48416 return { 48417 isOpen, 48418 setIsOpen, 48419 open, 48420 close, 48421 toggle 48422 }; 48423} 48424
vendor: 384 bytes, lines 48425-48436
48425// node_modules/@kobalte/core/dist/chunk/ET5T45DO.js 48426function createTagName(ref, fallback) { 48427 const [tagName, setTagName] = createSignal(stringOrUndefined(fallback?.())); 48428 createEffect(() => { 48429 setTagName(ref()?.tagName.toLowerCase() || stringOrUndefined(fallback?.())); 48430 }); 48431 return tagName; 48432} 48433function stringOrUndefined(value) { 48434 return isString(value) ? value : void 0; 48435} 48436
vendor: 224 bytes, lines 48437-48443
48437// node_modules/@kobalte/core/dist/chunk/5ZKAE4VZ.js 48438var __defProp = Object.defineProperty; 48439var __export = (target, all3) => { 48440 for (var name in all3) 48441 __defProp(target, name, { get: all3[name], enumerable: true }); 48442}; 48443
vendor: 2,047 bytes, lines 48444-48518
48444// node_modules/@kobalte/core/dist/chunk/7OVKXYPU.js 48445var button_exports = {}; 48446__export(button_exports, { 48447 Button: () => Button, 48448 Root: () => ButtonRoot 48449}); 48450var BUTTON_INPUT_TYPES = [ 48451 "button", 48452 "color", 48453 "file", 48454 "image", 48455 "reset", 48456 "submit" 48457]; 48458function isButton(element3) { 48459 const tagName = element3.tagName.toLowerCase(); 48460 if (tagName === "button") { 48461 return true; 48462 } 48463 if (tagName === "input" && element3.type) { 48464 return BUTTON_INPUT_TYPES.indexOf(element3.type) !== -1; 48465 } 48466 return false; 48467} 48468function ButtonRoot(props) { 48469 let ref; 48470 const mergedProps = mergeDefaultProps({ 48471 type: "button" 48472 }, props); 48473 const [local, others] = splitProps(mergedProps, ["ref", "type", "disabled"]); 48474 const tagName = createTagName(() => ref, () => "button"); 48475 const isNativeButton = createMemo(() => { 48476 const elementTagName = tagName(); 48477 if (elementTagName == null) { 48478 return false; 48479 } 48480 return isButton({ 48481 tagName: elementTagName, 48482 type: local.type 48483 }); 48484 }); 48485 const isNativeInput = createMemo(() => { 48486 return tagName() === "input"; 48487 }); 48488 const isNativeLink = createMemo(() => { 48489 return tagName() === "a" && ref?.getAttribute("href") != null; 48490 }); 48491 return createComponent(Polymorphic, mergeProps({ 48492 as: "button", 48493 ref(r$) { 48494 const _ref$ = mergeRefs((el) => ref = el, local.ref); 48495 typeof _ref$ === "function" && _ref$(r$); 48496 }, 48497 get type() { 48498 return isNativeButton() || isNativeInput() ? local.type : void 0; 48499 }, 48500 get role() { 48501 return !isNativeButton() && !isNativeLink() ? "button" : void 0; 48502 }, 48503 get tabIndex() { 48504 return !isNativeButton() && !isNativeLink() && !local.disabled ? 0 : void 0; 48505 }, 48506 get disabled() { 48507 return isNativeButton() || isNativeInput() ? local.disabled : void 0; 48508 }, 48509 get ["aria-disabled"]() { 48510 return !isNativeButton() && !isNativeInput() && local.disabled ? true : void 0; 48511 }, 48512 get ["data-disabled"]() { 48513 return local.disabled ? "" : void 0; 48514 } 48515 }, others)); 48516} 48517var Button = ButtonRoot; 48518
vendor: 165 bytes, lines 48519-48526
48519// node_modules/@kobalte/core/dist/chunk/E4R2EMM4.js 48520function createRegisterId(setter) { 48521 return (id) => { 48522 setter(id); 48523 return () => setter(void 0); 48524 }; 48525} 48526
vendor: 109 bytes, lines 48527-48529
48527// node_modules/@corvu/utils/dist/chunk/ZV6G25TT.js 48528var access5 = (v) => typeof v === "function" ? v() : v; 48529
vendor: 343 bytes, lines 48530-48540
48530// node_modules/@corvu/utils/dist/chunk/SEUPK2SH.js 48531var contains2 = (wrapper, target) => { 48532 if (wrapper.contains(target)) return true; 48533 let currentElement = target; 48534 while (currentElement) { 48535 if (currentElement === wrapper) return true; 48536 currentElement = currentElement._$host ?? currentElement.parentElement; 48537 } 48538 return false; 48539}; 48540
vendor: 1,516 bytes, lines 48541-48587
48541// node_modules/@corvu/utils/dist/create/style.js 48542var activeStyles = /* @__PURE__ */ new Map(); 48543var createStyle = (props) => { 48544 createEffect(() => { 48545 const style2 = access5(props.style) ?? {}; 48546 const properties = access5(props.properties) ?? []; 48547 const originalStyles = {}; 48548 for (const key in style2) { 48549 originalStyles[key] = props.element.style[key]; 48550 } 48551 const activeStyle = activeStyles.get(props.key); 48552 if (activeStyle) { 48553 activeStyle.activeCount++; 48554 } else { 48555 activeStyles.set(props.key, { 48556 activeCount: 1, 48557 originalStyles, 48558 properties: properties.map((property3) => property3.key) 48559 }); 48560 } 48561 Object.assign(props.element.style, props.style); 48562 for (const property3 of properties) { 48563 props.element.style.setProperty(property3.key, property3.value); 48564 } 48565 onCleanup(() => { 48566 const activeStyle2 = activeStyles.get(props.key); 48567 if (!activeStyle2) return; 48568 if (activeStyle2.activeCount !== 1) { 48569 activeStyle2.activeCount--; 48570 return; 48571 } 48572 activeStyles.delete(props.key); 48573 for (const [key, value] of Object.entries(activeStyle2.originalStyles)) { 48574 props.element.style[key] = value; 48575 } 48576 for (const property3 of activeStyle2.properties) { 48577 props.element.style.removeProperty(property3); 48578 } 48579 if (props.element.style.length === 0) { 48580 props.element.removeAttribute("style"); 48581 } 48582 props.cleanup?.(); 48583 }); 48584 }); 48585}; 48586var style_default = createStyle; 48587
vendor: 1,608 bytes, lines 48588-48627
48588// node_modules/@corvu/utils/dist/scroll/index.js 48589var getScrollDimensions = (element3, axis) => { 48590 switch (axis) { 48591 case "x": 48592 return [element3.clientWidth, element3.scrollLeft, element3.scrollWidth]; 48593 case "y": 48594 return [element3.clientHeight, element3.scrollTop, element3.scrollHeight]; 48595 } 48596}; 48597var isScrollContainer = (element3, axis) => { 48598 const styles = getComputedStyle(element3); 48599 const overflow = axis === "x" ? styles.overflowX : styles.overflowY; 48600 return overflow === "auto" || overflow === "scroll" || // The HTML element is a scroll container if it has overflow visible 48601 element3.tagName === "HTML" && overflow === "visible"; 48602}; 48603var getScrollAtLocation = (location, axis, stopAt) => { 48604 const directionFactor = axis === "x" && window.getComputedStyle(location).direction === "rtl" ? -1 : 1; 48605 let currentElement = location; 48606 let availableScroll = 0; 48607 let availableScrollTop = 0; 48608 let wrapperReached = false; 48609 do { 48610 const [clientSize, scrollOffset, scrollSize] = getScrollDimensions( 48611 currentElement, 48612 axis 48613 ); 48614 const scrolled = scrollSize - clientSize - directionFactor * scrollOffset; 48615 if ((scrollOffset !== 0 || scrolled !== 0) && isScrollContainer(currentElement, axis)) { 48616 availableScroll += scrolled; 48617 availableScrollTop += scrollOffset; 48618 } 48619 if (currentElement === (stopAt ?? document.documentElement)) { 48620 wrapperReached = true; 48621 } else { 48622 currentElement = currentElement._$host ?? currentElement.parentElement; 48623 } 48624 } while (currentElement && !wrapperReached); 48625 return [availableScroll, availableScrollTop]; 48626}; 48627
vendor: 5,644 bytes, lines 48628-48796
48628// node_modules/solid-prevent-scroll/dist/index.js 48629var [preventScrollStack, setPreventScrollStack] = createSignal([]); 48630var isActive = (id) => preventScrollStack().indexOf(id) === preventScrollStack().length - 1; 48631var createPreventScroll = (props) => { 48632 const defaultedProps = mergeProps( 48633 { 48634 element: null, 48635 enabled: true, 48636 hideScrollbar: true, 48637 preventScrollbarShift: true, 48638 preventScrollbarShiftMode: "padding", 48639 restoreScrollPosition: true, 48640 allowPinchZoom: false 48641 }, 48642 props 48643 ); 48644 const preventScrollId = createUniqueId(); 48645 let currentTouchStart = [0, 0]; 48646 let currentTouchStartAxis = null; 48647 let currentTouchStartDelta = null; 48648 createEffect(() => { 48649 if (!access5(defaultedProps.enabled)) return; 48650 setPreventScrollStack((stack3) => [...stack3, preventScrollId]); 48651 onCleanup(() => { 48652 setPreventScrollStack( 48653 (stack3) => stack3.filter((id) => id !== preventScrollId) 48654 ); 48655 }); 48656 }); 48657 createEffect(() => { 48658 if (!access5(defaultedProps.enabled) || !access5(defaultedProps.hideScrollbar)) 48659 return; 48660 const { documentElement } = document; 48661 const scrollbarWidth = window.innerWidth - documentElement.clientWidth; 48662 if (access5(defaultedProps.preventScrollbarShift)) { 48663 const style2 = { overflow: "hidden" }; 48664 const properties = []; 48665 if (scrollbarWidth > 0) { 48666 if (access5(defaultedProps.preventScrollbarShiftMode) === "padding") { 48667 style2.paddingRight = `calc(${window.getComputedStyle(documentElement).paddingRight} + ${scrollbarWidth}px)`; 48668 } else { 48669 style2.marginRight = `calc(${window.getComputedStyle(documentElement).marginRight} + ${scrollbarWidth}px)`; 48670 } 48671 properties.push({ 48672 key: "--scrollbar-width", 48673 value: `${scrollbarWidth}px` 48674 }); 48675 } 48676 const offsetTop = window.scrollY; 48677 const offsetLeft = window.scrollX; 48678 style_default({ 48679 key: "prevent-scroll", 48680 element: documentElement, 48681 style: style2, 48682 properties, 48683 cleanup: () => { 48684 if (access5(defaultedProps.restoreScrollPosition) && scrollbarWidth > 0) { 48685 window.scrollTo(offsetLeft, offsetTop); 48686 } 48687 } 48688 }); 48689 } else { 48690 style_default({ 48691 key: "prevent-scroll", 48692 element: documentElement, 48693 style: { 48694 overflow: "hidden" 48695 } 48696 }); 48697 } 48698 }); 48699 createEffect(() => { 48700 if (!isActive(preventScrollId) || !access5(defaultedProps.enabled)) return; 48701 document.addEventListener("wheel", maybePreventWheel, { 48702 passive: false 48703 }); 48704 document.addEventListener("touchstart", logTouchStart, { 48705 passive: false 48706 }); 48707 document.addEventListener("touchmove", maybePreventTouch, { 48708 passive: false 48709 }); 48710 onCleanup(() => { 48711 document.removeEventListener("wheel", maybePreventWheel); 48712 document.removeEventListener("touchstart", logTouchStart); 48713 document.removeEventListener("touchmove", maybePreventTouch); 48714 }); 48715 }); 48716 const logTouchStart = (event) => { 48717 currentTouchStart = getTouchXY(event); 48718 currentTouchStartAxis = null; 48719 currentTouchStartDelta = null; 48720 }; 48721 const maybePreventWheel = (event) => { 48722 const target = event.target; 48723 const wrapper = access5(defaultedProps.element); 48724 const delta = getDeltaXY(event); 48725 const axis = Math.abs(delta[0]) > Math.abs(delta[1]) ? "x" : "y"; 48726 const axisDelta = axis === "x" ? delta[0] : delta[1]; 48727 const resultsInScroll = wouldScroll(target, axis, axisDelta, wrapper); 48728 let shouldCancel; 48729 if (wrapper && contains2(wrapper, target)) { 48730 shouldCancel = !resultsInScroll; 48731 } else { 48732 shouldCancel = true; 48733 } 48734 if (shouldCancel && event.cancelable) { 48735 event.preventDefault(); 48736 } 48737 }; 48738 const maybePreventTouch = (event) => { 48739 const wrapper = access5(defaultedProps.element); 48740 const target = event.target; 48741 let shouldCancel; 48742 if (event.touches.length === 2) { 48743 shouldCancel = !access5(defaultedProps.allowPinchZoom); 48744 } else { 48745 if (currentTouchStartAxis == null || currentTouchStartDelta === null) { 48746 const delta = getTouchXY(event).map( 48747 (touch, i) => currentTouchStart[i] - touch 48748 ); 48749 const axis = Math.abs(delta[0]) > Math.abs(delta[1]) ? "x" : "y"; 48750 currentTouchStartAxis = axis; 48751 currentTouchStartDelta = axis === "x" ? delta[0] : delta[1]; 48752 } 48753 if (target.type === "range") { 48754 shouldCancel = false; 48755 } else { 48756 const wouldResultInScroll = wouldScroll( 48757 target, 48758 currentTouchStartAxis, 48759 currentTouchStartDelta, 48760 wrapper 48761 ); 48762 if (wrapper && contains2(wrapper, target)) { 48763 shouldCancel = !wouldResultInScroll; 48764 } else { 48765 shouldCancel = true; 48766 } 48767 } 48768 } 48769 if (shouldCancel && event.cancelable) { 48770 event.preventDefault(); 48771 } 48772 }; 48773}; 48774var getDeltaXY = (event) => [ 48775 event.deltaX, 48776 event.deltaY 48777]; 48778var getTouchXY = (event) => event.changedTouches[0] ? [event.changedTouches[0].clientX, event.changedTouches[0].clientY] : [0, 0]; 48779var wouldScroll = (target, axis, delta, wrapper) => { 48780 const targetInWrapper = wrapper !== null && contains2(wrapper, target); 48781 const [availableScroll, availableScrollTop] = getScrollAtLocation( 48782 target, 48783 axis, 48784 targetInWrapper ? wrapper : void 0 48785 ); 48786 if (delta > 0 && Math.abs(availableScroll) <= 1) { 48787 return false; 48788 } 48789 if (delta < 0 && Math.abs(availableScrollTop) < 1) { 48790 return false; 48791 } 48792 return true; 48793}; 48794var preventScroll_default = createPreventScroll; 48795var index_default = preventScroll_default; 48796
vendor: 2,531 bytes, lines 48797-48867
48797// node_modules/solid-presence/dist/index.js 48798var createPresence = (props) => { 48799 const refStyles = createMemo(() => { 48800 const element3 = access5(props.element); 48801 if (!element3) return; 48802 return getComputedStyle(element3); 48803 }); 48804 const getAnimationName = () => { 48805 return refStyles()?.animationName ?? "none"; 48806 }; 48807 const [presentState, setPresentStateInternal] = createSignal(access5(props.show) ? "present" : "hidden"); 48808 const setPresentState = (state) => { 48809 setPresentStateInternal(state); 48810 props.onStateChange?.(state); 48811 }; 48812 let animationName = "none"; 48813 createEffect((prevShow) => { 48814 const show = access5(props.show); 48815 untrack(() => { 48816 if (prevShow === show) return show; 48817 const prevAnimationName = animationName; 48818 const currentAnimationName = getAnimationName(); 48819 if (show) { 48820 setPresentState("present"); 48821 } else if (currentAnimationName === "none" || refStyles()?.display === "none") { 48822 setPresentState("hidden"); 48823 } else { 48824 const isAnimating = prevAnimationName !== currentAnimationName; 48825 if (prevShow === true && isAnimating) { 48826 setPresentState("hiding"); 48827 } else { 48828 setPresentState("hidden"); 48829 } 48830 } 48831 }); 48832 return show; 48833 }, access5(props.show)); 48834 createEffect(() => { 48835 const element3 = access5(props.element); 48836 if (!element3) return; 48837 const handleAnimationStart = (event) => { 48838 if (event.target === element3) { 48839 animationName = getAnimationName(); 48840 } 48841 }; 48842 const handleAnimationEnd = (event) => { 48843 const currentAnimationName = getAnimationName(); 48844 const isCurrentAnimation = currentAnimationName.includes( 48845 event.animationName 48846 ); 48847 if (event.target === element3 && isCurrentAnimation && presentState() === "hiding") { 48848 setPresentState("hidden"); 48849 } 48850 }; 48851 element3.addEventListener("animationstart", handleAnimationStart); 48852 element3.addEventListener("animationcancel", handleAnimationEnd); 48853 element3.addEventListener("animationend", handleAnimationEnd); 48854 onCleanup(() => { 48855 element3.removeEventListener("animationstart", handleAnimationStart); 48856 element3.removeEventListener("animationcancel", handleAnimationEnd); 48857 element3.removeEventListener("animationend", handleAnimationEnd); 48858 }); 48859 }); 48860 return { 48861 present: () => presentState() === "present" || presentState() === "hiding", 48862 state: presentState 48863 }; 48864}; 48865var presence_default = createPresence; 48866var index_default2 = presence_default; 48867
vendor: 9,732 bytes, lines 48868-49193
48868// node_modules/@kobalte/core/dist/chunk/27MLNS66.js 48869var dialog_exports = {}; 48870__export(dialog_exports, { 48871 CloseButton: () => DialogCloseButton, 48872 Content: () => DialogContent, 48873 Description: () => DialogDescription, 48874 Dialog: () => Dialog, 48875 Overlay: () => DialogOverlay, 48876 Portal: () => DialogPortal, 48877 Root: () => DialogRoot, 48878 Title: () => DialogTitle, 48879 Trigger: () => DialogTrigger, 48880 useDialogContext: () => useDialogContext 48881}); 48882var DialogContext = createContext(); 48883function useDialogContext() { 48884 const context3 = useContext(DialogContext); 48885 if (context3 === void 0) { 48886 throw new Error("[kobalte]: `useDialogContext` must be used within a `Dialog` component"); 48887 } 48888 return context3; 48889} 48890function DialogCloseButton(props) { 48891 const context3 = useDialogContext(); 48892 const [local, others] = splitProps(props, ["aria-label", "onClick"]); 48893 const onClick = (e) => { 48894 callHandler(e, local.onClick); 48895 context3.close(); 48896 }; 48897 return createComponent(ButtonRoot, mergeProps({ 48898 get ["aria-label"]() { 48899 return local["aria-label"] || context3.translations().dismiss; 48900 }, 48901 onClick 48902 }, others)); 48903} 48904function DialogContent(props) { 48905 let ref; 48906 const context3 = useDialogContext(); 48907 const mergedProps = mergeDefaultProps({ 48908 id: context3.generateId("content") 48909 }, props); 48910 const [local, others] = splitProps(mergedProps, ["ref", "onOpenAutoFocus", "onCloseAutoFocus", "onPointerDownOutside", "onFocusOutside", "onInteractOutside"]); 48911 let hasInteractedOutside = false; 48912 let hasPointerDownOutside = false; 48913 const onPointerDownOutside = (e) => { 48914 local.onPointerDownOutside?.(e); 48915 if (context3.modal() && e.detail.isContextMenu) { 48916 e.preventDefault(); 48917 } 48918 }; 48919 const onFocusOutside = (e) => { 48920 local.onFocusOutside?.(e); 48921 if (context3.modal()) { 48922 e.preventDefault(); 48923 } 48924 }; 48925 const onInteractOutside = (e) => { 48926 local.onInteractOutside?.(e); 48927 if (context3.modal()) { 48928 return; 48929 } 48930 if (!e.defaultPrevented) { 48931 hasInteractedOutside = true; 48932 if (e.detail.originalEvent.type === "pointerdown") { 48933 hasPointerDownOutside = true; 48934 } 48935 } 48936 if (contains(context3.triggerRef(), e.target)) { 48937 e.preventDefault(); 48938 } 48939 if (e.detail.originalEvent.type === "focusin" && hasPointerDownOutside) { 48940 e.preventDefault(); 48941 } 48942 }; 48943 const onCloseAutoFocus = (e) => { 48944 local.onCloseAutoFocus?.(e); 48945 if (context3.modal()) { 48946 e.preventDefault(); 48947 focusWithoutScrolling(context3.triggerRef()); 48948 } else { 48949 if (!e.defaultPrevented) { 48950 if (!hasInteractedOutside) { 48951 focusWithoutScrolling(context3.triggerRef()); 48952 } 48953 e.preventDefault(); 48954 } 48955 hasInteractedOutside = false; 48956 hasPointerDownOutside = false; 48957 } 48958 }; 48959 createHideOutside({ 48960 isDisabled: () => !(context3.isOpen() && context3.modal()), 48961 targets: () => ref ? [ref] : [] 48962 }); 48963 index_default({ 48964 element: () => ref ?? null, 48965 enabled: () => context3.contentPresent() && context3.preventScroll() 48966 }); 48967 createFocusScope({ 48968 trapFocus: () => context3.isOpen() && context3.modal(), 48969 onMountAutoFocus: local.onOpenAutoFocus, 48970 onUnmountAutoFocus: onCloseAutoFocus 48971 }, () => ref); 48972 createEffect(() => onCleanup(context3.registerContentId(others.id))); 48973 return createComponent(Show, { 48974 get when() { 48975 return context3.contentPresent(); 48976 }, 48977 get children() { 48978 return createComponent(DismissableLayer, mergeProps({ 48979 ref(r$) { 48980 const _ref$ = mergeRefs((el) => { 48981 context3.setContentRef(el); 48982 ref = el; 48983 }, local.ref); 48984 typeof _ref$ === "function" && _ref$(r$); 48985 }, 48986 role: "dialog", 48987 tabIndex: -1, 48988 get disableOutsidePointerEvents() { 48989 return memo(() => !!context3.modal())() && context3.isOpen(); 48990 }, 48991 get excludedElements() { 48992 return [context3.triggerRef]; 48993 }, 48994 get ["aria-labelledby"]() { 48995 return context3.titleId(); 48996 }, 48997 get ["aria-describedby"]() { 48998 return context3.descriptionId(); 48999 }, 49000 get ["data-expanded"]() { 49001 return context3.isOpen() ? "" : void 0; 49002 }, 49003 get ["data-closed"]() { 49004 return !context3.isOpen() ? "" : void 0; 49005 }, 49006 onPointerDownOutside, 49007 onFocusOutside, 49008 onInteractOutside, 49009 get onDismiss() { 49010 return context3.close; 49011 } 49012 }, others)); 49013 } 49014 }); 49015} 49016function DialogDescription(props) { 49017 const context3 = useDialogContext(); 49018 const mergedProps = mergeDefaultProps({ 49019 id: context3.generateId("description") 49020 }, props); 49021 const [local, others] = splitProps(mergedProps, ["id"]); 49022 createEffect(() => onCleanup(context3.registerDescriptionId(local.id))); 49023 return createComponent(Polymorphic, mergeProps({ 49024 as: "p", 49025 get id() { 49026 return local.id; 49027 } 49028 }, others)); 49029} 49030function DialogOverlay(props) { 49031 const context3 = useDialogContext(); 49032 const [local, others] = splitProps(props, ["ref", "style", "onPointerDown"]); 49033 const onPointerDown = (e) => { 49034 callHandler(e, local.onPointerDown); 49035 if (e.target === e.currentTarget) { 49036 e.preventDefault(); 49037 } 49038 }; 49039 return createComponent(Show, { 49040 get when() { 49041 return context3.overlayPresent(); 49042 }, 49043 get children() { 49044 return createComponent(Polymorphic, mergeProps({ 49045 as: "div", 49046 ref(r$) { 49047 const _ref$ = mergeRefs(context3.setOverlayRef, local.ref); 49048 typeof _ref$ === "function" && _ref$(r$); 49049 }, 49050 get style() { 49051 return combineStyle({ 49052 "pointer-events": "auto" 49053 }, local.style); 49054 }, 49055 get ["data-expanded"]() { 49056 return context3.isOpen() ? "" : void 0; 49057 }, 49058 get ["data-closed"]() { 49059 return !context3.isOpen() ? "" : void 0; 49060 }, 49061 onPointerDown 49062 }, others)); 49063 } 49064 }); 49065} 49066function DialogPortal(props) { 49067 const context3 = useDialogContext(); 49068 return createComponent(Show, { 49069 get when() { 49070 return context3.contentPresent() || context3.overlayPresent(); 49071 }, 49072 get children() { 49073 return createComponent(Portal, props); 49074 } 49075 }); 49076} 49077var DIALOG_INTL_TRANSLATIONS = { 49078 // `aria-label` of Dialog.CloseButton. 49079 dismiss: "Dismiss" 49080}; 49081function DialogRoot(props) { 49082 const defaultId = `dialog-${createUniqueId()}`; 49083 const mergedProps = mergeDefaultProps({ 49084 id: defaultId, 49085 modal: true, 49086 translations: DIALOG_INTL_TRANSLATIONS 49087 }, props); 49088 const [contentId, setContentId] = createSignal(); 49089 const [titleId, setTitleId] = createSignal(); 49090 const [descriptionId, setDescriptionId] = createSignal(); 49091 const [overlayRef, setOverlayRef] = createSignal(); 49092 const [contentRef, setContentRef] = createSignal(); 49093 const [triggerRef, setTriggerRef] = createSignal(); 49094 const disclosureState = createDisclosureState({ 49095 open: () => mergedProps.open, 49096 defaultOpen: () => mergedProps.defaultOpen, 49097 onOpenChange: (isOpen) => mergedProps.onOpenChange?.(isOpen) 49098 }); 49099 const shouldMount = () => mergedProps.forceMount || disclosureState.isOpen(); 49100 const { 49101 present: overlayPresent 49102 } = index_default2({ 49103 show: shouldMount, 49104 element: () => overlayRef() ?? null 49105 }); 49106 const { 49107 present: contentPresent 49108 } = index_default2({ 49109 show: shouldMount, 49110 element: () => contentRef() ?? null 49111 }); 49112 const context3 = { 49113 translations: () => mergedProps.translations ?? DIALOG_INTL_TRANSLATIONS, 49114 isOpen: disclosureState.isOpen, 49115 modal: () => mergedProps.modal ?? true, 49116 preventScroll: () => mergedProps.preventScroll ?? context3.modal(), 49117 contentId, 49118 titleId, 49119 descriptionId, 49120 triggerRef, 49121 overlayRef, 49122 setOverlayRef, 49123 contentRef, 49124 setContentRef, 49125 overlayPresent, 49126 contentPresent, 49127 close: disclosureState.close, 49128 toggle: disclosureState.toggle, 49129 setTriggerRef, 49130 generateId: createGenerateId(() => mergedProps.id), 49131 registerContentId: createRegisterId(setContentId), 49132 registerTitleId: createRegisterId(setTitleId), 49133 registerDescriptionId: createRegisterId(setDescriptionId) 49134 }; 49135 return createComponent(DialogContext.Provider, { 49136 value: context3, 49137 get children() { 49138 return mergedProps.children; 49139 } 49140 }); 49141} 49142function DialogTitle(props) { 49143 const context3 = useDialogContext(); 49144 const mergedProps = mergeDefaultProps({ 49145 id: context3.generateId("title") 49146 }, props); 49147 const [local, others] = splitProps(mergedProps, ["id"]); 49148 createEffect(() => onCleanup(context3.registerTitleId(local.id))); 49149 return createComponent(Polymorphic, mergeProps({ 49150 as: "h2", 49151 get id() { 49152 return local.id; 49153 } 49154 }, others)); 49155} 49156function DialogTrigger(props) { 49157 const context3 = useDialogContext(); 49158 const [local, others] = splitProps(props, ["ref", "onClick"]); 49159 const onClick = (e) => { 49160 callHandler(e, local.onClick); 49161 context3.toggle(); 49162 }; 49163 return createComponent(ButtonRoot, mergeProps({ 49164 ref(r$) { 49165 const _ref$ = mergeRefs(context3.setTriggerRef, local.ref); 49166 typeof _ref$ === "function" && _ref$(r$); 49167 }, 49168 "aria-haspopup": "dialog", 49169 get ["aria-expanded"]() { 49170 return context3.isOpen(); 49171 }, 49172 get ["aria-controls"]() { 49173 return memo(() => !!context3.isOpen())() ? context3.contentId() : void 0; 49174 }, 49175 get ["data-expanded"]() { 49176 return context3.isOpen() ? "" : void 0; 49177 }, 49178 get ["data-closed"]() { 49179 return !context3.isOpen() ? "" : void 0; 49180 }, 49181 onClick 49182 }, others)); 49183} 49184var Dialog = Object.assign(DialogRoot, { 49185 CloseButton: DialogCloseButton, 49186 Content: DialogContent, 49187 Description: DialogDescription, 49188 Overlay: DialogOverlay, 49189 Portal: DialogPortal, 49190 Title: DialogTitle, 49191 Trigger: DialogTrigger 49192}); 49193
vendor: 5,810 bytes, lines 49194-49334
49194// node_modules/@internationalized/number/dist/NumberFormatter.mjs 49195var $488c6ddbf4ef74c2$var$formatterCache = /* @__PURE__ */ new Map(); 49196var $488c6ddbf4ef74c2$var$supportsSignDisplay = false; 49197try { 49198 $488c6ddbf4ef74c2$var$supportsSignDisplay = new Intl.NumberFormat("de-DE", { 49199 signDisplay: "exceptZero" 49200 }).resolvedOptions().signDisplay === "exceptZero"; 49201} catch (e) { 49202} 49203var $488c6ddbf4ef74c2$var$supportsUnit = false; 49204try { 49205 $488c6ddbf4ef74c2$var$supportsUnit = new Intl.NumberFormat("de-DE", { 49206 style: "unit", 49207 unit: "degree" 49208 }).resolvedOptions().style === "unit"; 49209} catch (e) { 49210} 49211var $488c6ddbf4ef74c2$var$UNITS = { 49212 degree: { 49213 narrow: { 49214 default: "\xB0", 49215 "ja-JP": " \u5EA6", 49216 "zh-TW": "\u5EA6", 49217 "sl-SI": " \xB0" 49218 } 49219 } 49220}; 49221var $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5 = class { 49222 /** Formats a number value as a string, according to the locale and options provided to the constructor. */ 49223 format(value) { 49224 let res = ""; 49225 if (!$488c6ddbf4ef74c2$var$supportsSignDisplay && this.options.signDisplay != null) res = $488c6ddbf4ef74c2$export$711b50b3c525e0f2(this.numberFormatter, this.options.signDisplay, value); 49226 else res = this.numberFormatter.format(value); 49227 if (this.options.style === "unit" && !$488c6ddbf4ef74c2$var$supportsUnit) { 49228 var _UNITS_unit; 49229 let { unit, unitDisplay = "short", locale } = this.resolvedOptions(); 49230 if (!unit) return res; 49231 let values = (_UNITS_unit = $488c6ddbf4ef74c2$var$UNITS[unit]) === null || _UNITS_unit === void 0 ? void 0 : _UNITS_unit[unitDisplay]; 49232 res += values[locale] || values.default; 49233 } 49234 return res; 49235 } 49236 /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */ 49237 formatToParts(value) { 49238 return this.numberFormatter.formatToParts(value); 49239 } 49240 /** Formats a number range as a string. */ 49241 formatRange(start, end) { 49242 if (typeof this.numberFormatter.formatRange === "function") 49243 return this.numberFormatter.formatRange(start, end); 49244 if (end < start) throw new RangeError("End date must be >= start date"); 49245 return `${this.format(start)} \u2013 ${this.format(end)}`; 49246 } 49247 /** Formats a number range as an array of parts. */ 49248 formatRangeToParts(start, end) { 49249 if (typeof this.numberFormatter.formatRangeToParts === "function") 49250 return this.numberFormatter.formatRangeToParts(start, end); 49251 if (end < start) throw new RangeError("End date must be >= start date"); 49252 let startParts = this.numberFormatter.formatToParts(start); 49253 let endParts = this.numberFormatter.formatToParts(end); 49254 return [ 49255 ...startParts.map((p) => ({ 49256 ...p, 49257 source: "startRange" 49258 })), 49259 { 49260 type: "literal", 49261 value: " \u2013 ", 49262 source: "shared" 49263 }, 49264 ...endParts.map((p) => ({ 49265 ...p, 49266 source: "endRange" 49267 })) 49268 ]; 49269 } 49270 /** Returns the resolved formatting options based on the values passed to the constructor. */ 49271 resolvedOptions() { 49272 let options = this.numberFormatter.resolvedOptions(); 49273 if (!$488c6ddbf4ef74c2$var$supportsSignDisplay && this.options.signDisplay != null) options = { 49274 ...options, 49275 signDisplay: this.options.signDisplay 49276 }; 49277 if (!$488c6ddbf4ef74c2$var$supportsUnit && this.options.style === "unit") options = { 49278 ...options, 49279 style: "unit", 49280 unit: this.options.unit, 49281 unitDisplay: this.options.unitDisplay 49282 }; 49283 return options; 49284 } 49285 constructor(locale, options = {}) { 49286 this.numberFormatter = $488c6ddbf4ef74c2$var$getCachedNumberFormatter(locale, options); 49287 this.options = options; 49288 } 49289}; 49290function $488c6ddbf4ef74c2$var$getCachedNumberFormatter(locale, options = {}) { 49291 let { numberingSystem } = options; 49292 if (numberingSystem && locale.includes("-nu-")) { 49293 if (!locale.includes("-u-")) locale += "-u-"; 49294 locale += `-nu-${numberingSystem}`; 49295 } 49296 if (options.style === "unit" && !$488c6ddbf4ef74c2$var$supportsUnit) { 49297 var _UNITS_unit; 49298 let { unit, unitDisplay = "short" } = options; 49299 if (!unit) throw new Error('unit option must be provided with style: "unit"'); 49300 if (!((_UNITS_unit = $488c6ddbf4ef74c2$var$UNITS[unit]) === null || _UNITS_unit === void 0 ? void 0 : _UNITS_unit[unitDisplay])) throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`); 49301 options = { 49302 ...options, 49303 style: "decimal" 49304 }; 49305 } 49306 let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : ""); 49307 if ($488c6ddbf4ef74c2$var$formatterCache.has(cacheKey)) return $488c6ddbf4ef74c2$var$formatterCache.get(cacheKey); 49308 let numberFormatter = new Intl.NumberFormat(locale, options); 49309 $488c6ddbf4ef74c2$var$formatterCache.set(cacheKey, numberFormatter); 49310 return numberFormatter; 49311} 49312function $488c6ddbf4ef74c2$export$711b50b3c525e0f2(numberFormat, signDisplay, num) { 49313 if (signDisplay === "auto") return numberFormat.format(num); 49314 else if (signDisplay === "never") return numberFormat.format(Math.abs(num)); 49315 else { 49316 let needsPositiveSign = false; 49317 if (signDisplay === "always") needsPositiveSign = num > 0 || Object.is(num, 0); 49318 else if (signDisplay === "exceptZero") { 49319 if (Object.is(num, -0) || Object.is(num, 0)) num = Math.abs(num); 49320 else needsPositiveSign = num > 0; 49321 } 49322 if (needsPositiveSign) { 49323 let negative = numberFormat.format(-num); 49324 let noSign = numberFormat.format(num); 49325 let minus = negative.replace(noSign, "").replace(/\u200e|\u061C/, ""); 49326 if ([ 49327 ...minus 49328 ].length !== 1) console.warn("@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case"); 49329 let positive = negative.replace(noSign, "!!!").replace(minus, "+").replace("!!!", noSign); 49330 return positive; 49331 } else return numberFormat.format(num); 49332 } 49333} 49334
vendor: 2,852 bytes, lines 49335-49453
49335// node_modules/@kobalte/core/dist/chunk/7TPOQ36Z.js 49336var RTL_SCRIPTS = /* @__PURE__ */ new Set([ 49337 "Avst", 49338 "Arab", 49339 "Armi", 49340 "Syrc", 49341 "Samr", 49342 "Mand", 49343 "Thaa", 49344 "Mend", 49345 "Nkoo", 49346 "Adlm", 49347 "Rohg", 49348 "Hebr" 49349]); 49350var RTL_LANGS = /* @__PURE__ */ new Set([ 49351 "ae", 49352 "ar", 49353 "arc", 49354 "bcc", 49355 "bqi", 49356 "ckb", 49357 "dv", 49358 "fa", 49359 "glk", 49360 "he", 49361 "ku", 49362 "mzn", 49363 "nqo", 49364 "pnb", 49365 "ps", 49366 "sd", 49367 "ug", 49368 "ur", 49369 "yi" 49370]); 49371function isRTL(locale) { 49372 if (Intl.Locale) { 49373 const script = new Intl.Locale(locale).maximize().script ?? ""; 49374 return RTL_SCRIPTS.has(script); 49375 } 49376 const lang = locale.split("-")[0]; 49377 return RTL_LANGS.has(lang); 49378} 49379function getReadingDirection(locale) { 49380 return isRTL(locale) ? "rtl" : "ltr"; 49381} 49382function getDefaultLocale() { 49383 let locale = typeof navigator !== "undefined" && // @ts-ignore 49384 (navigator.language || navigator.userLanguage) || "en-US"; 49385 return { 49386 locale, 49387 direction: getReadingDirection(locale) 49388 }; 49389} 49390var currentLocale = getDefaultLocale(); 49391var listeners = /* @__PURE__ */ new Set(); 49392function updateLocale() { 49393 currentLocale = getDefaultLocale(); 49394 for (const listener of listeners) { 49395 listener(currentLocale); 49396 } 49397} 49398function createDefaultLocale() { 49399 const defaultSSRLocale = { 49400 locale: "en-US", 49401 direction: "ltr" 49402 }; 49403 const [defaultClientLocale, setDefaultClientLocale] = createSignal(currentLocale); 49404 const defaultLocale = createMemo( 49405 () => isServer ? defaultSSRLocale : defaultClientLocale() 49406 ); 49407 onMount(() => { 49408 if (listeners.size === 0) { 49409 window.addEventListener("languagechange", updateLocale); 49410 } 49411 listeners.add(setDefaultClientLocale); 49412 onCleanup(() => { 49413 listeners.delete(setDefaultClientLocale); 49414 if (listeners.size === 0) { 49415 window.removeEventListener("languagechange", updateLocale); 49416 } 49417 }); 49418 }); 49419 return { 49420 locale: () => defaultLocale().locale, 49421 direction: () => defaultLocale().direction 49422 }; 49423} 49424var I18nContext = createContext(); 49425function useLocale() { 49426 const defaultLocale = createDefaultLocale(); 49427 const context3 = useContext(I18nContext); 49428 return context3 || defaultLocale; 49429} 49430var cache3 = /* @__PURE__ */ new Map(); 49431function createCollator(options) { 49432 const { locale } = useLocale(); 49433 const cacheKey = createMemo(() => { 49434 return locale() + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : ""); 49435 }); 49436 return createMemo(() => { 49437 const key = cacheKey(); 49438 let collator; 49439 if (cache3.has(key)) { 49440 collator = cache3.get(key); 49441 } 49442 if (!collator) { 49443 collator = new Intl.Collator(locale(), options); 49444 cache3.set(key, collator); 49445 } 49446 return collator; 49447 }); 49448} 49449function createNumberFormatter(options) { 49450 const { locale } = useLocale(); 49451 return createMemo(() => new $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5(locale(), access4(options))); 49452} 49453
vendor: 3,845 bytes, lines 49454-49588
49454// node_modules/@kobalte/core/dist/chunk/PTVG6YKC.js 49455var MeterContext = createContext(); 49456function useMeterContext() { 49457 const context3 = useContext(MeterContext); 49458 if (context3 === void 0) { 49459 throw new Error("[kobalte]: `useMeterContext` must be used within a `Meter.Root` component"); 49460 } 49461 return context3; 49462} 49463function MeterFill(props) { 49464 const context3 = useMeterContext(); 49465 const [local, others] = splitProps(props, ["style"]); 49466 return createComponent(Polymorphic, mergeProps({ 49467 as: "div", 49468 get style() { 49469 return combineStyle({ 49470 "--kb-meter-fill-width": context3.meterFillWidth() 49471 }, local.style); 49472 } 49473 }, () => context3.dataset(), others)); 49474} 49475function MeterLabel(props) { 49476 const context3 = useMeterContext(); 49477 const mergedProps = mergeDefaultProps({ 49478 id: context3.generateId("label") 49479 }, props); 49480 const [local, others] = splitProps(mergedProps, ["id"]); 49481 createEffect(() => onCleanup(context3.registerLabelId(local.id))); 49482 return createComponent(Polymorphic, mergeProps({ 49483 as: "span", 49484 get id() { 49485 return local.id; 49486 } 49487 }, () => context3.dataset(), others)); 49488} 49489function MeterRoot(props) { 49490 const defaultId = `meter-${createUniqueId()}`; 49491 const mergedProps = mergeDefaultProps({ 49492 id: defaultId, 49493 value: 0, 49494 minValue: 0, 49495 maxValue: 100, 49496 role: "meter", 49497 indeterminate: false 49498 }, props); 49499 const [local, others] = splitProps(mergedProps, ["value", "minValue", "maxValue", "getValueLabel", "role", "aria-valuetext", "aria-labelledby", "aria-valuemax", "aria-valuemin", "aria-valuenow", "indeterminate"]); 49500 const [labelId, setLabelId] = createSignal(); 49501 const defaultFormatter = createNumberFormatter(() => ({ 49502 style: "percent" 49503 })); 49504 const value = () => { 49505 return clamp7(local.value, local.minValue, local.maxValue); 49506 }; 49507 const valuePercent = () => { 49508 return (value() - local.minValue) / (local.maxValue - local.minValue); 49509 }; 49510 const valueLabel = () => { 49511 if (local.indeterminate) { 49512 return void 0; 49513 } 49514 if (local.getValueLabel) { 49515 return local.getValueLabel({ 49516 value: value(), 49517 min: local.minValue, 49518 max: local.maxValue 49519 }); 49520 } 49521 return defaultFormatter().format(valuePercent()); 49522 }; 49523 const meterFillWidth = () => { 49524 return `${valuePercent() * 100}%`; 49525 }; 49526 const dataset = createMemo(() => { 49527 return {}; 49528 }); 49529 const context3 = { 49530 dataset, 49531 value, 49532 valuePercent, 49533 valueLabel, 49534 labelId, 49535 meterFillWidth, 49536 generateId: createGenerateId(() => others.id), 49537 registerLabelId: createRegisterId(setLabelId) 49538 }; 49539 return createComponent(MeterContext.Provider, { 49540 value: context3, 49541 get children() { 49542 return createComponent(Polymorphic, mergeProps({ 49543 as: "div", 49544 get role() { 49545 return local.role || "meter"; 49546 }, 49547 get ["aria-valuenow"]() { 49548 return memo(() => !!local.indeterminate)() ? void 0 : value(); 49549 }, 49550 get ["aria-valuemin"]() { 49551 return local.minValue; 49552 }, 49553 get ["aria-valuemax"]() { 49554 return local.maxValue; 49555 }, 49556 get ["aria-valuetext"]() { 49557 return valueLabel(); 49558 }, 49559 get ["aria-labelledby"]() { 49560 return labelId(); 49561 } 49562 }, dataset, others)); 49563 } 49564 }); 49565} 49566function MeterTrack(props) { 49567 const context3 = useMeterContext(); 49568 return createComponent(Polymorphic, mergeProps({ 49569 as: "div" 49570 }, () => context3.dataset(), props)); 49571} 49572function MeterValueLabel(props) { 49573 const context3 = useMeterContext(); 49574 return createComponent(Polymorphic, mergeProps({ 49575 as: "div" 49576 }, () => context3.dataset(), props, { 49577 get children() { 49578 return context3.valueLabel(); 49579 } 49580 })); 49581} 49582var Meter = Object.assign(MeterRoot, { 49583 Fill: MeterFill, 49584 Label: MeterLabel, 49585 Track: MeterTrack, 49586 ValueLabel: MeterValueLabel 49587}); 49588
vendor: 3,805 bytes, lines 49589-49713
49589// node_modules/@kobalte/core/dist/chunk/JGNXQB3J.js 49590var progress_exports = {}; 49591__export(progress_exports, { 49592 Fill: () => ProgressFill, 49593 Label: () => ProgressLabel, 49594 Progress: () => Progress, 49595 Root: () => ProgressRoot, 49596 Track: () => ProgressTrack, 49597 ValueLabel: () => ProgressValueLabel, 49598 useProgressContext: () => useProgressContext 49599}); 49600var ProgressContext = createContext(); 49601function useProgressContext() { 49602 const context3 = useContext(ProgressContext); 49603 if (context3 === void 0) { 49604 throw new Error("[kobalte]: `useProgressContext` must be used within a `Progress.Root` component"); 49605 } 49606 return context3; 49607} 49608function ProgressFill(props) { 49609 const context3 = useProgressContext(); 49610 const [local, others] = splitProps(props, ["style"]); 49611 return createComponent(Meter.Fill, mergeProps({ 49612 get style() { 49613 return combineStyle({ 49614 "--kb-progress-fill-width": context3.progressFillWidth() 49615 }, local.style); 49616 } 49617 }, () => context3.dataset(), others)); 49618} 49619function ProgressLabel(props) { 49620 const context3 = useProgressContext(); 49621 const mergedProps = mergeDefaultProps({ 49622 id: context3.generateId("label") 49623 }, props); 49624 const [local, others] = splitProps(mergedProps, ["id"]); 49625 createEffect(() => onCleanup(context3.registerLabelId(local.id))); 49626 return createComponent(Meter.Label, mergeProps({ 49627 get id() { 49628 return local.id; 49629 } 49630 }, () => context3.dataset(), others)); 49631} 49632function ProgressRoot(props) { 49633 const defaultId = `progress-${createUniqueId()}`; 49634 const mergedProps = mergeDefaultProps({ 49635 id: defaultId, 49636 value: 0, 49637 minValue: 0, 49638 maxValue: 100 49639 }, props); 49640 const [local, others] = splitProps(mergedProps, ["value", "minValue", "maxValue", "indeterminate", "getValueLabel"]); 49641 const [labelId, setLabelId] = createSignal(); 49642 const defaultFormatter = createNumberFormatter(() => ({ 49643 style: "percent" 49644 })); 49645 const value = () => { 49646 return clamp7(local.value, local.minValue, local.maxValue); 49647 }; 49648 const valuePercent = () => { 49649 return (value() - local.minValue) / (local.maxValue - local.minValue); 49650 }; 49651 const valueLabel = () => { 49652 if (local.indeterminate) { 49653 return void 0; 49654 } 49655 if (local.getValueLabel) { 49656 return local.getValueLabel({ 49657 value: value(), 49658 min: local.minValue, 49659 max: local.maxValue 49660 }); 49661 } 49662 return defaultFormatter().format(valuePercent()); 49663 }; 49664 const progressFillWidth = () => { 49665 return local.indeterminate ? void 0 : `${valuePercent() * 100}%`; 49666 }; 49667 const dataset = createMemo(() => { 49668 let dataProgress = void 0; 49669 if (!local.indeterminate) { 49670 dataProgress = valuePercent() === 1 ? "complete" : "loading"; 49671 } 49672 return { 49673 "data-progress": dataProgress, 49674 "data-indeterminate": local.indeterminate ? "" : void 0 49675 }; 49676 }); 49677 const context3 = { 49678 dataset, 49679 value, 49680 valuePercent, 49681 valueLabel, 49682 labelId, 49683 progressFillWidth, 49684 generateId: createGenerateId(() => others.id), 49685 registerLabelId: createRegisterId(setLabelId) 49686 }; 49687 return createComponent(ProgressContext.Provider, { 49688 value: context3, 49689 get children() { 49690 return createComponent(Meter, mergeProps({ 49691 role: "progressbar", 49692 get indeterminate() { 49693 return local.indeterminate || false; 49694 } 49695 }, dataset, mergedProps)); 49696 } 49697 }); 49698} 49699function ProgressTrack(props) { 49700 const context3 = useProgressContext(); 49701 return createComponent(Meter.Track, mergeProps(() => context3.dataset(), props)); 49702} 49703function ProgressValueLabel(props) { 49704 const context3 = useProgressContext(); 49705 return createComponent(Meter.ValueLabel, mergeProps(() => context3.dataset(), props)); 49706} 49707var Progress = Object.assign(ProgressRoot, { 49708 Fill: ProgressFill, 49709 Label: ProgressLabel, 49710 Track: ProgressTrack, 49711 ValueLabel: ProgressValueLabel 49712}); 49713
49714// src/viewer/spinner.jsx 49715var _tmpl$3 = /* @__PURE__ */ template(`<div class="progress__label-container">`); 49716var _tmpl$22 = /* @__PURE__ */ template(`<div class="progress__positioner">`); 49717var Spinner = (props) => { 49718 return createComponent(Dialog, { 49719 open: true, 49720 get children() { 49721 return createComponent(Dialog.Portal, { 49722 get mount() { 49723 return props.root; 49724 }, 49725 get children() { 49726 return [createComponent(Dialog.Overlay, { 49727 "class": "progress__overlay" 49728 }), (() => { 49729 const _el$ = _tmpl$22(); 49730 insert(_el$, createComponent(Dialog.Content, { 49731 "class": "progress__content", 49732 get children() { 49733 return createComponent(Progress, { 49734 indeterminate: true, 49735 "class": "progress", 49736 get children() { 49737 return [(() => { 49738 const _el$2 = _tmpl$3(); 49739 insert(_el$2, createComponent(Progress.Label, { 49740 "class": "progress__label", 49741 children: "Loading..." 49742 })); 49743 return _el$2; 49744 })(), createComponent(Progress.Track, { 49745 "class": "progress__track", 49746 get children() { 49747 return createComponent(Progress.Fill, { 49748 "class": "progress__fill" 49749 }); 49750 } 49751 })]; 49752 } 49753 }); 49754 } 49755 })); 49756 return _el$; 49757 })()]; 49758 } 49759 }); 49760 } 49761 }); 49762}; 49763
49764// src/viewer/alert.jsx 49765var _tmpl$4 = /* @__PURE__ */ template(`<div><div class="alert-dialog__overlay" data-expanded></div><div class="alert-dialog__positioner"><div class="alert-dialog__content" role="alertdialog" id="dialog-cl-3-content" tabindex="-1" data-expanded aria-labelledby="dialog-cl-3-title" aria-describedby="dialog-cl-3-description"><div class="alert-dialog__header"><h2 class="alert-dialog__title" id="dialog-cl-3-title">There's a problem</h2><button class="alert-dialog__close-button" aria-label="Dismiss" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59L7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12L5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z"></path></svg></button></div><p class="alert-dialog__description" id="dialog-cl-3-description">`); 49766var ErrorAlert = (props) => { 49767 const { 49768 problem, 49769 clearProblem 49770 } = useViewer(); 49771 return createComponent(Show, { 49772 get when() { 49773 return !!problem(); 49774 }, 49775 get children() { 49776 const _el$ = _tmpl$4(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$5.nextSibling; 49777 addEventListener(_el$7, "click", clearProblem, true); 49778 insert(_el$8, problem); 49779 return _el$; 49780 } 49781 }); 49782}; 49783delegateEvents(["click"]); 49784
49785// src/viewer/scenes.jsx 49786var _tmpl$5 = /* @__PURE__ */ template(`<div><select class="scene__select" aria-label="Scene">`); 49787var _tmpl$23 = /* @__PURE__ */ template(`<option>`); 49788var SceneMenu = (props) => { 49789 const { 49790 showTitledScene, 49791 sceneTitle, 49792 setSceneTitle, 49793 sceneTitles 49794 } = useSceneTitles(); 49795 const handleChange = (e) => { 49796 const title = e.target.value; 49797 setSceneTitle(title); 49798 showTitledScene(title); 49799 }; 49800 return createComponent(Show, { 49801 get when() { 49802 return sceneTitles().length > 1; 49803 }, 49804 get children() { 49805 const _el$ = _tmpl$5(), _el$2 = _el$.firstChild; 49806 _el$.style.setProperty("position", "absolute"); 49807 _el$.style.setProperty("top", "1em"); 49808 _el$.style.setProperty("left", "1em"); 49809 _el$2.addEventListener("change", handleChange); 49810 insert(_el$2, createComponent(For, { 49811 get each() { 49812 return sceneTitles(); 49813 }, 49814 children: (title) => (() => { 49815 const _el$3 = _tmpl$23(); 49816 _el$3.value = title; 49817 insert(_el$3, title); 49818 createRenderEffect(() => _el$3.selected = title === sceneTitle()); 49819 return _el$3; 49820 })() 49821 })); 49822 return _el$; 49823 } 49824 }); 49825}; 49826
vendor: 3,426 bytes, lines 49827-49951
49827// node_modules/@floating-ui/core/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs 49828var sides = ["top", "right", "bottom", "left"]; 49829var min3 = Math.min; 49830var max3 = Math.max; 49831var oppositeSideMap = { 49832 left: "right", 49833 right: "left", 49834 bottom: "top", 49835 top: "bottom" 49836}; 49837var oppositeAlignmentMap = { 49838 start: "end", 49839 end: "start" 49840}; 49841function clamp8(start, value, end) { 49842 return max3(start, min3(value, end)); 49843} 49844function evaluate(value, param) { 49845 return typeof value === "function" ? value(param) : value; 49846} 49847function getSide(placement) { 49848 return placement.split("-")[0]; 49849} 49850function getAlignment(placement) { 49851 return placement.split("-")[1]; 49852} 49853function getOppositeAxis(axis) { 49854 return axis === "x" ? "y" : "x"; 49855} 49856function getAxisLength(axis) { 49857 return axis === "y" ? "height" : "width"; 49858} 49859function getSideAxis(placement) { 49860 return ["top", "bottom"].includes(getSide(placement)) ? "y" : "x"; 49861} 49862function getAlignmentAxis(placement) { 49863 return getOppositeAxis(getSideAxis(placement)); 49864} 49865function getAlignmentSides(placement, rects, rtl) { 49866 if (rtl === void 0) { 49867 rtl = false; 49868 } 49869 const alignment = getAlignment(placement); 49870 const alignmentAxis = getAlignmentAxis(placement); 49871 const length3 = getAxisLength(alignmentAxis); 49872 let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top"; 49873 if (rects.reference[length3] > rects.floating[length3]) { 49874 mainAlignmentSide = getOppositePlacement(mainAlignmentSide); 49875 } 49876 return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)]; 49877} 49878function getExpandedPlacements(placement) { 49879 const oppositePlacement = getOppositePlacement(placement); 49880 return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)]; 49881} 49882function getOppositeAlignmentPlacement(placement) { 49883 return placement.replace(/start|end/g, (alignment) => oppositeAlignmentMap[alignment]); 49884} 49885function getSideList(side, isStart, rtl) { 49886 const lr = ["left", "right"]; 49887 const rl = ["right", "left"]; 49888 const tb = ["top", "bottom"]; 49889 const bt = ["bottom", "top"]; 49890 switch (side) { 49891 case "top": 49892 case "bottom": 49893 if (rtl) return isStart ? rl : lr; 49894 return isStart ? lr : rl; 49895 case "left": 49896 case "right": 49897 return isStart ? tb : bt; 49898 default: 49899 return []; 49900 } 49901} 49902function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) { 49903 const alignment = getAlignment(placement); 49904 let list = getSideList(getSide(placement), direction === "start", rtl); 49905 if (alignment) { 49906 list = list.map((side) => side + "-" + alignment); 49907 if (flipAlignment) { 49908 list = list.concat(list.map(getOppositeAlignmentPlacement)); 49909 } 49910 } 49911 return list; 49912} 49913function getOppositePlacement(placement) { 49914 return placement.replace(/left|right|bottom|top/g, (side) => oppositeSideMap[side]); 49915} 49916function expandPaddingObject(padding) { 49917 return { 49918 top: 0, 49919 right: 0, 49920 bottom: 0, 49921 left: 0, 49922 ...padding 49923 }; 49924} 49925function getPaddingObject(padding) { 49926 return typeof padding !== "number" ? expandPaddingObject(padding) : { 49927 top: padding, 49928 right: padding, 49929 bottom: padding, 49930 left: padding 49931 }; 49932} 49933function rectToClientRect(rect) { 49934 const { 49935 x, 49936 y, 49937 width, 49938 height 49939 } = rect; 49940 return { 49941 width, 49942 height, 49943 top: y, 49944 left: x, 49945 right: x + width, 49946 bottom: y + height, 49947 x, 49948 y 49949 }; 49950} 49951
vendor: 19,891 bytes, lines 49952-50575
49952// node_modules/@floating-ui/core/dist/floating-ui.core.mjs 49953function computeCoordsFromPlacement(_ref, placement, rtl) { 49954 let { 49955 reference: reference3, 49956 floating 49957 } = _ref; 49958 const sideAxis = getSideAxis(placement); 49959 const alignmentAxis = getAlignmentAxis(placement); 49960 const alignLength = getAxisLength(alignmentAxis); 49961 const side = getSide(placement); 49962 const isVertical = sideAxis === "y"; 49963 const commonX = reference3.x + reference3.width / 2 - floating.width / 2; 49964 const commonY = reference3.y + reference3.height / 2 - floating.height / 2; 49965 const commonAlign = reference3[alignLength] / 2 - floating[alignLength] / 2; 49966 let coords; 49967 switch (side) { 49968 case "top": 49969 coords = { 49970 x: commonX, 49971 y: reference3.y - floating.height 49972 }; 49973 break; 49974 case "bottom": 49975 coords = { 49976 x: commonX, 49977 y: reference3.y + reference3.height 49978 }; 49979 break; 49980 case "right": 49981 coords = { 49982 x: reference3.x + reference3.width, 49983 y: commonY 49984 }; 49985 break; 49986 case "left": 49987 coords = { 49988 x: reference3.x - floating.width, 49989 y: commonY 49990 }; 49991 break; 49992 default: 49993 coords = { 49994 x: reference3.x, 49995 y: reference3.y 49996 }; 49997 } 49998 switch (getAlignment(placement)) { 49999 case "start": 50000 coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1); 50001 break; 50002 case "end": 50003 coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1); 50004 break; 50005 } 50006 return coords; 50007} 50008var computePosition = async (reference3, floating, config) => { 50009 const { 50010 placement = "bottom", 50011 strategy = "absolute", 50012 middleware = [], 50013 platform: platform2 50014 } = config; 50015 const validMiddleware = middleware.filter(Boolean); 50016 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(floating)); 50017 let rects = await platform2.getElementRects({ 50018 reference: reference3, 50019 floating, 50020 strategy 50021 }); 50022 let { 50023 x, 50024 y 50025 } = computeCoordsFromPlacement(rects, placement, rtl); 50026 let statefulPlacement = placement; 50027 let middlewareData = {}; 50028 let resetCount = 0; 50029 for (let i = 0; i < validMiddleware.length; i++) { 50030 const { 50031 name, 50032 fn 50033 } = validMiddleware[i]; 50034 const { 50035 x: nextX, 50036 y: nextY, 50037 data, 50038 reset 50039 } = await fn({ 50040 x, 50041 y, 50042 initialPlacement: placement, 50043 placement: statefulPlacement, 50044 strategy, 50045 middlewareData, 50046 rects, 50047 platform: platform2, 50048 elements: { 50049 reference: reference3, 50050 floating 50051 } 50052 }); 50053 x = nextX != null ? nextX : x; 50054 y = nextY != null ? nextY : y; 50055 middlewareData = { 50056 ...middlewareData, 50057 [name]: { 50058 ...middlewareData[name], 50059 ...data 50060 } 50061 }; 50062 if (reset && resetCount <= 50) { 50063 resetCount++; 50064 if (typeof reset === "object") { 50065 if (reset.placement) { 50066 statefulPlacement = reset.placement; 50067 } 50068 if (reset.rects) { 50069 rects = reset.rects === true ? await platform2.getElementRects({ 50070 reference: reference3, 50071 floating, 50072 strategy 50073 }) : reset.rects; 50074 } 50075 ({ 50076 x, 50077 y 50078 } = computeCoordsFromPlacement(rects, statefulPlacement, rtl)); 50079 } 50080 i = -1; 50081 } 50082 } 50083 return { 50084 x, 50085 y, 50086 placement: statefulPlacement, 50087 strategy, 50088 middlewareData 50089 }; 50090}; 50091async function detectOverflow(state, options) { 50092 var _await$platform$isEle; 50093 if (options === void 0) { 50094 options = {}; 50095 } 50096 const { 50097 x, 50098 y, 50099 platform: platform2, 50100 rects, 50101 elements, 50102 strategy 50103 } = state; 50104 const { 50105 boundary = "clippingAncestors", 50106 rootBoundary = "viewport", 50107 elementContext = "floating", 50108 altBoundary = false, 50109 padding = 0 50110 } = evaluate(options, state); 50111 const paddingObject = getPaddingObject(padding); 50112 const altContext = elementContext === "floating" ? "reference" : "floating"; 50113 const element3 = elements[altBoundary ? altContext : elementContext]; 50114 const clippingClientRect = rectToClientRect(await platform2.getClippingRect({ 50115 element: ((_await$platform$isEle = await (platform2.isElement == null ? void 0 : platform2.isElement(element3))) != null ? _await$platform$isEle : true) ? element3 : element3.contextElement || await (platform2.getDocumentElement == null ? void 0 : platform2.getDocumentElement(elements.floating)), 50116 boundary, 50117 rootBoundary, 50118 strategy 50119 })); 50120 const rect = elementContext === "floating" ? { 50121 x, 50122 y, 50123 width: rects.floating.width, 50124 height: rects.floating.height 50125 } : rects.reference; 50126 const offsetParent = await (platform2.getOffsetParent == null ? void 0 : platform2.getOffsetParent(elements.floating)); 50127 const offsetScale = await (platform2.isElement == null ? void 0 : platform2.isElement(offsetParent)) ? await (platform2.getScale == null ? void 0 : platform2.getScale(offsetParent)) || { 50128 x: 1, 50129 y: 1 50130 } : { 50131 x: 1, 50132 y: 1 50133 }; 50134 const elementClientRect = rectToClientRect(platform2.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform2.convertOffsetParentRelativeRectToViewportRelativeRect({ 50135 elements, 50136 rect, 50137 offsetParent, 50138 strategy 50139 }) : rect); 50140 return { 50141 top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y, 50142 bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y, 50143 left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x, 50144 right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x 50145 }; 50146} 50147var arrow = (options) => ({ 50148 name: "arrow", 50149 options, 50150 async fn(state) { 50151 const { 50152 x, 50153 y, 50154 placement, 50155 rects, 50156 platform: platform2, 50157 elements, 50158 middlewareData 50159 } = state; 50160 const { 50161 element: element3, 50162 padding = 0 50163 } = evaluate(options, state) || {}; 50164 if (element3 == null) { 50165 return {}; 50166 } 50167 const paddingObject = getPaddingObject(padding); 50168 const coords = { 50169 x, 50170 y 50171 }; 50172 const axis = getAlignmentAxis(placement); 50173 const length3 = getAxisLength(axis); 50174 const arrowDimensions = await platform2.getDimensions(element3); 50175 const isYAxis = axis === "y"; 50176 const minProp = isYAxis ? "top" : "left"; 50177 const maxProp = isYAxis ? "bottom" : "right"; 50178 const clientProp = isYAxis ? "clientHeight" : "clientWidth"; 50179 const endDiff = rects.reference[length3] + rects.reference[axis] - coords[axis] - rects.floating[length3]; 50180 const startDiff = coords[axis] - rects.reference[axis]; 50181 const arrowOffsetParent = await (platform2.getOffsetParent == null ? void 0 : platform2.getOffsetParent(element3)); 50182 let clientSize = arrowOffsetParent ? arrowOffsetParent[clientProp] : 0; 50183 if (!clientSize || !await (platform2.isElement == null ? void 0 : platform2.isElement(arrowOffsetParent))) { 50184 clientSize = elements.floating[clientProp] || rects.floating[length3]; 50185 } 50186 const centerToReference = endDiff / 2 - startDiff / 2; 50187 const largestPossiblePadding = clientSize / 2 - arrowDimensions[length3] / 2 - 1; 50188 const minPadding = min3(paddingObject[minProp], largestPossiblePadding); 50189 const maxPadding = min3(paddingObject[maxProp], largestPossiblePadding); 50190 const min$12 = minPadding; 50191 const max5 = clientSize - arrowDimensions[length3] - maxPadding; 50192 const center = clientSize / 2 - arrowDimensions[length3] / 2 + centerToReference; 50193 const offset3 = clamp8(min$12, center, max5); 50194 const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset3 && rects.reference[length3] / 2 - (center < min$12 ? minPadding : maxPadding) - arrowDimensions[length3] / 2 < 0; 50195 const alignmentOffset = shouldAddOffset ? center < min$12 ? center - min$12 : center - max5 : 0; 50196 return { 50197 [axis]: coords[axis] + alignmentOffset, 50198 data: { 50199 [axis]: offset3, 50200 centerOffset: center - offset3 - alignmentOffset, 50201 ...shouldAddOffset && { 50202 alignmentOffset 50203 } 50204 }, 50205 reset: shouldAddOffset 50206 }; 50207 } 50208}); 50209var flip = function(options) { 50210 if (options === void 0) { 50211 options = {}; 50212 } 50213 return { 50214 name: "flip", 50215 options, 50216 async fn(state) { 50217 var _middlewareData$arrow, _middlewareData$flip; 50218 const { 50219 placement, 50220 middlewareData, 50221 rects, 50222 initialPlacement, 50223 platform: platform2, 50224 elements 50225 } = state; 50226 const { 50227 mainAxis: checkMainAxis = true, 50228 crossAxis: checkCrossAxis = true, 50229 fallbackPlacements: specifiedFallbackPlacements, 50230 fallbackStrategy = "bestFit", 50231 fallbackAxisSideDirection = "none", 50232 flipAlignment = true, 50233 ...detectOverflowOptions 50234 } = evaluate(options, state); 50235 if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) { 50236 return {}; 50237 } 50238 const side = getSide(placement); 50239 const isBasePlacement = getSide(initialPlacement) === initialPlacement; 50240 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)); 50241 const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement)); 50242 if (!specifiedFallbackPlacements && fallbackAxisSideDirection !== "none") { 50243 fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl)); 50244 } 50245 const placements2 = [initialPlacement, ...fallbackPlacements]; 50246 const overflow = await detectOverflow(state, detectOverflowOptions); 50247 const overflows = []; 50248 let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || []; 50249 if (checkMainAxis) { 50250 overflows.push(overflow[side]); 50251 } 50252 if (checkCrossAxis) { 50253 const sides2 = getAlignmentSides(placement, rects, rtl); 50254 overflows.push(overflow[sides2[0]], overflow[sides2[1]]); 50255 } 50256 overflowsData = [...overflowsData, { 50257 placement, 50258 overflows 50259 }]; 50260 if (!overflows.every((side2) => side2 <= 0)) { 50261 var _middlewareData$flip2, _overflowsData$filter; 50262 const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1; 50263 const nextPlacement = placements2[nextIndex]; 50264 if (nextPlacement) { 50265 return { 50266 data: { 50267 index: nextIndex, 50268 overflows: overflowsData 50269 }, 50270 reset: { 50271 placement: nextPlacement 50272 } 50273 }; 50274 } 50275 let resetPlacement = (_overflowsData$filter = overflowsData.filter((d) => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement; 50276 if (!resetPlacement) { 50277 switch (fallbackStrategy) { 50278 case "bestFit": { 50279 var _overflowsData$map$so; 50280 const placement2 = (_overflowsData$map$so = overflowsData.map((d) => [d.placement, d.overflows.filter((overflow2) => overflow2 > 0).reduce((acc, overflow2) => acc + overflow2, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$map$so[0]; 50281 if (placement2) { 50282 resetPlacement = placement2; 50283 } 50284 break; 50285 } 50286 case "initialPlacement": 50287 resetPlacement = initialPlacement; 50288 break; 50289 } 50290 } 50291 if (placement !== resetPlacement) { 50292 return { 50293 reset: { 50294 placement: resetPlacement 50295 } 50296 }; 50297 } 50298 } 50299 return {}; 50300 } 50301 }; 50302}; 50303function getSideOffsets(overflow, rect) { 50304 return { 50305 top: overflow.top - rect.height, 50306 right: overflow.right - rect.width, 50307 bottom: overflow.bottom - rect.height, 50308 left: overflow.left - rect.width 50309 }; 50310} 50311function isAnySideFullyClipped(overflow) { 50312 return sides.some((side) => overflow[side] >= 0); 50313} 50314var hide = function(options) { 50315 if (options === void 0) { 50316 options = {}; 50317 } 50318 return { 50319 name: "hide", 50320 options, 50321 async fn(state) { 50322 const { 50323 rects 50324 } = state; 50325 const { 50326 strategy = "referenceHidden", 50327 ...detectOverflowOptions 50328 } = evaluate(options, state); 50329 switch (strategy) { 50330 case "referenceHidden": { 50331 const overflow = await detectOverflow(state, { 50332 ...detectOverflowOptions, 50333 elementContext: "reference" 50334 }); 50335 const offsets = getSideOffsets(overflow, rects.reference); 50336 return { 50337 data: { 50338 referenceHiddenOffsets: offsets, 50339 referenceHidden: isAnySideFullyClipped(offsets) 50340 } 50341 }; 50342 } 50343 case "escaped": { 50344 const overflow = await detectOverflow(state, { 50345 ...detectOverflowOptions, 50346 altBoundary: true 50347 }); 50348 const offsets = getSideOffsets(overflow, rects.floating); 50349 return { 50350 data: { 50351 escapedOffsets: offsets, 50352 escaped: isAnySideFullyClipped(offsets) 50353 } 50354 }; 50355 } 50356 default: { 50357 return {}; 50358 } 50359 } 50360 } 50361 }; 50362}; 50363async function convertValueToCoords(state, options) { 50364 const { 50365 placement, 50366 platform: platform2, 50367 elements 50368 } = state; 50369 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)); 50370 const side = getSide(placement); 50371 const alignment = getAlignment(placement); 50372 const isVertical = getSideAxis(placement) === "y"; 50373 const mainAxisMulti = ["left", "top"].includes(side) ? -1 : 1; 50374 const crossAxisMulti = rtl && isVertical ? -1 : 1; 50375 const rawValue = evaluate(options, state); 50376 let { 50377 mainAxis, 50378 crossAxis, 50379 alignmentAxis 50380 } = typeof rawValue === "number" ? { 50381 mainAxis: rawValue, 50382 crossAxis: 0, 50383 alignmentAxis: null 50384 } : { 50385 mainAxis: 0, 50386 crossAxis: 0, 50387 alignmentAxis: null, 50388 ...rawValue 50389 }; 50390 if (alignment && typeof alignmentAxis === "number") { 50391 crossAxis = alignment === "end" ? alignmentAxis * -1 : alignmentAxis; 50392 } 50393 return isVertical ? { 50394 x: crossAxis * crossAxisMulti, 50395 y: mainAxis * mainAxisMulti 50396 } : { 50397 x: mainAxis * mainAxisMulti, 50398 y: crossAxis * crossAxisMulti 50399 }; 50400} 50401var offset = function(options) { 50402 if (options === void 0) { 50403 options = 0; 50404 } 50405 return { 50406 name: "offset", 50407 options, 50408 async fn(state) { 50409 var _middlewareData$offse, _middlewareData$arrow; 50410 const { 50411 x, 50412 y, 50413 placement, 50414 middlewareData 50415 } = state; 50416 const diffCoords = await convertValueToCoords(state, options); 50417 if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) { 50418 return {}; 50419 } 50420 return { 50421 x: x + diffCoords.x, 50422 y: y + diffCoords.y, 50423 data: { 50424 ...diffCoords, 50425 placement 50426 } 50427 }; 50428 } 50429 }; 50430}; 50431var shift = function(options) { 50432 if (options === void 0) { 50433 options = {}; 50434 } 50435 return { 50436 name: "shift", 50437 options, 50438 async fn(state) { 50439 const { 50440 x, 50441 y, 50442 placement 50443 } = state; 50444 const { 50445 mainAxis: checkMainAxis = true, 50446 crossAxis: checkCrossAxis = false, 50447 limiter = { 50448 fn: (_ref) => { 50449 let { 50450 x: x2, 50451 y: y2 50452 } = _ref; 50453 return { 50454 x: x2, 50455 y: y2 50456 }; 50457 } 50458 }, 50459 ...detectOverflowOptions 50460 } = evaluate(options, state); 50461 const coords = { 50462 x, 50463 y 50464 }; 50465 const overflow = await detectOverflow(state, detectOverflowOptions); 50466 const crossAxis = getSideAxis(getSide(placement)); 50467 const mainAxis = getOppositeAxis(crossAxis); 50468 let mainAxisCoord = coords[mainAxis]; 50469 let crossAxisCoord = coords[crossAxis]; 50470 if (checkMainAxis) { 50471 const minSide = mainAxis === "y" ? "top" : "left"; 50472 const maxSide = mainAxis === "y" ? "bottom" : "right"; 50473 const min5 = mainAxisCoord + overflow[minSide]; 50474 const max5 = mainAxisCoord - overflow[maxSide]; 50475 mainAxisCoord = clamp8(min5, mainAxisCoord, max5); 50476 } 50477 if (checkCrossAxis) { 50478 const minSide = crossAxis === "y" ? "top" : "left"; 50479 const maxSide = crossAxis === "y" ? "bottom" : "right"; 50480 const min5 = crossAxisCoord + overflow[minSide]; 50481 const max5 = crossAxisCoord - overflow[maxSide]; 50482 crossAxisCoord = clamp8(min5, crossAxisCoord, max5); 50483 } 50484 const limitedCoords = limiter.fn({ 50485 ...state, 50486 [mainAxis]: mainAxisCoord, 50487 [crossAxis]: crossAxisCoord 50488 }); 50489 return { 50490 ...limitedCoords, 50491 data: { 50492 x: limitedCoords.x - x, 50493 y: limitedCoords.y - y 50494 } 50495 }; 50496 } 50497 }; 50498}; 50499var size = function(options) { 50500 if (options === void 0) { 50501 options = {}; 50502 } 50503 return { 50504 name: "size", 50505 options, 50506 async fn(state) { 50507 const { 50508 placement, 50509 rects, 50510 platform: platform2, 50511 elements 50512 } = state; 50513 const { 50514 apply = () => { 50515 }, 50516 ...detectOverflowOptions 50517 } = evaluate(options, state); 50518 const overflow = await detectOverflow(state, detectOverflowOptions); 50519 const side = getSide(placement); 50520 const alignment = getAlignment(placement); 50521 const isYAxis = getSideAxis(placement) === "y"; 50522 const { 50523 width, 50524 height 50525 } = rects.floating; 50526 let heightSide; 50527 let widthSide; 50528 if (side === "top" || side === "bottom") { 50529 heightSide = side; 50530 widthSide = alignment === (await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)) ? "start" : "end") ? "left" : "right"; 50531 } else { 50532 widthSide = side; 50533 heightSide = alignment === "end" ? "top" : "bottom"; 50534 } 50535 const maximumClippingHeight = height - overflow.top - overflow.bottom; 50536 const maximumClippingWidth = width - overflow.left - overflow.right; 50537 const overflowAvailableHeight = min3(height - overflow[heightSide], maximumClippingHeight); 50538 const overflowAvailableWidth = min3(width - overflow[widthSide], maximumClippingWidth); 50539 const noShift = !state.middlewareData.shift; 50540 let availableHeight = overflowAvailableHeight; 50541 let availableWidth = overflowAvailableWidth; 50542 if (isYAxis) { 50543 availableWidth = alignment || noShift ? min3(overflowAvailableWidth, maximumClippingWidth) : maximumClippingWidth; 50544 } else { 50545 availableHeight = alignment || noShift ? min3(overflowAvailableHeight, maximumClippingHeight) : maximumClippingHeight; 50546 } 50547 if (noShift && !alignment) { 50548 const xMin = max3(overflow.left, 0); 50549 const xMax = max3(overflow.right, 0); 50550 const yMin = max3(overflow.top, 0); 50551 const yMax = max3(overflow.bottom, 0); 50552 if (isYAxis) { 50553 availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max3(overflow.left, overflow.right)); 50554 } else { 50555 availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max3(overflow.top, overflow.bottom)); 50556 } 50557 } 50558 await apply({ 50559 ...state, 50560 availableWidth, 50561 availableHeight 50562 }); 50563 const nextDimensions = await platform2.getDimensions(elements.floating); 50564 if (width !== nextDimensions.width || height !== nextDimensions.height) { 50565 return { 50566 reset: { 50567 rects: true 50568 } 50569 }; 50570 } 50571 return {}; 50572 } 50573 }; 50574}; 50575
vendor: 233 bytes, lines 50576-50585
50576// node_modules/@floating-ui/dom/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs 50577var min4 = Math.min; 50578var max4 = Math.max; 50579var round3 = Math.round; 50580var floor3 = Math.floor; 50581var createCoords = (v) => ({ 50582 x: v, 50583 y: v 50584}); 50585
vendor: 4,506 bytes, lines 50586-50704
50586// node_modules/@floating-ui/dom/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs 50587function getNodeName(node) { 50588 if (isNode(node)) { 50589 return (node.nodeName || "").toLowerCase(); 50590 } 50591 return "#document"; 50592} 50593function getWindow2(node) { 50594 var _node$ownerDocument; 50595 return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window; 50596} 50597function getDocumentElement(node) { 50598 var _ref; 50599 return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement; 50600} 50601function isNode(value) { 50602 return value instanceof Node || value instanceof getWindow2(value).Node; 50603} 50604function isElement(value) { 50605 return value instanceof Element || value instanceof getWindow2(value).Element; 50606} 50607function isHTMLElement(value) { 50608 return value instanceof HTMLElement || value instanceof getWindow2(value).HTMLElement; 50609} 50610function isShadowRoot(value) { 50611 if (typeof ShadowRoot === "undefined") { 50612 return false; 50613 } 50614 return value instanceof ShadowRoot || value instanceof getWindow2(value).ShadowRoot; 50615} 50616function isOverflowElement(element3) { 50617 const { 50618 overflow, 50619 overflowX, 50620 overflowY, 50621 display 50622 } = getComputedStyle2(element3); 50623 return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !["inline", "contents"].includes(display); 50624} 50625function isTableElement(element3) { 50626 return ["table", "td", "th"].includes(getNodeName(element3)); 50627} 50628function isContainingBlock(element3) { 50629 const webkit = isWebKit2(); 50630 const css = getComputedStyle2(element3); 50631 return css.transform !== "none" || css.perspective !== "none" || (css.containerType ? css.containerType !== "normal" : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !webkit && (css.filter ? css.filter !== "none" : false) || ["transform", "perspective", "filter"].some((value) => (css.willChange || "").includes(value)) || ["paint", "layout", "strict", "content"].some((value) => (css.contain || "").includes(value)); 50632} 50633function getContainingBlock(element3) { 50634 let currentNode = getParentNode(element3); 50635 while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) { 50636 if (isContainingBlock(currentNode)) { 50637 return currentNode; 50638 } 50639 currentNode = getParentNode(currentNode); 50640 } 50641 return null; 50642} 50643function isWebKit2() { 50644 if (typeof CSS === "undefined" || !CSS.supports) return false; 50645 return CSS.supports("-webkit-backdrop-filter", "none"); 50646} 50647function isLastTraversableNode(node) { 50648 return ["html", "body", "#document"].includes(getNodeName(node)); 50649} 50650function getComputedStyle2(element3) { 50651 return getWindow2(element3).getComputedStyle(element3); 50652} 50653function getNodeScroll(element3) { 50654 if (isElement(element3)) { 50655 return { 50656 scrollLeft: element3.scrollLeft, 50657 scrollTop: element3.scrollTop 50658 }; 50659 } 50660 return { 50661 scrollLeft: element3.pageXOffset, 50662 scrollTop: element3.pageYOffset 50663 }; 50664} 50665function getParentNode(node) { 50666 if (getNodeName(node) === "html") { 50667 return node; 50668 } 50669 const result = ( 50670 // Step into the shadow DOM of the parent of a slotted node. 50671 node.assignedSlot || // DOM Element detected. 50672 node.parentNode || // ShadowRoot detected. 50673 isShadowRoot(node) && node.host || // Fallback. 50674 getDocumentElement(node) 50675 ); 50676 return isShadowRoot(result) ? result.host : result; 50677} 50678function getNearestOverflowAncestor(node) { 50679 const parentNode = getParentNode(node); 50680 if (isLastTraversableNode(parentNode)) { 50681 return node.ownerDocument ? node.ownerDocument.body : node.body; 50682 } 50683 if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) { 50684 return parentNode; 50685 } 50686 return getNearestOverflowAncestor(parentNode); 50687} 50688function getOverflowAncestors(node, list, traverseIframes) { 50689 var _node$ownerDocument2; 50690 if (list === void 0) { 50691 list = []; 50692 } 50693 if (traverseIframes === void 0) { 50694 traverseIframes = true; 50695 } 50696 const scrollableAncestor = getNearestOverflowAncestor(node); 50697 const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body); 50698 const win = getWindow2(scrollableAncestor); 50699 if (isBody) { 50700 return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], win.frameElement && traverseIframes ? getOverflowAncestors(win.frameElement) : []); 50701 } 50702 return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes)); 50703} 50704
vendor: 18,898 bytes, lines 50705-51276
50705// node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs 50706function getCssDimensions(element3) { 50707 const css = getComputedStyle2(element3); 50708 let width = parseFloat(css.width) || 0; 50709 let height = parseFloat(css.height) || 0; 50710 const hasOffset = isHTMLElement(element3); 50711 const offsetWidth = hasOffset ? element3.offsetWidth : width; 50712 const offsetHeight = hasOffset ? element3.offsetHeight : height; 50713 const shouldFallback = round3(width) !== offsetWidth || round3(height) !== offsetHeight; 50714 if (shouldFallback) { 50715 width = offsetWidth; 50716 height = offsetHeight; 50717 } 50718 return { 50719 width, 50720 height, 50721 $: shouldFallback 50722 }; 50723} 50724function unwrapElement(element3) { 50725 return !isElement(element3) ? element3.contextElement : element3; 50726} 50727function getScale(element3) { 50728 const domElement = unwrapElement(element3); 50729 if (!isHTMLElement(domElement)) { 50730 return createCoords(1); 50731 } 50732 const rect = domElement.getBoundingClientRect(); 50733 const { 50734 width, 50735 height, 50736 $ 50737 } = getCssDimensions(domElement); 50738 let x = ($ ? round3(rect.width) : rect.width) / width; 50739 let y = ($ ? round3(rect.height) : rect.height) / height; 50740 if (!x || !Number.isFinite(x)) { 50741 x = 1; 50742 } 50743 if (!y || !Number.isFinite(y)) { 50744 y = 1; 50745 } 50746 return { 50747 x, 50748 y 50749 }; 50750} 50751var noOffsets = /* @__PURE__ */ createCoords(0); 50752function getVisualOffsets(element3) { 50753 const win = getWindow2(element3); 50754 if (!isWebKit2() || !win.visualViewport) { 50755 return noOffsets; 50756 } 50757 return { 50758 x: win.visualViewport.offsetLeft, 50759 y: win.visualViewport.offsetTop 50760 }; 50761} 50762function shouldAddVisualOffsets(element3, isFixed, floatingOffsetParent) { 50763 if (isFixed === void 0) { 50764 isFixed = false; 50765 } 50766 if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow2(element3)) { 50767 return false; 50768 } 50769 return isFixed; 50770} 50771function getBoundingClientRect(element3, includeScale, isFixedStrategy, offsetParent) { 50772 if (includeScale === void 0) { 50773 includeScale = false; 50774 } 50775 if (isFixedStrategy === void 0) { 50776 isFixedStrategy = false; 50777 } 50778 const clientRect = element3.getBoundingClientRect(); 50779 const domElement = unwrapElement(element3); 50780 let scale2 = createCoords(1); 50781 if (includeScale) { 50782 if (offsetParent) { 50783 if (isElement(offsetParent)) { 50784 scale2 = getScale(offsetParent); 50785 } 50786 } else { 50787 scale2 = getScale(element3); 50788 } 50789 } 50790 const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0); 50791 let x = (clientRect.left + visualOffsets.x) / scale2.x; 50792 let y = (clientRect.top + visualOffsets.y) / scale2.y; 50793 let width = clientRect.width / scale2.x; 50794 let height = clientRect.height / scale2.y; 50795 if (domElement) { 50796 const win = getWindow2(domElement); 50797 const offsetWin = offsetParent && isElement(offsetParent) ? getWindow2(offsetParent) : offsetParent; 50798 let currentWin = win; 50799 let currentIFrame = currentWin.frameElement; 50800 while (currentIFrame && offsetParent && offsetWin !== currentWin) { 50801 const iframeScale = getScale(currentIFrame); 50802 const iframeRect = currentIFrame.getBoundingClientRect(); 50803 const css = getComputedStyle2(currentIFrame); 50804 const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x; 50805 const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y; 50806 x *= iframeScale.x; 50807 y *= iframeScale.y; 50808 width *= iframeScale.x; 50809 height *= iframeScale.y; 50810 x += left; 50811 y += top; 50812 currentWin = getWindow2(currentIFrame); 50813 currentIFrame = currentWin.frameElement; 50814 } 50815 } 50816 return rectToClientRect({ 50817 width, 50818 height, 50819 x, 50820 y 50821 }); 50822} 50823var topLayerSelectors = [":popover-open", ":modal"]; 50824function isTopLayer(element3) { 50825 return topLayerSelectors.some((selector) => { 50826 try { 50827 return element3.matches(selector); 50828 } catch (e) { 50829 return false; 50830 } 50831 }); 50832} 50833function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) { 50834 let { 50835 elements, 50836 rect, 50837 offsetParent, 50838 strategy 50839 } = _ref; 50840 const isFixed = strategy === "fixed"; 50841 const documentElement = getDocumentElement(offsetParent); 50842 const topLayer = elements ? isTopLayer(elements.floating) : false; 50843 if (offsetParent === documentElement || topLayer && isFixed) { 50844 return rect; 50845 } 50846 let scroll = { 50847 scrollLeft: 0, 50848 scrollTop: 0 50849 }; 50850 let scale2 = createCoords(1); 50851 const offsets = createCoords(0); 50852 const isOffsetParentAnElement = isHTMLElement(offsetParent); 50853 if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { 50854 if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) { 50855 scroll = getNodeScroll(offsetParent); 50856 } 50857 if (isHTMLElement(offsetParent)) { 50858 const offsetRect = getBoundingClientRect(offsetParent); 50859 scale2 = getScale(offsetParent); 50860 offsets.x = offsetRect.x + offsetParent.clientLeft; 50861 offsets.y = offsetRect.y + offsetParent.clientTop; 50862 } 50863 } 50864 return { 50865 width: rect.width * scale2.x, 50866 height: rect.height * scale2.y, 50867 x: rect.x * scale2.x - scroll.scrollLeft * scale2.x + offsets.x, 50868 y: rect.y * scale2.y - scroll.scrollTop * scale2.y + offsets.y 50869 }; 50870} 50871function getClientRects(element3) { 50872 return Array.from(element3.getClientRects()); 50873} 50874function getWindowScrollBarX(element3) { 50875 return getBoundingClientRect(getDocumentElement(element3)).left + getNodeScroll(element3).scrollLeft; 50876} 50877function getDocumentRect(element3) { 50878 const html = getDocumentElement(element3); 50879 const scroll = getNodeScroll(element3); 50880 const body = element3.ownerDocument.body; 50881 const width = max4(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth); 50882 const height = max4(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight); 50883 let x = -scroll.scrollLeft + getWindowScrollBarX(element3); 50884 const y = -scroll.scrollTop; 50885 if (getComputedStyle2(body).direction === "rtl") { 50886 x += max4(html.clientWidth, body.clientWidth) - width; 50887 } 50888 return { 50889 width, 50890 height, 50891 x, 50892 y 50893 }; 50894} 50895function getViewportRect(element3, strategy) { 50896 const win = getWindow2(element3); 50897 const html = getDocumentElement(element3); 50898 const visualViewport = win.visualViewport; 50899 let width = html.clientWidth; 50900 let height = html.clientHeight; 50901 let x = 0; 50902 let y = 0; 50903 if (visualViewport) { 50904 width = visualViewport.width; 50905 height = visualViewport.height; 50906 const visualViewportBased = isWebKit2(); 50907 if (!visualViewportBased || visualViewportBased && strategy === "fixed") { 50908 x = visualViewport.offsetLeft; 50909 y = visualViewport.offsetTop; 50910 } 50911 } 50912 return { 50913 width, 50914 height, 50915 x, 50916 y 50917 }; 50918} 50919function getInnerBoundingClientRect(element3, strategy) { 50920 const clientRect = getBoundingClientRect(element3, true, strategy === "fixed"); 50921 const top = clientRect.top + element3.clientTop; 50922 const left = clientRect.left + element3.clientLeft; 50923 const scale2 = isHTMLElement(element3) ? getScale(element3) : createCoords(1); 50924 const width = element3.clientWidth * scale2.x; 50925 const height = element3.clientHeight * scale2.y; 50926 const x = left * scale2.x; 50927 const y = top * scale2.y; 50928 return { 50929 width, 50930 height, 50931 x, 50932 y 50933 }; 50934} 50935function getClientRectFromClippingAncestor(element3, clippingAncestor, strategy) { 50936 let rect; 50937 if (clippingAncestor === "viewport") { 50938 rect = getViewportRect(element3, strategy); 50939 } else if (clippingAncestor === "document") { 50940 rect = getDocumentRect(getDocumentElement(element3)); 50941 } else if (isElement(clippingAncestor)) { 50942 rect = getInnerBoundingClientRect(clippingAncestor, strategy); 50943 } else { 50944 const visualOffsets = getVisualOffsets(element3); 50945 rect = { 50946 ...clippingAncestor, 50947 x: clippingAncestor.x - visualOffsets.x, 50948 y: clippingAncestor.y - visualOffsets.y 50949 }; 50950 } 50951 return rectToClientRect(rect); 50952} 50953function hasFixedPositionAncestor(element3, stopNode) { 50954 const parentNode = getParentNode(element3); 50955 if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) { 50956 return false; 50957 } 50958 return getComputedStyle2(parentNode).position === "fixed" || hasFixedPositionAncestor(parentNode, stopNode); 50959} 50960function getClippingElementAncestors(element3, cache4) { 50961 const cachedResult = cache4.get(element3); 50962 if (cachedResult) { 50963 return cachedResult; 50964 } 50965 let result = getOverflowAncestors(element3, [], false).filter((el) => isElement(el) && getNodeName(el) !== "body"); 50966 let currentContainingBlockComputedStyle = null; 50967 const elementIsFixed = getComputedStyle2(element3).position === "fixed"; 50968 let currentNode = elementIsFixed ? getParentNode(element3) : element3; 50969 while (isElement(currentNode) && !isLastTraversableNode(currentNode)) { 50970 const computedStyle = getComputedStyle2(currentNode); 50971 const currentNodeIsContaining = isContainingBlock(currentNode); 50972 if (!currentNodeIsContaining && computedStyle.position === "fixed") { 50973 currentContainingBlockComputedStyle = null; 50974 } 50975 const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === "static" && !!currentContainingBlockComputedStyle && ["absolute", "fixed"].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element3, currentNode); 50976 if (shouldDropCurrentNode) { 50977 result = result.filter((ancestor) => ancestor !== currentNode); 50978 } else { 50979 currentContainingBlockComputedStyle = computedStyle; 50980 } 50981 currentNode = getParentNode(currentNode); 50982 } 50983 cache4.set(element3, result); 50984 return result; 50985} 50986function getClippingRect(_ref) { 50987 let { 50988 element: element3, 50989 boundary, 50990 rootBoundary, 50991 strategy 50992 } = _ref; 50993 const elementClippingAncestors = boundary === "clippingAncestors" ? isTopLayer(element3) ? [] : getClippingElementAncestors(element3, this._c) : [].concat(boundary); 50994 const clippingAncestors = [...elementClippingAncestors, rootBoundary]; 50995 const firstClippingAncestor = clippingAncestors[0]; 50996 const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => { 50997 const rect = getClientRectFromClippingAncestor(element3, clippingAncestor, strategy); 50998 accRect.top = max4(rect.top, accRect.top); 50999 accRect.right = min4(rect.right, accRect.right); 51000 accRect.bottom = min4(rect.bottom, accRect.bottom); 51001 accRect.left = max4(rect.left, accRect.left); 51002 return accRect; 51003 }, getClientRectFromClippingAncestor(element3, firstClippingAncestor, strategy)); 51004 return { 51005 width: clippingRect.right - clippingRect.left, 51006 height: clippingRect.bottom - clippingRect.top, 51007 x: clippingRect.left, 51008 y: clippingRect.top 51009 }; 51010} 51011function getDimensions(element3) { 51012 const { 51013 width, 51014 height 51015 } = getCssDimensions(element3); 51016 return { 51017 width, 51018 height 51019 }; 51020} 51021function getRectRelativeToOffsetParent(element3, offsetParent, strategy) { 51022 const isOffsetParentAnElement = isHTMLElement(offsetParent); 51023 const documentElement = getDocumentElement(offsetParent); 51024 const isFixed = strategy === "fixed"; 51025 const rect = getBoundingClientRect(element3, true, isFixed, offsetParent); 51026 let scroll = { 51027 scrollLeft: 0, 51028 scrollTop: 0 51029 }; 51030 const offsets = createCoords(0); 51031 if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { 51032 if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) { 51033 scroll = getNodeScroll(offsetParent); 51034 } 51035 if (isOffsetParentAnElement) { 51036 const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent); 51037 offsets.x = offsetRect.x + offsetParent.clientLeft; 51038 offsets.y = offsetRect.y + offsetParent.clientTop; 51039 } else if (documentElement) { 51040 offsets.x = getWindowScrollBarX(documentElement); 51041 } 51042 } 51043 const x = rect.left + scroll.scrollLeft - offsets.x; 51044 const y = rect.top + scroll.scrollTop - offsets.y; 51045 return { 51046 x, 51047 y, 51048 width: rect.width, 51049 height: rect.height 51050 }; 51051} 51052function isStaticPositioned(element3) { 51053 return getComputedStyle2(element3).position === "static"; 51054} 51055function getTrueOffsetParent(element3, polyfill) { 51056 if (!isHTMLElement(element3) || getComputedStyle2(element3).position === "fixed") { 51057 return null; 51058 } 51059 if (polyfill) { 51060 return polyfill(element3); 51061 } 51062 return element3.offsetParent; 51063} 51064function getOffsetParent(element3, polyfill) { 51065 const win = getWindow2(element3); 51066 if (isTopLayer(element3)) { 51067 return win; 51068 } 51069 if (!isHTMLElement(element3)) { 51070 let svgOffsetParent = getParentNode(element3); 51071 while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) { 51072 if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) { 51073 return svgOffsetParent; 51074 } 51075 svgOffsetParent = getParentNode(svgOffsetParent); 51076 } 51077 return win; 51078 } 51079 let offsetParent = getTrueOffsetParent(element3, polyfill); 51080 while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) { 51081 offsetParent = getTrueOffsetParent(offsetParent, polyfill); 51082 } 51083 if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) { 51084 return win; 51085 } 51086 return offsetParent || getContainingBlock(element3) || win; 51087} 51088var getElementRects = async function(data) { 51089 const getOffsetParentFn = this.getOffsetParent || getOffsetParent; 51090 const getDimensionsFn = this.getDimensions; 51091 const floatingDimensions = await getDimensionsFn(data.floating); 51092 return { 51093 reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy), 51094 floating: { 51095 x: 0, 51096 y: 0, 51097 width: floatingDimensions.width, 51098 height: floatingDimensions.height 51099 } 51100 }; 51101}; 51102function isRTL2(element3) { 51103 return getComputedStyle2(element3).direction === "rtl"; 51104} 51105var platform = { 51106 convertOffsetParentRelativeRectToViewportRelativeRect, 51107 getDocumentElement, 51108 getClippingRect, 51109 getOffsetParent, 51110 getElementRects, 51111 getClientRects, 51112 getDimensions, 51113 getScale, 51114 isElement, 51115 isRTL: isRTL2 51116}; 51117function observeMove(element3, onMove) { 51118 let io = null; 51119 let timeoutId; 51120 const root = getDocumentElement(element3); 51121 function cleanup() { 51122 var _io; 51123 clearTimeout(timeoutId); 51124 (_io = io) == null || _io.disconnect(); 51125 io = null; 51126 } 51127 function refresh(skip, threshold) { 51128 if (skip === void 0) { 51129 skip = false; 51130 } 51131 if (threshold === void 0) { 51132 threshold = 1; 51133 } 51134 cleanup(); 51135 const { 51136 left, 51137 top, 51138 width, 51139 height 51140 } = element3.getBoundingClientRect(); 51141 if (!skip) { 51142 onMove(); 51143 } 51144 if (!width || !height) { 51145 return; 51146 } 51147 const insetTop = floor3(top); 51148 const insetRight = floor3(root.clientWidth - (left + width)); 51149 const insetBottom = floor3(root.clientHeight - (top + height)); 51150 const insetLeft = floor3(left); 51151 const rootMargin = -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px"; 51152 const options = { 51153 rootMargin, 51154 threshold: max4(0, min4(1, threshold)) || 1 51155 }; 51156 let isFirstUpdate = true; 51157 function handleObserve(entries5) { 51158 const ratio = entries5[0].intersectionRatio; 51159 if (ratio !== threshold) { 51160 if (!isFirstUpdate) { 51161 return refresh(); 51162 } 51163 if (!ratio) { 51164 timeoutId = setTimeout(() => { 51165 refresh(false, 1e-7); 51166 }, 1e3); 51167 } else { 51168 refresh(false, ratio); 51169 } 51170 } 51171 isFirstUpdate = false; 51172 } 51173 try { 51174 io = new IntersectionObserver(handleObserve, { 51175 ...options, 51176 // Handle <iframe>s 51177 root: root.ownerDocument 51178 }); 51179 } catch (e) { 51180 io = new IntersectionObserver(handleObserve, options); 51181 } 51182 io.observe(element3); 51183 } 51184 refresh(true); 51185 return cleanup; 51186} 51187function autoUpdate(reference3, floating, update, options) { 51188 if (options === void 0) { 51189 options = {}; 51190 } 51191 const { 51192 ancestorScroll = true, 51193 ancestorResize = true, 51194 elementResize = typeof ResizeObserver === "function", 51195 layoutShift = typeof IntersectionObserver === "function", 51196 animationFrame = false 51197 } = options; 51198 const referenceEl = unwrapElement(reference3); 51199 const ancestors = ancestorScroll || ancestorResize ? [...referenceEl ? getOverflowAncestors(referenceEl) : [], ...getOverflowAncestors(floating)] : []; 51200 ancestors.forEach((ancestor) => { 51201 ancestorScroll && ancestor.addEventListener("scroll", update, { 51202 passive: true 51203 }); 51204 ancestorResize && ancestor.addEventListener("resize", update); 51205 }); 51206 const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update) : null; 51207 let reobserveFrame = -1; 51208 let resizeObserver = null; 51209 if (elementResize) { 51210 resizeObserver = new ResizeObserver((_ref) => { 51211 let [firstEntry] = _ref; 51212 if (firstEntry && firstEntry.target === referenceEl && resizeObserver) { 51213 resizeObserver.unobserve(floating); 51214 cancelAnimationFrame(reobserveFrame); 51215 reobserveFrame = requestAnimationFrame(() => { 51216 var _resizeObserver; 51217 (_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating); 51218 }); 51219 } 51220 update(); 51221 }); 51222 if (referenceEl && !animationFrame) { 51223 resizeObserver.observe(referenceEl); 51224 } 51225 resizeObserver.observe(floating); 51226 } 51227 let frameId3; 51228 let prevRefRect = animationFrame ? getBoundingClientRect(reference3) : null; 51229 if (animationFrame) { 51230 frameLoop(); 51231 } 51232 function frameLoop() { 51233 const nextRefRect = getBoundingClientRect(reference3); 51234 if (prevRefRect && (nextRefRect.x !== prevRefRect.x || nextRefRect.y !== prevRefRect.y || nextRefRect.width !== prevRefRect.width || nextRefRect.height !== prevRefRect.height)) { 51235 update(); 51236 } 51237 prevRefRect = nextRefRect; 51238 frameId3 = requestAnimationFrame(frameLoop); 51239 } 51240 update(); 51241 return () => { 51242 var _resizeObserver2; 51243 ancestors.forEach((ancestor) => { 51244 ancestorScroll && ancestor.removeEventListener("scroll", update); 51245 ancestorResize && ancestor.removeEventListener("resize", update); 51246 }); 51247 cleanupIo == null || cleanupIo(); 51248 (_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect(); 51249 resizeObserver = null; 51250 if (animationFrame) { 51251 cancelAnimationFrame(frameId3); 51252 } 51253 }; 51254} 51255var offset2 = offset; 51256var shift2 = shift; 51257var flip2 = flip; 51258var size2 = size; 51259var hide2 = hide; 51260var arrow2 = arrow; 51261var computePosition2 = (reference3, floating, options) => { 51262 const cache4 = /* @__PURE__ */ new Map(); 51263 const mergedOptions = { 51264 platform, 51265 ...options 51266 }; 51267 const platformWithCache = { 51268 ...mergedOptions.platform, 51269 _c: cache4 51270 }; 51271 return computePosition(reference3, floating, { 51272 ...mergedOptions, 51273 platform: platformWithCache 51274 }); 51275}; 51276
vendor: 10,639 bytes, lines 51277-51602
51277// node_modules/@kobalte/core/dist/chunk/BK63AFY4.js 51278var PopperContext = createContext(); 51279function usePopperContext() { 51280 const context3 = useContext(PopperContext); 51281 if (context3 === void 0) { 51282 throw new Error("[kobalte]: `usePopperContext` must be used within a `Popper` component"); 51283 } 51284 return context3; 51285} 51286var _tmpl$6 = /* @__PURE__ */ template(`<svg display="block" viewBox="0 0 30 30" style="transform:scale(1.02)"><g><path fill="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z"></path><path stroke="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z">`); 51287var DEFAULT_SIZE = 30; 51288var HALF_DEFAULT_SIZE = DEFAULT_SIZE / 2; 51289var ROTATION_DEG = { 51290 top: 180, 51291 right: -90, 51292 bottom: 0, 51293 left: 90 51294}; 51295function PopperArrow(props) { 51296 const context3 = usePopperContext(); 51297 const mergedProps = mergeDefaultProps({ 51298 size: DEFAULT_SIZE 51299 }, props); 51300 const [local, others] = splitProps(mergedProps, ["ref", "style", "size"]); 51301 const dir = () => context3.currentPlacement().split("-")[0]; 51302 const contentStyle = createComputedStyle(context3.contentRef); 51303 const fill = () => contentStyle()?.getPropertyValue("background-color") || "none"; 51304 const stroke = () => contentStyle()?.getPropertyValue(`border-${dir()}-color`) || "none"; 51305 const borderWidth = () => contentStyle()?.getPropertyValue(`border-${dir()}-width`) || "0px"; 51306 const strokeWidth = () => { 51307 return Number.parseInt(borderWidth()) * 2 * (DEFAULT_SIZE / local.size); 51308 }; 51309 const rotate3 = () => { 51310 return `rotate(${ROTATION_DEG[dir()]} ${HALF_DEFAULT_SIZE} ${HALF_DEFAULT_SIZE}) translate(0 2)`; 51311 }; 51312 return createComponent(Polymorphic, mergeProps({ 51313 as: "div", 51314 ref(r$) { 51315 const _ref$ = mergeRefs(context3.setArrowRef, local.ref); 51316 typeof _ref$ === "function" && _ref$(r$); 51317 }, 51318 "aria-hidden": "true", 51319 get style() { 51320 return combineStyle({ 51321 // server side rendering 51322 position: "absolute", 51323 "font-size": `${local.size}px`, 51324 width: "1em", 51325 height: "1em", 51326 "pointer-events": "none", 51327 fill: fill(), 51328 stroke: stroke(), 51329 "stroke-width": strokeWidth() 51330 }, local.style); 51331 } 51332 }, others, { 51333 get children() { 51334 const _el$ = _tmpl$6(), _el$2 = _el$.firstChild; 51335 createRenderEffect(() => setAttribute(_el$2, "transform", rotate3())); 51336 return _el$; 51337 } 51338 })); 51339} 51340function createComputedStyle(element3) { 51341 const [style2, setStyle] = createSignal(); 51342 createEffect(() => { 51343 const el = element3(); 51344 el && setStyle(getWindow(el).getComputedStyle(el)); 51345 }); 51346 return style2; 51347} 51348function PopperPositioner(props) { 51349 const context3 = usePopperContext(); 51350 const [local, others] = splitProps(props, ["ref", "style"]); 51351 return createComponent(Polymorphic, mergeProps({ 51352 as: "div", 51353 ref(r$) { 51354 const _ref$ = mergeRefs(context3.setPositionerRef, local.ref); 51355 typeof _ref$ === "function" && _ref$(r$); 51356 }, 51357 "data-popper-positioner": "", 51358 get style() { 51359 return combineStyle({ 51360 position: "absolute", 51361 top: 0, 51362 left: 0, 51363 "min-width": "max-content" 51364 }, local.style); 51365 } 51366 }, others)); 51367} 51368function createDOMRect(anchorRect) { 51369 const { x = 0, y = 0, width = 0, height = 0 } = anchorRect ?? {}; 51370 if (typeof DOMRect === "function") { 51371 return new DOMRect(x, y, width, height); 51372 } 51373 const rect = { 51374 x, 51375 y, 51376 width, 51377 height, 51378 top: y, 51379 right: x + width, 51380 bottom: y + height, 51381 left: x 51382 }; 51383 return { ...rect, toJSON: () => rect }; 51384} 51385function getAnchorElement(anchor, getAnchorRect) { 51386 const contextElement = anchor; 51387 return { 51388 contextElement, 51389 getBoundingClientRect: () => { 51390 const anchorRect = getAnchorRect(anchor); 51391 if (anchorRect) { 51392 return createDOMRect(anchorRect); 51393 } 51394 if (anchor) { 51395 return anchor.getBoundingClientRect(); 51396 } 51397 return createDOMRect(); 51398 } 51399 }; 51400} 51401function isValidPlacement(flip22) { 51402 return /^(?:top|bottom|left|right)(?:-(?:start|end))?$/.test(flip22); 51403} 51404var REVERSE_BASE_PLACEMENT = { 51405 top: "bottom", 51406 right: "left", 51407 bottom: "top", 51408 left: "right" 51409}; 51410function getTransformOrigin(placement, readingDirection) { 51411 const [basePlacement, alignment] = placement.split("-"); 51412 const reversePlacement = REVERSE_BASE_PLACEMENT[basePlacement]; 51413 if (!alignment) { 51414 return `${reversePlacement} center`; 51415 } 51416 if (basePlacement === "left" || basePlacement === "right") { 51417 return `${reversePlacement} ${alignment === "start" ? "top" : "bottom"}`; 51418 } 51419 if (alignment === "start") { 51420 return `${reversePlacement} ${readingDirection === "rtl" ? "right" : "left"}`; 51421 } 51422 return `${reversePlacement} ${readingDirection === "rtl" ? "left" : "right"}`; 51423} 51424function PopperRoot(props) { 51425 const mergedProps = mergeDefaultProps({ 51426 getAnchorRect: (anchor) => anchor?.getBoundingClientRect(), 51427 placement: "bottom", 51428 gutter: 0, 51429 shift: 0, 51430 flip: true, 51431 slide: true, 51432 overlap: false, 51433 sameWidth: false, 51434 fitViewport: false, 51435 hideWhenDetached: false, 51436 detachedPadding: 0, 51437 arrowPadding: 4, 51438 overflowPadding: 8 51439 }, props); 51440 const [positionerRef, setPositionerRef] = createSignal(); 51441 const [arrowRef, setArrowRef] = createSignal(); 51442 const [currentPlacement, setCurrentPlacement] = createSignal(mergedProps.placement); 51443 const anchorRef = () => getAnchorElement(mergedProps.anchorRef?.(), mergedProps.getAnchorRect); 51444 const { 51445 direction 51446 } = useLocale(); 51447 async function updatePosition() { 51448 const referenceEl = anchorRef(); 51449 const floatingEl = positionerRef(); 51450 const arrowEl = arrowRef(); 51451 if (!referenceEl || !floatingEl) { 51452 return; 51453 } 51454 const arrowOffset = (arrowEl?.clientHeight || 0) / 2; 51455 const finalGutter = typeof mergedProps.gutter === "number" ? mergedProps.gutter + arrowOffset : mergedProps.gutter ?? arrowOffset; 51456 floatingEl.style.setProperty("--kb-popper-content-overflow-padding", `${mergedProps.overflowPadding}px`); 51457 referenceEl.getBoundingClientRect(); 51458 const middleware = [ 51459 // https://floating-ui.com/docs/offset 51460 offset2(({ 51461 placement 51462 }) => { 51463 const hasAlignment = !!placement.split("-")[1]; 51464 return { 51465 mainAxis: finalGutter, 51466 crossAxis: !hasAlignment ? mergedProps.shift : void 0, 51467 alignmentAxis: mergedProps.shift 51468 }; 51469 }) 51470 ]; 51471 if (mergedProps.flip !== false) { 51472 const fallbackPlacements = typeof mergedProps.flip === "string" ? mergedProps.flip.split(" ") : void 0; 51473 if (fallbackPlacements !== void 0 && !fallbackPlacements.every(isValidPlacement)) { 51474 throw new Error("`flip` expects a spaced-delimited list of placements"); 51475 } 51476 middleware.push(flip2({ 51477 padding: mergedProps.overflowPadding, 51478 fallbackPlacements 51479 })); 51480 } 51481 if (mergedProps.slide || mergedProps.overlap) { 51482 middleware.push(shift2({ 51483 mainAxis: mergedProps.slide, 51484 crossAxis: mergedProps.overlap, 51485 padding: mergedProps.overflowPadding 51486 })); 51487 } 51488 middleware.push(size2({ 51489 padding: mergedProps.overflowPadding, 51490 apply({ 51491 availableWidth, 51492 availableHeight, 51493 rects 51494 }) { 51495 const referenceWidth = Math.round(rects.reference.width); 51496 availableWidth = Math.floor(availableWidth); 51497 availableHeight = Math.floor(availableHeight); 51498 floatingEl.style.setProperty("--kb-popper-anchor-width", `${referenceWidth}px`); 51499 floatingEl.style.setProperty("--kb-popper-content-available-width", `${availableWidth}px`); 51500 floatingEl.style.setProperty("--kb-popper-content-available-height", `${availableHeight}px`); 51501 if (mergedProps.sameWidth) { 51502 floatingEl.style.width = `${referenceWidth}px`; 51503 } 51504 if (mergedProps.fitViewport) { 51505 floatingEl.style.maxWidth = `${availableWidth}px`; 51506 floatingEl.style.maxHeight = `${availableHeight}px`; 51507 } 51508 } 51509 })); 51510 if (mergedProps.hideWhenDetached) { 51511 middleware.push(hide2({ 51512 padding: mergedProps.detachedPadding 51513 })); 51514 } 51515 if (arrowEl) { 51516 middleware.push(arrow2({ 51517 element: arrowEl, 51518 padding: mergedProps.arrowPadding 51519 })); 51520 } 51521 const pos = await computePosition2(referenceEl, floatingEl, { 51522 placement: mergedProps.placement, 51523 strategy: "absolute", 51524 middleware, 51525 platform: { 51526 ...platform, 51527 isRTL: () => direction() === "rtl" 51528 } 51529 }); 51530 setCurrentPlacement(pos.placement); 51531 mergedProps.onCurrentPlacementChange?.(pos.placement); 51532 if (!floatingEl) { 51533 return; 51534 } 51535 floatingEl.style.setProperty("--kb-popper-content-transform-origin", getTransformOrigin(pos.placement, direction())); 51536 const x = Math.round(pos.x); 51537 const y = Math.round(pos.y); 51538 let visibility; 51539 if (mergedProps.hideWhenDetached) { 51540 visibility = pos.middlewareData.hide?.referenceHidden ? "hidden" : "visible"; 51541 } 51542 Object.assign(floatingEl.style, { 51543 top: "0", 51544 left: "0", 51545 transform: `translate3d(${x}px, ${y}px, 0)`, 51546 visibility 51547 }); 51548 if (arrowEl && pos.middlewareData.arrow) { 51549 const { 51550 x: arrowX, 51551 y: arrowY 51552 } = pos.middlewareData.arrow; 51553 const dir = pos.placement.split("-")[0]; 51554 Object.assign(arrowEl.style, { 51555 left: arrowX != null ? `${arrowX}px` : "", 51556 top: arrowY != null ? `${arrowY}px` : "", 51557 [dir]: "100%" 51558 }); 51559 } 51560 } 51561 createEffect(() => { 51562 const referenceEl = anchorRef(); 51563 const floatingEl = positionerRef(); 51564 if (!referenceEl || !floatingEl) { 51565 return; 51566 } 51567 const cleanupAutoUpdate = autoUpdate(referenceEl, floatingEl, updatePosition, { 51568 // JSDOM doesn't support ResizeObserver 51569 elementResize: typeof ResizeObserver === "function" 51570 }); 51571 onCleanup(cleanupAutoUpdate); 51572 }); 51573 createEffect(() => { 51574 const positioner = positionerRef(); 51575 const content = mergedProps.contentRef?.(); 51576 if (!positioner || !content) { 51577 return; 51578 } 51579 queueMicrotask(() => { 51580 positioner.style.zIndex = getComputedStyle(content).zIndex; 51581 }); 51582 }); 51583 const context3 = { 51584 currentPlacement, 51585 contentRef: () => mergedProps.contentRef?.(), 51586 setPositionerRef, 51587 setArrowRef 51588 }; 51589 return createComponent(PopperContext.Provider, { 51590 value: context3, 51591 get children() { 51592 return mergedProps.children; 51593 } 51594 }); 51595} 51596var Popper = Object.assign(PopperRoot, { 51597 Arrow: PopperArrow, 51598 Context: PopperContext, 51599 usePopperContext, 51600 Positioner: PopperPositioner 51601}); 51602
vendor: 13,865 bytes, lines 51603-52054
51603// node_modules/@kobalte/core/dist/chunk/PKWJSNR5.js 51604var tooltip_exports = {}; 51605__export(tooltip_exports, { 51606 Arrow: () => PopperArrow, 51607 Content: () => TooltipContent, 51608 Portal: () => TooltipPortal, 51609 Root: () => TooltipRoot, 51610 Tooltip: () => Tooltip, 51611 Trigger: () => TooltipTrigger, 51612 useTooltipContext: () => useTooltipContext 51613}); 51614var TooltipContext = createContext(); 51615function useTooltipContext() { 51616 const context3 = useContext(TooltipContext); 51617 if (context3 === void 0) { 51618 throw new Error("[kobalte]: `useTooltipContext` must be used within a `Tooltip` component"); 51619 } 51620 return context3; 51621} 51622function TooltipContent(props) { 51623 const context3 = useTooltipContext(); 51624 const mergedProps = mergeDefaultProps({ 51625 id: context3.generateId("content") 51626 }, props); 51627 const [local, others] = splitProps(mergedProps, ["ref", "style"]); 51628 createEffect(() => onCleanup(context3.registerContentId(others.id))); 51629 return createComponent(Show, { 51630 get when() { 51631 return context3.contentPresent(); 51632 }, 51633 get children() { 51634 return createComponent(Popper.Positioner, { 51635 get children() { 51636 return createComponent(DismissableLayer, mergeProps({ 51637 ref(r$) { 51638 const _ref$ = mergeRefs((el) => { 51639 context3.setContentRef(el); 51640 }, local.ref); 51641 typeof _ref$ === "function" && _ref$(r$); 51642 }, 51643 role: "tooltip", 51644 disableOutsidePointerEvents: false, 51645 get style() { 51646 return combineStyle({ 51647 "--kb-tooltip-content-transform-origin": "var(--kb-popper-content-transform-origin)", 51648 position: "relative" 51649 }, local.style); 51650 }, 51651 onFocusOutside: (e) => e.preventDefault(), 51652 onDismiss: () => context3.hideTooltip(true) 51653 }, () => context3.dataset(), others)); 51654 } 51655 }); 51656 } 51657 }); 51658} 51659function TooltipPortal(props) { 51660 const context3 = useTooltipContext(); 51661 return createComponent(Show, { 51662 get when() { 51663 return context3.contentPresent(); 51664 }, 51665 get children() { 51666 return createComponent(Portal, props); 51667 } 51668 }); 51669} 51670function getTooltipSafeArea(placement, anchorEl, floatingEl) { 51671 const basePlacement = placement.split("-")[0]; 51672 const anchorRect = anchorEl.getBoundingClientRect(); 51673 const floatingRect = floatingEl.getBoundingClientRect(); 51674 const polygon = []; 51675 const anchorCenterX = anchorRect.left + anchorRect.width / 2; 51676 const anchorCenterY = anchorRect.top + anchorRect.height / 2; 51677 switch (basePlacement) { 51678 case "top": 51679 polygon.push([anchorRect.left, anchorCenterY]); 51680 polygon.push([floatingRect.left, floatingRect.bottom]); 51681 polygon.push([floatingRect.left, floatingRect.top]); 51682 polygon.push([floatingRect.right, floatingRect.top]); 51683 polygon.push([floatingRect.right, floatingRect.bottom]); 51684 polygon.push([anchorRect.right, anchorCenterY]); 51685 break; 51686 case "right": 51687 polygon.push([anchorCenterX, anchorRect.top]); 51688 polygon.push([floatingRect.left, floatingRect.top]); 51689 polygon.push([floatingRect.right, floatingRect.top]); 51690 polygon.push([floatingRect.right, floatingRect.bottom]); 51691 polygon.push([floatingRect.left, floatingRect.bottom]); 51692 polygon.push([anchorCenterX, anchorRect.bottom]); 51693 break; 51694 case "bottom": 51695 polygon.push([anchorRect.left, anchorCenterY]); 51696 polygon.push([floatingRect.left, floatingRect.top]); 51697 polygon.push([floatingRect.left, floatingRect.bottom]); 51698 polygon.push([floatingRect.right, floatingRect.bottom]); 51699 polygon.push([floatingRect.right, floatingRect.top]); 51700 polygon.push([anchorRect.right, anchorCenterY]); 51701 break; 51702 case "left": 51703 polygon.push([anchorCenterX, anchorRect.top]); 51704 polygon.push([floatingRect.right, floatingRect.top]); 51705 polygon.push([floatingRect.left, floatingRect.top]); 51706 polygon.push([floatingRect.left, floatingRect.bottom]); 51707 polygon.push([floatingRect.right, floatingRect.bottom]); 51708 polygon.push([anchorCenterX, anchorRect.bottom]); 51709 break; 51710 } 51711 return polygon; 51712} 51713var tooltips = {}; 51714var tooltipsCounter = 0; 51715var globalWarmedUp = false; 51716var globalWarmUpTimeout; 51717var globalCoolDownTimeout; 51718var globalSkipDelayTimeout; 51719function TooltipRoot(props) { 51720 const defaultId = `tooltip-${createUniqueId()}`; 51721 const tooltipId = `${++tooltipsCounter}`; 51722 const mergedProps = mergeDefaultProps({ 51723 id: defaultId, 51724 openDelay: 700, 51725 closeDelay: 300, 51726 skipDelayDuration: 300 51727 }, props); 51728 const [local, others] = splitProps(mergedProps, ["id", "open", "defaultOpen", "onOpenChange", "disabled", "triggerOnFocusOnly", "openDelay", "closeDelay", "skipDelayDuration", "ignoreSafeArea", "forceMount", "onCurrentPlacementChange"]); 51729 let closeTimeoutId; 51730 const [contentId, setContentId] = createSignal(); 51731 const [triggerRef, setTriggerRef] = createSignal(); 51732 const [contentRef, setContentRef] = createSignal(); 51733 const [currentPlacement, setCurrentPlacement] = createSignal(others.placement); 51734 const disclosureState = createDisclosureState({ 51735 open: () => local.open, 51736 defaultOpen: () => local.defaultOpen, 51737 onOpenChange: (isOpen) => local.onOpenChange?.(isOpen) 51738 }); 51739 const { 51740 present: contentPresent 51741 } = index_default2({ 51742 show: () => local.forceMount || disclosureState.isOpen(), 51743 element: () => contentRef() ?? null 51744 }); 51745 const ensureTooltipEntry = () => { 51746 tooltips[tooltipId] = hideTooltip; 51747 }; 51748 const closeOpenTooltips = () => { 51749 for (const hideTooltipId in tooltips) { 51750 if (hideTooltipId !== tooltipId) { 51751 tooltips[hideTooltipId](true); 51752 delete tooltips[hideTooltipId]; 51753 } 51754 } 51755 }; 51756 const hideTooltip = (immediate = false) => { 51757 if (isServer) { 51758 return; 51759 } 51760 if (immediate || local.closeDelay && local.closeDelay <= 0) { 51761 window.clearTimeout(closeTimeoutId); 51762 closeTimeoutId = void 0; 51763 disclosureState.close(); 51764 } else if (!closeTimeoutId) { 51765 closeTimeoutId = window.setTimeout(() => { 51766 closeTimeoutId = void 0; 51767 disclosureState.close(); 51768 }, local.closeDelay); 51769 } 51770 window.clearTimeout(globalWarmUpTimeout); 51771 globalWarmUpTimeout = void 0; 51772 if (local.skipDelayDuration && local.skipDelayDuration >= 0) { 51773 globalSkipDelayTimeout = window.setTimeout(() => { 51774 window.clearTimeout(globalSkipDelayTimeout); 51775 globalSkipDelayTimeout = void 0; 51776 }, local.skipDelayDuration); 51777 } 51778 if (globalWarmedUp) { 51779 window.clearTimeout(globalCoolDownTimeout); 51780 globalCoolDownTimeout = window.setTimeout(() => { 51781 delete tooltips[tooltipId]; 51782 globalCoolDownTimeout = void 0; 51783 globalWarmedUp = false; 51784 }, local.closeDelay); 51785 } 51786 }; 51787 const showTooltip = () => { 51788 if (isServer) { 51789 return; 51790 } 51791 clearTimeout(closeTimeoutId); 51792 closeTimeoutId = void 0; 51793 closeOpenTooltips(); 51794 ensureTooltipEntry(); 51795 globalWarmedUp = true; 51796 disclosureState.open(); 51797 window.clearTimeout(globalWarmUpTimeout); 51798 globalWarmUpTimeout = void 0; 51799 window.clearTimeout(globalCoolDownTimeout); 51800 globalCoolDownTimeout = void 0; 51801 window.clearTimeout(globalSkipDelayTimeout); 51802 globalSkipDelayTimeout = void 0; 51803 }; 51804 const warmupTooltip = () => { 51805 if (isServer) { 51806 return; 51807 } 51808 closeOpenTooltips(); 51809 ensureTooltipEntry(); 51810 if (!disclosureState.isOpen() && !globalWarmUpTimeout && !globalWarmedUp) { 51811 globalWarmUpTimeout = window.setTimeout(() => { 51812 globalWarmUpTimeout = void 0; 51813 globalWarmedUp = true; 51814 showTooltip(); 51815 }, local.openDelay); 51816 } else if (!disclosureState.isOpen()) { 51817 showTooltip(); 51818 } 51819 }; 51820 const openTooltip = (immediate = false) => { 51821 if (isServer) { 51822 return; 51823 } 51824 if (!immediate && local.openDelay && local.openDelay > 0 && !closeTimeoutId && !globalSkipDelayTimeout) { 51825 warmupTooltip(); 51826 } else { 51827 showTooltip(); 51828 } 51829 }; 51830 const cancelOpening = () => { 51831 if (isServer) { 51832 return; 51833 } 51834 window.clearTimeout(globalWarmUpTimeout); 51835 globalWarmUpTimeout = void 0; 51836 globalWarmedUp = false; 51837 }; 51838 const cancelClosing = () => { 51839 if (isServer) { 51840 return; 51841 } 51842 window.clearTimeout(closeTimeoutId); 51843 closeTimeoutId = void 0; 51844 }; 51845 const isTargetOnTooltip = (target) => { 51846 return contains(triggerRef(), target) || contains(contentRef(), target); 51847 }; 51848 const getPolygonSafeArea = (placement) => { 51849 const triggerEl = triggerRef(); 51850 const contentEl = contentRef(); 51851 if (!triggerEl || !contentEl) { 51852 return; 51853 } 51854 return getTooltipSafeArea(placement, triggerEl, contentEl); 51855 }; 51856 const onHoverOutside = (event) => { 51857 const target = event.target; 51858 if (isTargetOnTooltip(target)) { 51859 cancelClosing(); 51860 return; 51861 } 51862 if (!local.ignoreSafeArea) { 51863 const polygon = getPolygonSafeArea(currentPlacement()); 51864 if (polygon && isPointInPolygon(getEventPoint(event), polygon)) { 51865 cancelClosing(); 51866 return; 51867 } 51868 } 51869 if (closeTimeoutId) { 51870 return; 51871 } 51872 hideTooltip(); 51873 }; 51874 createEffect(() => { 51875 if (isServer) { 51876 return; 51877 } 51878 if (!disclosureState.isOpen()) { 51879 return; 51880 } 51881 const doc = getDocument(); 51882 doc.addEventListener("pointermove", onHoverOutside, true); 51883 onCleanup(() => { 51884 doc.removeEventListener("pointermove", onHoverOutside, true); 51885 }); 51886 }); 51887 createEffect(() => { 51888 const trigger = triggerRef(); 51889 if (!trigger || !disclosureState.isOpen()) { 51890 return; 51891 } 51892 const handleScroll = (event) => { 51893 const target = event.target; 51894 if (contains(target, trigger)) { 51895 hideTooltip(true); 51896 } 51897 }; 51898 const win = getWindow(); 51899 win.addEventListener("scroll", handleScroll, { 51900 capture: true 51901 }); 51902 onCleanup(() => { 51903 win.removeEventListener("scroll", handleScroll, { 51904 capture: true 51905 }); 51906 }); 51907 }); 51908 onCleanup(() => { 51909 clearTimeout(closeTimeoutId); 51910 const tooltip = tooltips[tooltipId]; 51911 if (tooltip) { 51912 delete tooltips[tooltipId]; 51913 } 51914 }); 51915 const dataset = createMemo(() => ({ 51916 "data-expanded": disclosureState.isOpen() ? "" : void 0, 51917 "data-closed": !disclosureState.isOpen() ? "" : void 0 51918 })); 51919 const context3 = { 51920 dataset, 51921 isOpen: disclosureState.isOpen, 51922 isDisabled: () => local.disabled ?? false, 51923 triggerOnFocusOnly: () => local.triggerOnFocusOnly ?? false, 51924 contentId, 51925 contentPresent, 51926 openTooltip, 51927 hideTooltip, 51928 cancelOpening, 51929 generateId: createGenerateId(() => mergedProps.id), 51930 registerContentId: createRegisterId(setContentId), 51931 isTargetOnTooltip, 51932 setTriggerRef, 51933 setContentRef 51934 }; 51935 return createComponent(TooltipContext.Provider, { 51936 value: context3, 51937 get children() { 51938 return createComponent(Popper, mergeProps({ 51939 anchorRef: triggerRef, 51940 contentRef, 51941 onCurrentPlacementChange: (value) => { 51942 setCurrentPlacement(value); 51943 local.onCurrentPlacementChange?.(value); 51944 } 51945 }, others)); 51946 } 51947 }); 51948} 51949function TooltipTrigger(props) { 51950 let ref; 51951 const context3 = useTooltipContext(); 51952 const [local, others] = splitProps(props, ["ref", "onPointerEnter", "onPointerLeave", "onPointerDown", "onClick", "onFocus", "onBlur"]); 51953 let isPointerDown = false; 51954 let isHovered = false; 51955 let isFocused = false; 51956 const handlePointerUp = () => { 51957 isPointerDown = false; 51958 }; 51959 const handleShow = () => { 51960 if (!context3.isOpen() && (isHovered || isFocused)) { 51961 context3.openTooltip(isFocused); 51962 } 51963 }; 51964 const handleHide = (immediate) => { 51965 if (context3.isOpen() && !isHovered && !isFocused) { 51966 context3.hideTooltip(immediate); 51967 } 51968 }; 51969 const onPointerEnter = (e) => { 51970 callHandler(e, local.onPointerEnter); 51971 if (e.pointerType === "touch" || context3.triggerOnFocusOnly() || context3.isDisabled() || e.defaultPrevented) { 51972 return; 51973 } 51974 isHovered = true; 51975 handleShow(); 51976 }; 51977 const onPointerLeave = (e) => { 51978 callHandler(e, local.onPointerLeave); 51979 if (e.pointerType === "touch") { 51980 return; 51981 } 51982 isHovered = false; 51983 isFocused = false; 51984 if (context3.isOpen()) { 51985 handleHide(); 51986 } else { 51987 context3.cancelOpening(); 51988 } 51989 }; 51990 const onPointerDown = (e) => { 51991 callHandler(e, local.onPointerDown); 51992 isPointerDown = true; 51993 getDocument(ref).addEventListener("pointerup", handlePointerUp, { 51994 once: true 51995 }); 51996 }; 51997 const onClick = (e) => { 51998 callHandler(e, local.onClick); 51999 isHovered = false; 52000 isFocused = false; 52001 handleHide(true); 52002 }; 52003 const onFocus = (e) => { 52004 callHandler(e, local.onFocus); 52005 if (context3.isDisabled() || e.defaultPrevented || isPointerDown) { 52006 return; 52007 } 52008 isFocused = true; 52009 handleShow(); 52010 }; 52011 const onBlur = (e) => { 52012 callHandler(e, local.onBlur); 52013 const relatedTarget = e.relatedTarget; 52014 if (context3.isTargetOnTooltip(relatedTarget)) { 52015 return; 52016 } 52017 isHovered = false; 52018 isFocused = false; 52019 handleHide(true); 52020 }; 52021 onCleanup(() => { 52022 if (isServer) { 52023 return; 52024 } 52025 getDocument(ref).removeEventListener("pointerup", handlePointerUp); 52026 }); 52027 return createComponent(Polymorphic, mergeProps({ 52028 as: "button", 52029 ref(r$) { 52030 const _ref$ = mergeRefs((el) => { 52031 context3.setTriggerRef(el); 52032 ref = el; 52033 }, local.ref); 52034 typeof _ref$ === "function" && _ref$(r$); 52035 }, 52036 get ["aria-describedby"]() { 52037 return memo(() => !!context3.isOpen())() ? context3.contentId() : void 0; 52038 }, 52039 onPointerEnter, 52040 onPointerLeave, 52041 onPointerDown, 52042 onClick, 52043 onFocus, 52044 onBlur, 52045 type: "button" 52046 }, () => context3.dataset(), others)); 52047} 52048var Tooltip = Object.assign(TooltipRoot, { 52049 Arrow: PopperArrow, 52050 Content: TooltipContent, 52051 Portal: TooltipPortal, 52052 Trigger: TooltipTrigger 52053}); 52054
52055// src/viewer/iconbutton.jsx 52056var _tmpl$7 = /* @__PURE__ */ template(`<p>`); 52057var IconButton = (props) => { 52058 return createComponent(Tooltip, { 52059 get children() { 52060 return [createComponent(Tooltip.Trigger, { 52061 get ["class"]() { 52062 return `${props.class} corner__icon__button`; 52063 }, 52064 get onclick() { 52065 return props.onClick; 52066 }, 52067 get children() { 52068 return props.children; 52069 } 52070 }), createComponent(Tooltip.Portal, { 52071 get mount() { 52072 return props.root; 52073 }, 52074 get children() { 52075 return createComponent(Tooltip.Content, { 52076 "class": "iconbutton__content", 52077 get children() { 52078 return [createComponent(Tooltip.Arrow, {}), (() => { 52079 const _el$ = _tmpl$7(); 52080 insert(_el$, () => props.tooltip); 52081 return _el$; 52082 })()]; 52083 } 52084 }); 52085 } 52086 })]; 52087 } 52088 }); 52089}; 52090
52091// src/viewer/fullscreen.jsx 52092var _tmpl$8 = /* @__PURE__ */ template(`<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false" data-testid="FullscreenExitIcon"><path d="M0 0h24v24H0z" fill="none"></path><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z">`); 52093var _tmpl$24 = /* @__PURE__ */ template(`<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false" data-testid="FullscreenIcon"><path d="M0 0h24v24H0z" fill="none"></path><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z">`); 52094var FullscreenButton = (props) => { 52095 return createComponent(Show, { 52096 get when() { 52097 return props.fullScreen; 52098 }, 52099 get fallback() { 52100 return createComponent(IconButton, { 52101 "class": "fullscreen", 52102 tooltip: "Expand view", 52103 get onClick() { 52104 return props.toggle; 52105 }, 52106 get root() { 52107 return props.root; 52108 }, 52109 get children() { 52110 return _tmpl$24(); 52111 } 52112 }); 52113 }, 52114 get children() { 52115 return createComponent(IconButton, { 52116 "class": "fullscreen", 52117 tooltip: "Collapse view", 52118 get onClick() { 52119 return props.toggle; 52120 }, 52121 get root() { 52122 return props.root; 52123 }, 52124 get children() { 52125 return _tmpl$8(); 52126 } 52127 }); 52128 } 52129 }); 52130}; 52131
vendor: 935 bytes, lines 52132-52163
52132// node_modules/@kobalte/core/dist/chunk/STGRFJHZ.js 52133var separator_exports = {}; 52134__export(separator_exports, { 52135 Root: () => SeparatorRoot, 52136 Separator: () => Separator 52137}); 52138function SeparatorRoot(props) { 52139 let ref; 52140 const mergedProps = mergeDefaultProps({ 52141 orientation: "horizontal" 52142 }, props); 52143 const [local, others] = splitProps(mergedProps, ["ref", "orientation"]); 52144 const tagName = createTagName(() => ref, () => "hr"); 52145 return createComponent(Polymorphic, mergeProps({ 52146 as: "hr", 52147 ref(r$) { 52148 const _ref$ = mergeRefs((el) => ref = el, local.ref); 52149 typeof _ref$ === "function" && _ref$(r$); 52150 }, 52151 get role() { 52152 return tagName() !== "hr" ? "separator" : void 0; 52153 }, 52154 get ["aria-orientation"]() { 52155 return local.orientation === "vertical" ? "vertical" : void 0; 52156 }, 52157 get ["data-orientation"]() { 52158 return local.orientation; 52159 } 52160 }, others)); 52161} 52162var Separator = SeparatorRoot; 52163
vendor: 3,087 bytes, lines 52164-52272
52164// node_modules/@kobalte/core/dist/chunk/3NGA46QE.js 52165function buildNodes(params) { 52166 let index = params.startIndex ?? 0; 52167 const level = params.startLevel ?? 0; 52168 const nodes = []; 52169 const getKey = (data) => { 52170 if (data == null) { 52171 return ""; 52172 } 52173 const _getKey = params.getKey ?? "key"; 52174 const dataKey = isString(_getKey) ? data[_getKey] : _getKey(data); 52175 return dataKey != null ? String(dataKey) : ""; 52176 }; 52177 const getTextValue = (data) => { 52178 if (data == null) { 52179 return ""; 52180 } 52181 const _getTextValue = params.getTextValue ?? "textValue"; 52182 const dataTextValue = isString(_getTextValue) ? data[_getTextValue] : _getTextValue(data); 52183 return dataTextValue != null ? String(dataTextValue) : ""; 52184 }; 52185 const getDisabled = (data) => { 52186 if (data == null) { 52187 return false; 52188 } 52189 const _getDisabled = params.getDisabled ?? "disabled"; 52190 return (isString(_getDisabled) ? data[_getDisabled] : _getDisabled(data)) ?? false; 52191 }; 52192 const getSectionChildren = (data) => { 52193 if (data == null) { 52194 return void 0; 52195 } 52196 if (isString(params.getSectionChildren)) { 52197 return data[params.getSectionChildren]; 52198 } 52199 return params.getSectionChildren?.(data); 52200 }; 52201 for (const data of params.dataSource) { 52202 if (isString(data) || isNumber(data)) { 52203 nodes.push({ 52204 type: "item", 52205 rawValue: data, 52206 key: String(data), 52207 textValue: String(data), 52208 disabled: getDisabled(data), 52209 level, 52210 index 52211 }); 52212 index++; 52213 continue; 52214 } 52215 if (getSectionChildren(data) != null) { 52216 nodes.push({ 52217 type: "section", 52218 rawValue: data, 52219 key: "", 52220 // not applicable here 52221 textValue: "", 52222 // not applicable here 52223 disabled: false, 52224 // not applicable here 52225 level, 52226 index 52227 }); 52228 index++; 52229 const sectionChildren = getSectionChildren(data) ?? []; 52230 if (sectionChildren.length > 0) { 52231 const childNodes = buildNodes({ 52232 dataSource: sectionChildren, 52233 getKey: params.getKey, 52234 getTextValue: params.getTextValue, 52235 getDisabled: params.getDisabled, 52236 getSectionChildren: params.getSectionChildren, 52237 startIndex: index, 52238 startLevel: level + 1 52239 }); 52240 nodes.push(...childNodes); 52241 index += childNodes.length; 52242 } 52243 } else { 52244 nodes.push({ 52245 type: "item", 52246 rawValue: data, 52247 key: getKey(data), 52248 textValue: getTextValue(data), 52249 disabled: getDisabled(data), 52250 level, 52251 index 52252 }); 52253 index++; 52254 } 52255 } 52256 return nodes; 52257} 52258function createCollection(props, deps = []) { 52259 return createMemo(() => { 52260 const nodes = buildNodes({ 52261 dataSource: access4(props.dataSource), 52262 getKey: access4(props.getKey), 52263 getTextValue: access4(props.getTextValue), 52264 getDisabled: access4(props.getDisabled), 52265 getSectionChildren: access4(props.getSectionChildren) 52266 }); 52267 for (let i = 0; i < deps.length; i++) 52268 deps[i](); 52269 return props.factory(nodes); 52270 }); 52271} 52272
vendor: 28,977 bytes, lines 52273-53255
52273// node_modules/@kobalte/core/dist/chunk/3D6FM2PJ.js 52274var Selection = class _Selection extends Set { 52275 anchorKey; 52276 currentKey; 52277 constructor(keys5, anchorKey, currentKey) { 52278 super(keys5); 52279 if (keys5 instanceof _Selection) { 52280 this.anchorKey = anchorKey || keys5.anchorKey; 52281 this.currentKey = currentKey || keys5.currentKey; 52282 } else { 52283 this.anchorKey = anchorKey; 52284 this.currentKey = currentKey; 52285 } 52286 } 52287}; 52288function createControllableSelectionSignal(props) { 52289 const [_value, setValue] = createControllableSignal(props); 52290 const value = () => _value() ?? new Selection(); 52291 return [value, setValue]; 52292} 52293function isNonContiguousSelectionModifier(e) { 52294 return isAppleDevice() ? e.altKey : e.ctrlKey; 52295} 52296function isCtrlKeyPressed(e) { 52297 if (isMac()) { 52298 return e.metaKey; 52299 } 52300 return e.ctrlKey; 52301} 52302function convertSelection(selection) { 52303 return new Selection(selection); 52304} 52305function isSameSelection(setA, setB) { 52306 if (setA.size !== setB.size) { 52307 return false; 52308 } 52309 for (const item of setA) { 52310 if (!setB.has(item)) { 52311 return false; 52312 } 52313 } 52314 return true; 52315} 52316function createMultipleSelectionState(props) { 52317 const mergedProps = mergeDefaultProps( 52318 { 52319 selectionMode: "none", 52320 selectionBehavior: "toggle" 52321 }, 52322 props 52323 ); 52324 const [isFocused, setFocused] = createSignal(false); 52325 const [focusedKey, setFocusedKey] = createSignal(); 52326 const selectedKeysProp = createMemo(() => { 52327 const selection = access4(mergedProps.selectedKeys); 52328 if (selection != null) { 52329 return convertSelection(selection); 52330 } 52331 return selection; 52332 }); 52333 const defaultSelectedKeys = createMemo(() => { 52334 const defaultSelection = access4(mergedProps.defaultSelectedKeys); 52335 if (defaultSelection != null) { 52336 return convertSelection(defaultSelection); 52337 } 52338 return new Selection(); 52339 }); 52340 const [selectedKeys, _setSelectedKeys] = createControllableSelectionSignal({ 52341 value: selectedKeysProp, 52342 defaultValue: defaultSelectedKeys, 52343 onChange: (value) => mergedProps.onSelectionChange?.(value) 52344 }); 52345 const [selectionBehavior, setSelectionBehavior] = createSignal(access4(mergedProps.selectionBehavior)); 52346 const selectionMode = () => access4(mergedProps.selectionMode); 52347 const disallowEmptySelection = () => access4(mergedProps.disallowEmptySelection) ?? false; 52348 const setSelectedKeys = (keys5) => { 52349 if (access4(mergedProps.allowDuplicateSelectionEvents) || !isSameSelection(keys5, selectedKeys())) { 52350 _setSelectedKeys(keys5); 52351 } 52352 }; 52353 createEffect(() => { 52354 const selection = selectedKeys(); 52355 if (access4(mergedProps.selectionBehavior) === "replace" && selectionBehavior() === "toggle" && typeof selection === "object" && selection.size === 0) { 52356 setSelectionBehavior("replace"); 52357 } 52358 }); 52359 createEffect(() => { 52360 setSelectionBehavior(access4(mergedProps.selectionBehavior) ?? "toggle"); 52361 }); 52362 return { 52363 selectionMode, 52364 disallowEmptySelection, 52365 selectionBehavior, 52366 setSelectionBehavior, 52367 isFocused, 52368 setFocused, 52369 focusedKey, 52370 setFocusedKey, 52371 selectedKeys, 52372 setSelectedKeys 52373 }; 52374} 52375function createTypeSelect(props) { 52376 const [search, setSearch] = createSignal(""); 52377 const [timeoutId, setTimeoutId] = createSignal(-1); 52378 const onKeyDown = (e) => { 52379 if (access4(props.isDisabled)) { 52380 return; 52381 } 52382 const delegate = access4(props.keyboardDelegate); 52383 const manager = access4(props.selectionManager); 52384 if (!delegate.getKeyForSearch) { 52385 return; 52386 } 52387 const character = getStringForKey(e.key); 52388 if (!character || e.ctrlKey || e.metaKey) { 52389 return; 52390 } 52391 if (character === " " && search().trim().length > 0) { 52392 e.preventDefault(); 52393 e.stopPropagation(); 52394 } 52395 let newSearch = setSearch((prev) => prev + character); 52396 let key = delegate.getKeyForSearch(newSearch, manager.focusedKey()) ?? delegate.getKeyForSearch(newSearch); 52397 if (key == null && isAllSameLetter(newSearch)) { 52398 newSearch = newSearch[0]; 52399 key = delegate.getKeyForSearch(newSearch, manager.focusedKey()) ?? delegate.getKeyForSearch(newSearch); 52400 } 52401 if (key != null) { 52402 manager.setFocusedKey(key); 52403 props.onTypeSelect?.(key); 52404 } 52405 clearTimeout(timeoutId()); 52406 setTimeoutId(window.setTimeout(() => setSearch(""), 500)); 52407 }; 52408 return { 52409 typeSelectHandlers: { 52410 onKeyDown 52411 } 52412 }; 52413} 52414function getStringForKey(key) { 52415 if (key.length === 1 || !/^[A-Z]/i.test(key)) { 52416 return key; 52417 } 52418 return ""; 52419} 52420function isAllSameLetter(search) { 52421 return search.split("").every((letter) => letter === search[0]); 52422} 52423function createSelectableCollection(props, ref, scrollRef) { 52424 const defaultProps = { 52425 selectOnFocus: () => access4(props.selectionManager).selectionBehavior() === "replace" 52426 }; 52427 const mergedProps = mergeProps(defaultProps, props); 52428 const finalScrollRef = () => scrollRef?.() ?? ref(); 52429 const { direction } = useLocale(); 52430 let scrollPos = { top: 0, left: 0 }; 52431 createEventListener( 52432 () => !access4(mergedProps.isVirtualized) ? finalScrollRef() : void 0, 52433 "scroll", 52434 () => { 52435 const scrollEl = finalScrollRef(); 52436 if (!scrollEl) { 52437 return; 52438 } 52439 scrollPos = { 52440 top: scrollEl.scrollTop, 52441 left: scrollEl.scrollLeft 52442 }; 52443 } 52444 ); 52445 const { typeSelectHandlers } = createTypeSelect({ 52446 isDisabled: () => access4(mergedProps.disallowTypeAhead), 52447 keyboardDelegate: () => access4(mergedProps.keyboardDelegate), 52448 selectionManager: () => access4(mergedProps.selectionManager) 52449 }); 52450 const orientation = () => access4(mergedProps.orientation) ?? "vertical"; 52451 const onKeyDown = (e) => { 52452 callHandler(e, typeSelectHandlers.onKeyDown); 52453 if (e.altKey && e.key === "Tab") { 52454 e.preventDefault(); 52455 } 52456 const refEl = ref(); 52457 if (!refEl?.contains(e.target)) { 52458 return; 52459 } 52460 const manager = access4(mergedProps.selectionManager); 52461 const selectOnFocus = access4(mergedProps.selectOnFocus); 52462 const navigateToKey = (key) => { 52463 if (key != null) { 52464 manager.setFocusedKey(key); 52465 if (e.shiftKey && manager.selectionMode() === "multiple") { 52466 manager.extendSelection(key); 52467 } else if (selectOnFocus && !isNonContiguousSelectionModifier(e)) { 52468 manager.replaceSelection(key); 52469 } 52470 } 52471 }; 52472 const delegate = access4(mergedProps.keyboardDelegate); 52473 const shouldFocusWrap = access4(mergedProps.shouldFocusWrap); 52474 const focusedKey = manager.focusedKey(); 52475 switch (e.key) { 52476 case (orientation() === "vertical" ? "ArrowDown" : "ArrowRight"): { 52477 if (delegate.getKeyBelow) { 52478 e.preventDefault(); 52479 let nextKey; 52480 if (focusedKey != null) { 52481 nextKey = delegate.getKeyBelow(focusedKey); 52482 } else { 52483 nextKey = delegate.getFirstKey?.(); 52484 } 52485 if (nextKey == null && shouldFocusWrap) { 52486 nextKey = delegate.getFirstKey?.(focusedKey); 52487 } 52488 navigateToKey(nextKey); 52489 } 52490 break; 52491 } 52492 case (orientation() === "vertical" ? "ArrowUp" : "ArrowLeft"): { 52493 if (delegate.getKeyAbove) { 52494 e.preventDefault(); 52495 let nextKey; 52496 if (focusedKey != null) { 52497 nextKey = delegate.getKeyAbove(focusedKey); 52498 } else { 52499 nextKey = delegate.getLastKey?.(); 52500 } 52501 if (nextKey == null && shouldFocusWrap) { 52502 nextKey = delegate.getLastKey?.(focusedKey); 52503 } 52504 navigateToKey(nextKey); 52505 } 52506 break; 52507 } 52508 case (orientation() === "vertical" ? "ArrowLeft" : "ArrowUp"): { 52509 if (delegate.getKeyLeftOf) { 52510 e.preventDefault(); 52511 const isRTL3 = direction() === "rtl"; 52512 let nextKey; 52513 if (focusedKey != null) { 52514 nextKey = delegate.getKeyLeftOf(focusedKey); 52515 } else { 52516 nextKey = isRTL3 ? delegate.getFirstKey?.() : delegate.getLastKey?.(); 52517 } 52518 navigateToKey(nextKey); 52519 } 52520 break; 52521 } 52522 case (orientation() === "vertical" ? "ArrowRight" : "ArrowDown"): { 52523 if (delegate.getKeyRightOf) { 52524 e.preventDefault(); 52525 const isRTL3 = direction() === "rtl"; 52526 let nextKey; 52527 if (focusedKey != null) { 52528 nextKey = delegate.getKeyRightOf(focusedKey); 52529 } else { 52530 nextKey = isRTL3 ? delegate.getLastKey?.() : delegate.getFirstKey?.(); 52531 } 52532 navigateToKey(nextKey); 52533 } 52534 break; 52535 } 52536 case "Home": 52537 if (delegate.getFirstKey) { 52538 e.preventDefault(); 52539 const firstKey = delegate.getFirstKey( 52540 focusedKey, 52541 isCtrlKeyPressed(e) 52542 ); 52543 if (firstKey != null) { 52544 manager.setFocusedKey(firstKey); 52545 if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode() === "multiple") { 52546 manager.extendSelection(firstKey); 52547 } else if (selectOnFocus) { 52548 manager.replaceSelection(firstKey); 52549 } 52550 } 52551 } 52552 break; 52553 case "End": 52554 if (delegate.getLastKey) { 52555 e.preventDefault(); 52556 const lastKey = delegate.getLastKey(focusedKey, isCtrlKeyPressed(e)); 52557 if (lastKey != null) { 52558 manager.setFocusedKey(lastKey); 52559 if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode() === "multiple") { 52560 manager.extendSelection(lastKey); 52561 } else if (selectOnFocus) { 52562 manager.replaceSelection(lastKey); 52563 } 52564 } 52565 } 52566 break; 52567 case "PageDown": 52568 if (delegate.getKeyPageBelow && focusedKey != null) { 52569 e.preventDefault(); 52570 const nextKey = delegate.getKeyPageBelow(focusedKey); 52571 navigateToKey(nextKey); 52572 } 52573 break; 52574 case "PageUp": 52575 if (delegate.getKeyPageAbove && focusedKey != null) { 52576 e.preventDefault(); 52577 const nextKey = delegate.getKeyPageAbove(focusedKey); 52578 navigateToKey(nextKey); 52579 } 52580 break; 52581 case "a": 52582 if (isCtrlKeyPressed(e) && manager.selectionMode() === "multiple" && access4(mergedProps.disallowSelectAll) !== true) { 52583 e.preventDefault(); 52584 manager.selectAll(); 52585 } 52586 break; 52587 case "Escape": 52588 if (!e.defaultPrevented && !access4(mergedProps.disallowEmptySelection)) { 52589 e.preventDefault(); 52590 manager.clearSelection(); 52591 } 52592 break; 52593 case "Tab": { 52594 if (!access4(mergedProps.allowsTabNavigation)) { 52595 if (e.shiftKey) { 52596 refEl.focus(); 52597 } else { 52598 const walker = getFocusableTreeWalker(refEl, { tabbable: true }); 52599 let next; 52600 let last; 52601 do { 52602 last = walker.lastChild(); 52603 if (last) { 52604 next = last; 52605 } 52606 } while (last); 52607 if (next && !next.contains(document.activeElement)) { 52608 focusWithoutScrolling(next); 52609 } 52610 } 52611 break; 52612 } 52613 } 52614 } 52615 }; 52616 const onFocusIn = (e) => { 52617 const manager = access4(mergedProps.selectionManager); 52618 const delegate = access4(mergedProps.keyboardDelegate); 52619 const selectOnFocus = access4(mergedProps.selectOnFocus); 52620 if (manager.isFocused()) { 52621 if (!e.currentTarget.contains(e.target)) { 52622 manager.setFocused(false); 52623 } 52624 return; 52625 } 52626 if (!e.currentTarget.contains(e.target)) { 52627 return; 52628 } 52629 manager.setFocused(true); 52630 if (manager.focusedKey() == null) { 52631 const navigateToFirstKey = (key) => { 52632 if (key == null) { 52633 return; 52634 } 52635 manager.setFocusedKey(key); 52636 if (selectOnFocus) { 52637 manager.replaceSelection(key); 52638 } 52639 }; 52640 const relatedTarget = e.relatedTarget; 52641 if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) { 52642 navigateToFirstKey( 52643 manager.lastSelectedKey() ?? delegate.getLastKey?.() 52644 ); 52645 } else { 52646 navigateToFirstKey( 52647 manager.firstSelectedKey() ?? delegate.getFirstKey?.() 52648 ); 52649 } 52650 } else if (!access4(mergedProps.isVirtualized)) { 52651 const scrollEl = finalScrollRef(); 52652 if (scrollEl) { 52653 scrollEl.scrollTop = scrollPos.top; 52654 scrollEl.scrollLeft = scrollPos.left; 52655 const element3 = scrollEl.querySelector( 52656 `[data-key="${manager.focusedKey()}"]` 52657 ); 52658 if (element3) { 52659 focusWithoutScrolling(element3); 52660 scrollIntoView(scrollEl, element3); 52661 } 52662 } 52663 } 52664 }; 52665 const onFocusOut = (e) => { 52666 const manager = access4(mergedProps.selectionManager); 52667 if (!e.currentTarget.contains(e.relatedTarget)) { 52668 manager.setFocused(false); 52669 } 52670 }; 52671 const onMouseDown = (e) => { 52672 if (finalScrollRef() === e.target) { 52673 e.preventDefault(); 52674 } 52675 }; 52676 const tryAutoFocus = () => { 52677 const autoFocus = access4(mergedProps.autoFocus); 52678 if (!autoFocus) { 52679 return; 52680 } 52681 const manager = access4(mergedProps.selectionManager); 52682 const delegate = access4(mergedProps.keyboardDelegate); 52683 let focusedKey; 52684 if (autoFocus === "first") { 52685 focusedKey = delegate.getFirstKey?.(); 52686 } 52687 if (autoFocus === "last") { 52688 focusedKey = delegate.getLastKey?.(); 52689 } 52690 const selectedKeys = manager.selectedKeys(); 52691 if (selectedKeys.size) { 52692 focusedKey = selectedKeys.values().next().value; 52693 } 52694 manager.setFocused(true); 52695 manager.setFocusedKey(focusedKey); 52696 const refEl = ref(); 52697 if (refEl && focusedKey == null && !access4(mergedProps.shouldUseVirtualFocus)) { 52698 focusWithoutScrolling(refEl); 52699 } 52700 }; 52701 onMount(() => { 52702 if (mergedProps.deferAutoFocus) { 52703 setTimeout(tryAutoFocus, 0); 52704 } else { 52705 tryAutoFocus(); 52706 } 52707 }); 52708 createEffect( 52709 on( 52710 [ 52711 finalScrollRef, 52712 () => access4(mergedProps.isVirtualized), 52713 () => access4(mergedProps.selectionManager).focusedKey() 52714 ], 52715 (newValue) => { 52716 const [scrollEl, isVirtualized, focusedKey] = newValue; 52717 if (isVirtualized) { 52718 focusedKey && mergedProps.scrollToKey?.(focusedKey); 52719 } else { 52720 if (focusedKey && scrollEl) { 52721 const element3 = scrollEl.querySelector( 52722 `[data-key="${focusedKey}"]` 52723 ); 52724 if (element3) { 52725 scrollIntoView(scrollEl, element3); 52726 } 52727 } 52728 } 52729 } 52730 ) 52731 ); 52732 const tabIndex = createMemo(() => { 52733 if (access4(mergedProps.shouldUseVirtualFocus)) { 52734 return void 0; 52735 } 52736 return access4(mergedProps.selectionManager).focusedKey() == null ? 0 : -1; 52737 }); 52738 return { 52739 tabIndex, 52740 onKeyDown, 52741 onMouseDown, 52742 onFocusIn, 52743 onFocusOut 52744 }; 52745} 52746function createSelectableItem(props, ref) { 52747 const manager = () => access4(props.selectionManager); 52748 const key = () => access4(props.key); 52749 const shouldUseVirtualFocus = () => access4(props.shouldUseVirtualFocus); 52750 const onSelect = (e) => { 52751 if (manager().selectionMode() === "none") { 52752 return; 52753 } 52754 if (manager().selectionMode() === "single") { 52755 if (manager().isSelected(key()) && !manager().disallowEmptySelection()) { 52756 manager().toggleSelection(key()); 52757 } else { 52758 manager().replaceSelection(key()); 52759 } 52760 } else if (e?.shiftKey) { 52761 manager().extendSelection(key()); 52762 } else if (manager().selectionBehavior() === "toggle" || isCtrlKeyPressed(e) || "pointerType" in e && e.pointerType === "touch") { 52763 manager().toggleSelection(key()); 52764 } else { 52765 manager().replaceSelection(key()); 52766 } 52767 }; 52768 const isSelected = () => manager().isSelected(key()); 52769 const isDisabled = () => access4(props.disabled) || manager().isDisabled(key()); 52770 const allowsSelection = () => !isDisabled() && manager().canSelectItem(key()); 52771 let pointerDownType = null; 52772 const onPointerDown = (e) => { 52773 if (!allowsSelection()) { 52774 return; 52775 } 52776 pointerDownType = e.pointerType; 52777 if (e.pointerType === "mouse" && e.button === 0 && !access4(props.shouldSelectOnPressUp)) { 52778 onSelect(e); 52779 } 52780 }; 52781 const onPointerUp = (e) => { 52782 if (!allowsSelection()) { 52783 return; 52784 } 52785 if (e.pointerType === "mouse" && e.button === 0 && access4(props.shouldSelectOnPressUp) && access4(props.allowsDifferentPressOrigin)) { 52786 onSelect(e); 52787 } 52788 }; 52789 const onClick = (e) => { 52790 if (!allowsSelection()) { 52791 return; 52792 } 52793 if (access4(props.shouldSelectOnPressUp) && !access4(props.allowsDifferentPressOrigin) || pointerDownType !== "mouse") { 52794 onSelect(e); 52795 } 52796 }; 52797 const onKeyDown = (e) => { 52798 if (!allowsSelection() || !["Enter", " "].includes(e.key)) { 52799 return; 52800 } 52801 if (isNonContiguousSelectionModifier(e)) { 52802 manager().toggleSelection(key()); 52803 } else { 52804 onSelect(e); 52805 } 52806 }; 52807 const onMouseDown = (e) => { 52808 if (isDisabled()) { 52809 e.preventDefault(); 52810 } 52811 }; 52812 const onFocus = (e) => { 52813 const refEl = ref(); 52814 if (shouldUseVirtualFocus() || isDisabled() || !refEl) { 52815 return; 52816 } 52817 if (e.target === refEl) { 52818 manager().setFocusedKey(key()); 52819 } 52820 }; 52821 const tabIndex = createMemo(() => { 52822 if (shouldUseVirtualFocus() || isDisabled()) { 52823 return void 0; 52824 } 52825 return key() === manager().focusedKey() ? 0 : -1; 52826 }); 52827 const dataKey = createMemo(() => { 52828 return access4(props.virtualized) ? void 0 : key(); 52829 }); 52830 createEffect( 52831 on( 52832 [ 52833 ref, 52834 key, 52835 shouldUseVirtualFocus, 52836 () => manager().focusedKey(), 52837 () => manager().isFocused() 52838 ], 52839 ([refEl, key2, shouldUseVirtualFocus2, focusedKey, isFocused]) => { 52840 if (refEl && key2 === focusedKey && isFocused && !shouldUseVirtualFocus2 && document.activeElement !== refEl) { 52841 if (props.focus) { 52842 props.focus(); 52843 } else { 52844 focusWithoutScrolling(refEl); 52845 } 52846 } 52847 } 52848 ) 52849 ); 52850 return { 52851 isSelected, 52852 isDisabled, 52853 allowsSelection, 52854 tabIndex, 52855 dataKey, 52856 onPointerDown, 52857 onPointerUp, 52858 onClick, 52859 onKeyDown, 52860 onMouseDown, 52861 onFocus 52862 }; 52863} 52864var SelectionManager = class { 52865 collection; 52866 state; 52867 constructor(collection, state) { 52868 this.collection = collection; 52869 this.state = state; 52870 } 52871 /** The type of selection that is allowed in the collection. */ 52872 selectionMode() { 52873 return this.state.selectionMode(); 52874 } 52875 /** Whether the collection allows empty selection. */ 52876 disallowEmptySelection() { 52877 return this.state.disallowEmptySelection(); 52878 } 52879 /** The selection behavior for the collection. */ 52880 selectionBehavior() { 52881 return this.state.selectionBehavior(); 52882 } 52883 /** Sets the selection behavior for the collection. */ 52884 setSelectionBehavior(selectionBehavior) { 52885 this.state.setSelectionBehavior(selectionBehavior); 52886 } 52887 /** Whether the collection is currently focused. */ 52888 isFocused() { 52889 return this.state.isFocused(); 52890 } 52891 /** Sets whether the collection is focused. */ 52892 setFocused(isFocused) { 52893 this.state.setFocused(isFocused); 52894 } 52895 /** The current focused key in the collection. */ 52896 focusedKey() { 52897 return this.state.focusedKey(); 52898 } 52899 /** Sets the focused key. */ 52900 setFocusedKey(key) { 52901 if (key == null || this.collection().getItem(key)) { 52902 this.state.setFocusedKey(key); 52903 } 52904 } 52905 /** The currently selected keys in the collection. */ 52906 selectedKeys() { 52907 return this.state.selectedKeys(); 52908 } 52909 /** Returns whether a key is selected. */ 52910 isSelected(key) { 52911 if (this.state.selectionMode() === "none") { 52912 return false; 52913 } 52914 const retrievedKey = this.getKey(key); 52915 if (retrievedKey == null) { 52916 return false; 52917 } 52918 return this.state.selectedKeys().has(retrievedKey); 52919 } 52920 /** Whether the selection is empty. */ 52921 isEmpty() { 52922 return this.state.selectedKeys().size === 0; 52923 } 52924 /** Whether all items in the collection are selected. */ 52925 isSelectAll() { 52926 if (this.isEmpty()) { 52927 return false; 52928 } 52929 const selectedKeys = this.state.selectedKeys(); 52930 return this.getAllSelectableKeys().every((k) => selectedKeys.has(k)); 52931 } 52932 firstSelectedKey() { 52933 let first; 52934 for (const key of this.state.selectedKeys()) { 52935 const item = this.collection().getItem(key); 52936 const isItemBeforeFirst = item?.index != null && first?.index != null && item.index < first.index; 52937 if (!first || isItemBeforeFirst) { 52938 first = item; 52939 } 52940 } 52941 return first?.key; 52942 } 52943 lastSelectedKey() { 52944 let last; 52945 for (const key of this.state.selectedKeys()) { 52946 const item = this.collection().getItem(key); 52947 const isItemAfterLast = item?.index != null && last?.index != null && item.index > last.index; 52948 if (!last || isItemAfterLast) { 52949 last = item; 52950 } 52951 } 52952 return last?.key; 52953 } 52954 /** Extends the selection to the given key. */ 52955 extendSelection(toKey) { 52956 if (this.selectionMode() === "none") { 52957 return; 52958 } 52959 if (this.selectionMode() === "single") { 52960 this.replaceSelection(toKey); 52961 return; 52962 } 52963 const retrievedToKey = this.getKey(toKey); 52964 if (retrievedToKey == null) { 52965 return; 52966 } 52967 const selectedKeys = this.state.selectedKeys(); 52968 const anchorKey = selectedKeys.anchorKey || retrievedToKey; 52969 const selection = new Selection(selectedKeys, anchorKey, retrievedToKey); 52970 for (const key of this.getKeyRange( 52971 anchorKey, 52972 selectedKeys.currentKey || retrievedToKey 52973 )) { 52974 selection.delete(key); 52975 } 52976 for (const key of this.getKeyRange(retrievedToKey, anchorKey)) { 52977 if (this.canSelectItem(key)) { 52978 selection.add(key); 52979 } 52980 } 52981 this.state.setSelectedKeys(selection); 52982 } 52983 getKeyRange(from, to) { 52984 const fromItem = this.collection().getItem(from); 52985 const toItem = this.collection().getItem(to); 52986 if (fromItem && toItem) { 52987 if (fromItem.index != null && toItem.index != null && fromItem.index <= toItem.index) { 52988 return this.getKeyRangeInternal(from, to); 52989 } 52990 return this.getKeyRangeInternal(to, from); 52991 } 52992 return []; 52993 } 52994 getKeyRangeInternal(from, to) { 52995 const keys5 = []; 52996 let key = from; 52997 while (key != null) { 52998 const item = this.collection().getItem(key); 52999 if (item && item.type === "item") { 53000 keys5.push(key); 53001 } 53002 if (key === to) { 53003 return keys5; 53004 } 53005 key = this.collection().getKeyAfter(key); 53006 } 53007 return []; 53008 } 53009 getKey(key) { 53010 const item = this.collection().getItem(key); 53011 if (!item) { 53012 return key; 53013 } 53014 if (!item || item.type !== "item") { 53015 return null; 53016 } 53017 return item.key; 53018 } 53019 /** Toggles whether the given key is selected. */ 53020 toggleSelection(key) { 53021 if (this.selectionMode() === "none") { 53022 return; 53023 } 53024 if (this.selectionMode() === "single" && !this.isSelected(key)) { 53025 this.replaceSelection(key); 53026 return; 53027 } 53028 const retrievedKey = this.getKey(key); 53029 if (retrievedKey == null) { 53030 return; 53031 } 53032 const keys5 = new Selection(this.state.selectedKeys()); 53033 if (keys5.has(retrievedKey)) { 53034 keys5.delete(retrievedKey); 53035 } else if (this.canSelectItem(retrievedKey)) { 53036 keys5.add(retrievedKey); 53037 keys5.anchorKey = retrievedKey; 53038 keys5.currentKey = retrievedKey; 53039 } 53040 if (this.disallowEmptySelection() && keys5.size === 0) { 53041 return; 53042 } 53043 this.state.setSelectedKeys(keys5); 53044 } 53045 /** Replaces the selection with only the given key. */ 53046 replaceSelection(key) { 53047 if (this.selectionMode() === "none") { 53048 return; 53049 } 53050 const retrievedKey = this.getKey(key); 53051 if (retrievedKey == null) { 53052 return; 53053 } 53054 const selection = this.canSelectItem(retrievedKey) ? new Selection([retrievedKey], retrievedKey, retrievedKey) : new Selection(); 53055 this.state.setSelectedKeys(selection); 53056 } 53057 /** Replaces the selection with the given keys. */ 53058 setSelectedKeys(keys5) { 53059 if (this.selectionMode() === "none") { 53060 return; 53061 } 53062 const selection = new Selection(); 53063 for (const key of keys5) { 53064 const retrievedKey = this.getKey(key); 53065 if (retrievedKey != null) { 53066 selection.add(retrievedKey); 53067 if (this.selectionMode() === "single") { 53068 break; 53069 } 53070 } 53071 } 53072 this.state.setSelectedKeys(selection); 53073 } 53074 /** Selects all items in the collection. */ 53075 selectAll() { 53076 if (this.selectionMode() === "multiple") { 53077 this.state.setSelectedKeys(new Set(this.getAllSelectableKeys())); 53078 } 53079 } 53080 /** 53081 * Removes all keys from the selection. 53082 */ 53083 clearSelection() { 53084 const selectedKeys = this.state.selectedKeys(); 53085 if (!this.disallowEmptySelection() && selectedKeys.size > 0) { 53086 this.state.setSelectedKeys(new Selection()); 53087 } 53088 } 53089 /** 53090 * Toggles between select all and an empty selection. 53091 */ 53092 toggleSelectAll() { 53093 if (this.isSelectAll()) { 53094 this.clearSelection(); 53095 } else { 53096 this.selectAll(); 53097 } 53098 } 53099 select(key, e) { 53100 if (this.selectionMode() === "none") { 53101 return; 53102 } 53103 if (this.selectionMode() === "single") { 53104 if (this.isSelected(key) && !this.disallowEmptySelection()) { 53105 this.toggleSelection(key); 53106 } else { 53107 this.replaceSelection(key); 53108 } 53109 } else if (this.selectionBehavior() === "toggle" || e && e.pointerType === "touch") { 53110 this.toggleSelection(key); 53111 } else { 53112 this.replaceSelection(key); 53113 } 53114 } 53115 /** Returns whether the current selection is equal to the given selection. */ 53116 isSelectionEqual(selection) { 53117 if (selection === this.state.selectedKeys()) { 53118 return true; 53119 } 53120 const selectedKeys = this.selectedKeys(); 53121 if (selection.size !== selectedKeys.size) { 53122 return false; 53123 } 53124 for (const key of selection) { 53125 if (!selectedKeys.has(key)) { 53126 return false; 53127 } 53128 } 53129 for (const key of selectedKeys) { 53130 if (!selection.has(key)) { 53131 return false; 53132 } 53133 } 53134 return true; 53135 } 53136 canSelectItem(key) { 53137 if (this.state.selectionMode() === "none") { 53138 return false; 53139 } 53140 const item = this.collection().getItem(key); 53141 return item != null && !item.disabled; 53142 } 53143 isDisabled(key) { 53144 const item = this.collection().getItem(key); 53145 return !item || item.disabled; 53146 } 53147 getAllSelectableKeys() { 53148 const keys5 = []; 53149 const addKeys = (key) => { 53150 while (key != null) { 53151 if (this.canSelectItem(key)) { 53152 const item = this.collection().getItem(key); 53153 if (!item) { 53154 continue; 53155 } 53156 if (item.type === "item") { 53157 keys5.push(key); 53158 } 53159 } 53160 key = this.collection().getKeyAfter(key); 53161 } 53162 }; 53163 addKeys(this.collection().getFirstKey()); 53164 return keys5; 53165 } 53166}; 53167var ListCollection = class { 53168 keyMap = /* @__PURE__ */ new Map(); 53169 iterable; 53170 firstKey; 53171 lastKey; 53172 constructor(nodes) { 53173 this.iterable = nodes; 53174 for (const node of nodes) { 53175 this.keyMap.set(node.key, node); 53176 } 53177 if (this.keyMap.size === 0) { 53178 return; 53179 } 53180 let last; 53181 let index = 0; 53182 for (const [key, node] of this.keyMap) { 53183 if (last) { 53184 last.nextKey = key; 53185 node.prevKey = last.key; 53186 } else { 53187 this.firstKey = key; 53188 node.prevKey = void 0; 53189 } 53190 if (node.type === "item") { 53191 node.index = index++; 53192 } 53193 last = node; 53194 last.nextKey = void 0; 53195 } 53196 this.lastKey = last.key; 53197 } 53198 *[Symbol.iterator]() { 53199 yield* this.iterable; 53200 } 53201 getSize() { 53202 return this.keyMap.size; 53203 } 53204 getKeys() { 53205 return this.keyMap.keys(); 53206 } 53207 getKeyBefore(key) { 53208 return this.keyMap.get(key)?.prevKey; 53209 } 53210 getKeyAfter(key) { 53211 return this.keyMap.get(key)?.nextKey; 53212 } 53213 getFirstKey() { 53214 return this.firstKey; 53215 } 53216 getLastKey() { 53217 return this.lastKey; 53218 } 53219 getItem(key) { 53220 return this.keyMap.get(key); 53221 } 53222 at(idx) { 53223 const keys5 = [...this.getKeys()]; 53224 return this.getItem(keys5[idx]); 53225 } 53226}; 53227function createListState(props) { 53228 const selectionState = createMultipleSelectionState(props); 53229 const factory = (nodes) => { 53230 return props.filter ? new ListCollection(props.filter(nodes)) : new ListCollection(nodes); 53231 }; 53232 const collection = createCollection( 53233 { 53234 dataSource: () => access4(props.dataSource), 53235 getKey: () => access4(props.getKey), 53236 getTextValue: () => access4(props.getTextValue), 53237 getDisabled: () => access4(props.getDisabled), 53238 getSectionChildren: () => access4(props.getSectionChildren), 53239 factory 53240 }, 53241 [() => props.filter] 53242 ); 53243 const selectionManager = new SelectionManager(collection, selectionState); 53244 createComputed(() => { 53245 const focusedKey = selectionState.focusedKey(); 53246 if (focusedKey != null && !collection().getItem(focusedKey)) { 53247 selectionState.setFocusedKey(void 0); 53248 } 53249 }); 53250 return { 53251 collection, 53252 selectionManager: () => selectionManager 53253 }; 53254} 53255
vendor: 4,332 bytes, lines 53256-53392
53256// node_modules/@kobalte/core/dist/chunk/I2LBZHJH.js 53257var ListKeyboardDelegate = class { 53258 collection; 53259 ref; 53260 collator; 53261 constructor(collection, ref, collator) { 53262 this.collection = collection; 53263 this.ref = ref; 53264 this.collator = collator; 53265 } 53266 getKeyBelow(key) { 53267 let keyAfter = this.collection().getKeyAfter(key); 53268 while (keyAfter != null) { 53269 const item = this.collection().getItem(keyAfter); 53270 if (item && item.type === "item" && !item.disabled) { 53271 return keyAfter; 53272 } 53273 keyAfter = this.collection().getKeyAfter(keyAfter); 53274 } 53275 } 53276 getKeyAbove(key) { 53277 let keyBefore = this.collection().getKeyBefore(key); 53278 while (keyBefore != null) { 53279 const item = this.collection().getItem(keyBefore); 53280 if (item && item.type === "item" && !item.disabled) { 53281 return keyBefore; 53282 } 53283 keyBefore = this.collection().getKeyBefore(keyBefore); 53284 } 53285 } 53286 getFirstKey() { 53287 let key = this.collection().getFirstKey(); 53288 while (key != null) { 53289 const item = this.collection().getItem(key); 53290 if (item && item.type === "item" && !item.disabled) { 53291 return key; 53292 } 53293 key = this.collection().getKeyAfter(key); 53294 } 53295 } 53296 getLastKey() { 53297 let key = this.collection().getLastKey(); 53298 while (key != null) { 53299 const item = this.collection().getItem(key); 53300 if (item && item.type === "item" && !item.disabled) { 53301 return key; 53302 } 53303 key = this.collection().getKeyBefore(key); 53304 } 53305 } 53306 getItem(key) { 53307 return this.ref?.()?.querySelector(`[data-key="${key}"]`) ?? null; 53308 } 53309 // TODO: not working correctly 53310 getKeyPageAbove(key) { 53311 const menu = this.ref?.(); 53312 let item = this.getItem(key); 53313 if (!menu || !item) { 53314 return; 53315 } 53316 const pageY = Math.max( 53317 0, 53318 item.offsetTop + item.offsetHeight - menu.offsetHeight 53319 ); 53320 let keyAbove = key; 53321 while (keyAbove && item && item.offsetTop > pageY) { 53322 keyAbove = this.getKeyAbove(keyAbove); 53323 item = keyAbove != null ? this.getItem(keyAbove) : null; 53324 } 53325 return keyAbove; 53326 } 53327 // TODO: not working correctly 53328 getKeyPageBelow(key) { 53329 const menu = this.ref?.(); 53330 let item = this.getItem(key); 53331 if (!menu || !item) { 53332 return; 53333 } 53334 const pageY = Math.min( 53335 menu.scrollHeight, 53336 item.offsetTop - item.offsetHeight + menu.offsetHeight 53337 ); 53338 let keyBelow = key; 53339 while (keyBelow && item && item.offsetTop < pageY) { 53340 keyBelow = this.getKeyBelow(keyBelow); 53341 item = keyBelow != null ? this.getItem(keyBelow) : null; 53342 } 53343 return keyBelow; 53344 } 53345 getKeyForSearch(search, fromKey) { 53346 const collator = this.collator?.(); 53347 if (!collator) { 53348 return; 53349 } 53350 let key = fromKey != null ? this.getKeyBelow(fromKey) : this.getFirstKey(); 53351 while (key != null) { 53352 const item = this.collection().getItem(key); 53353 if (item) { 53354 const substring = item.textValue.slice(0, search.length); 53355 if (item.textValue && collator.compare(substring, search) === 0) { 53356 return key; 53357 } 53358 } 53359 key = this.getKeyBelow(key); 53360 } 53361 } 53362}; 53363function createSelectableList(props, ref, scrollRef) { 53364 const collator = createCollator({ usage: "search", sensitivity: "base" }); 53365 const delegate = createMemo(() => { 53366 const keyboardDelegate = access4(props.keyboardDelegate); 53367 if (keyboardDelegate) { 53368 return keyboardDelegate; 53369 } 53370 return new ListKeyboardDelegate(props.collection, ref, collator); 53371 }); 53372 return createSelectableCollection( 53373 { 53374 selectionManager: () => access4(props.selectionManager), 53375 keyboardDelegate: delegate, 53376 autoFocus: () => access4(props.autoFocus), 53377 deferAutoFocus: () => access4(props.deferAutoFocus), 53378 shouldFocusWrap: () => access4(props.shouldFocusWrap), 53379 disallowEmptySelection: () => access4(props.disallowEmptySelection), 53380 selectOnFocus: () => access4(props.selectOnFocus), 53381 disallowTypeAhead: () => access4(props.disallowTypeAhead), 53382 shouldUseVirtualFocus: () => access4(props.shouldUseVirtualFocus), 53383 allowsTabNavigation: () => access4(props.allowsTabNavigation), 53384 isVirtualized: () => access4(props.isVirtualized), 53385 scrollToKey: (key) => access4(props.scrollToKey)?.(key), 53386 orientation: () => access4(props.orientation) 53387 }, 53388 ref, 53389 scrollRef 53390 ); 53391} 53392
vendor: 4,478 bytes, lines 53393-53556
53393// node_modules/@kobalte/core/dist/chunk/7CVNMTYF.js 53394var DomCollectionContext = createContext(); 53395function useOptionalDomCollectionContext() { 53396 return useContext(DomCollectionContext); 53397} 53398function useDomCollectionContext() { 53399 const context3 = useOptionalDomCollectionContext(); 53400 if (context3 === void 0) { 53401 throw new Error( 53402 "[kobalte]: `useDomCollectionContext` must be used within a `DomCollectionProvider` component" 53403 ); 53404 } 53405 return context3; 53406} 53407function isElementPreceding(a, b) { 53408 return Boolean( 53409 b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING 53410 ); 53411} 53412function findDOMIndex(items, item) { 53413 const itemEl = item.ref(); 53414 if (!itemEl) { 53415 return -1; 53416 } 53417 let length3 = items.length; 53418 if (!length3) { 53419 return -1; 53420 } 53421 while (length3--) { 53422 const currentItemEl = items[length3]?.ref(); 53423 if (!currentItemEl) { 53424 continue; 53425 } 53426 if (isElementPreceding(currentItemEl, itemEl)) { 53427 return length3 + 1; 53428 } 53429 } 53430 return 0; 53431} 53432function sortBasedOnDOMPosition(items) { 53433 const pairs = items.map((item, index) => [index, item]); 53434 let isOrderDifferent = false; 53435 pairs.sort(([indexA, a], [indexB, b]) => { 53436 const elementA = a.ref(); 53437 const elementB = b.ref(); 53438 if (elementA === elementB) { 53439 return 0; 53440 } 53441 if (!elementA || !elementB) { 53442 return 0; 53443 } 53444 if (isElementPreceding(elementA, elementB)) { 53445 if (indexA > indexB) { 53446 isOrderDifferent = true; 53447 } 53448 return -1; 53449 } 53450 if (indexA < indexB) { 53451 isOrderDifferent = true; 53452 } 53453 return 1; 53454 }); 53455 if (isOrderDifferent) { 53456 return pairs.map(([_, item]) => item); 53457 } 53458 return items; 53459} 53460function setItemsBasedOnDOMPosition(items, setItems) { 53461 const sortedItems = sortBasedOnDOMPosition(items); 53462 if (items !== sortedItems) { 53463 setItems(sortedItems); 53464 } 53465} 53466function getCommonParent(items) { 53467 const firstItem = items[0]; 53468 const lastItemEl = items[items.length - 1]?.ref(); 53469 let parentEl = firstItem?.ref()?.parentElement; 53470 while (parentEl) { 53471 if (lastItemEl && parentEl.contains(lastItemEl)) { 53472 return parentEl; 53473 } 53474 parentEl = parentEl.parentElement; 53475 } 53476 return getDocument(parentEl).body; 53477} 53478function createTimeoutObserver(items, setItems) { 53479 createEffect(() => { 53480 const timeout = setTimeout(() => { 53481 setItemsBasedOnDOMPosition(items(), setItems); 53482 }); 53483 onCleanup(() => clearTimeout(timeout)); 53484 }); 53485} 53486function createSortBasedOnDOMPosition(items, setItems) { 53487 if (typeof IntersectionObserver !== "function") { 53488 createTimeoutObserver(items, setItems); 53489 return; 53490 } 53491 let previousItems = []; 53492 createEffect(() => { 53493 const callback = () => { 53494 const hasPreviousItems = !!previousItems.length; 53495 previousItems = items(); 53496 if (!hasPreviousItems) { 53497 return; 53498 } 53499 setItemsBasedOnDOMPosition(items(), setItems); 53500 }; 53501 const root = getCommonParent(items()); 53502 const observer = new IntersectionObserver(callback, { root }); 53503 for (const item of items()) { 53504 const itemEl = item.ref(); 53505 if (itemEl) { 53506 observer.observe(itemEl); 53507 } 53508 } 53509 onCleanup(() => observer.disconnect()); 53510 }); 53511} 53512function createDomCollection(props = {}) { 53513 const [items, setItems] = createControllableArraySignal({ 53514 value: () => access4(props.items), 53515 onChange: (value) => props.onItemsChange?.(value) 53516 }); 53517 createSortBasedOnDOMPosition(items, setItems); 53518 const registerItem = (item) => { 53519 setItems((prevItems) => { 53520 const index = findDOMIndex(prevItems, item); 53521 return addItemToArray(prevItems, item, index); 53522 }); 53523 return () => { 53524 setItems((prevItems) => { 53525 const nextItems = prevItems.filter( 53526 (prevItem) => prevItem.ref() !== item.ref() 53527 ); 53528 if (prevItems.length === nextItems.length) { 53529 return prevItems; 53530 } 53531 return nextItems; 53532 }); 53533 }; 53534 }; 53535 const DomCollectionProvider = (props2) => { 53536 return createComponent(DomCollectionContext.Provider, { 53537 value: { registerItem }, 53538 get children() { 53539 return props2.children; 53540 } 53541 }); 53542 }; 53543 return { DomCollectionProvider }; 53544} 53545function createDomCollectionItem(props) { 53546 const context3 = useDomCollectionContext(); 53547 const mergedProps = mergeDefaultProps({ shouldRegisterItem: true }, props); 53548 createEffect(() => { 53549 if (!mergedProps.shouldRegisterItem) { 53550 return; 53551 } 53552 const unregister = context3.registerItem(mergedProps.getItem()); 53553 onCleanup(unregister); 53554 }); 53555} 53556
vendor: 685 bytes, lines 53557-53580
53557// node_modules/@kobalte/core/dist/chunk/YGDQXQ2B.js 53558function createToggleState(props = {}) { 53559 const [isSelected, _setIsSelected] = createControllableBooleanSignal({ 53560 value: () => access4(props.isSelected), 53561 defaultValue: () => !!access4(props.defaultIsSelected), 53562 onChange: (value) => props.onSelectedChange?.(value) 53563 }); 53564 const setIsSelected = (value) => { 53565 if (!access4(props.isReadOnly) && !access4(props.isDisabled)) { 53566 _setIsSelected(value); 53567 } 53568 }; 53569 const toggle = () => { 53570 if (!access4(props.isReadOnly) && !access4(props.isDisabled)) { 53571 _setIsSelected(!isSelected()); 53572 } 53573 }; 53574 return { 53575 isSelected, 53576 setIsSelected, 53577 toggle 53578 }; 53579} 53580
vendor: 42,399 bytes, lines 53581-54867
53581// node_modules/@kobalte/core/dist/chunk/HGKTPMYY.js 53582var MenubarContext = createContext(); 53583function useOptionalMenubarContext() { 53584 return useContext(MenubarContext); 53585} 53586function useMenubarContext() { 53587 const context3 = useOptionalMenubarContext(); 53588 if (context3 === void 0) { 53589 throw new Error("[kobalte]: `useMenubarContext` must be used within a `Menubar` component"); 53590 } 53591 return context3; 53592} 53593var NavigationMenuContext = createContext(); 53594function useOptionalNavigationMenuContext() { 53595 return useContext(NavigationMenuContext); 53596} 53597var MenuContext = createContext(); 53598function useOptionalMenuContext() { 53599 return useContext(MenuContext); 53600} 53601function useMenuContext() { 53602 const context3 = useOptionalMenuContext(); 53603 if (context3 === void 0) { 53604 throw new Error("[kobalte]: `useMenuContext` must be used within a `Menu` component"); 53605 } 53606 return context3; 53607} 53608var MenuRootContext = createContext(); 53609function useMenuRootContext() { 53610 const context3 = useContext(MenuRootContext); 53611 if (context3 === void 0) { 53612 throw new Error("[kobalte]: `useMenuRootContext` must be used within a `MenuRoot` component"); 53613 } 53614 return context3; 53615} 53616function getPointerGraceArea(placement, event, contentEl) { 53617 const basePlacement = placement.split("-")[0]; 53618 const contentRect = contentEl.getBoundingClientRect(); 53619 const polygon = []; 53620 const pointerX = event.clientX; 53621 const pointerY = event.clientY; 53622 switch (basePlacement) { 53623 case "top": 53624 polygon.push([pointerX, pointerY + 5]); 53625 polygon.push([contentRect.left, contentRect.bottom]); 53626 polygon.push([contentRect.left, contentRect.top]); 53627 polygon.push([contentRect.right, contentRect.top]); 53628 polygon.push([contentRect.right, contentRect.bottom]); 53629 break; 53630 case "right": 53631 polygon.push([pointerX - 5, pointerY]); 53632 polygon.push([contentRect.left, contentRect.top]); 53633 polygon.push([contentRect.right, contentRect.top]); 53634 polygon.push([contentRect.right, contentRect.bottom]); 53635 polygon.push([contentRect.left, contentRect.bottom]); 53636 break; 53637 case "bottom": 53638 polygon.push([pointerX, pointerY - 5]); 53639 polygon.push([contentRect.right, contentRect.top]); 53640 polygon.push([contentRect.right, contentRect.bottom]); 53641 polygon.push([contentRect.left, contentRect.bottom]); 53642 polygon.push([contentRect.left, contentRect.top]); 53643 break; 53644 case "left": 53645 polygon.push([pointerX + 5, pointerY]); 53646 polygon.push([contentRect.right, contentRect.bottom]); 53647 polygon.push([contentRect.left, contentRect.bottom]); 53648 polygon.push([contentRect.left, contentRect.top]); 53649 polygon.push([contentRect.right, contentRect.top]); 53650 break; 53651 } 53652 return polygon; 53653} 53654function isPointerInGraceArea(event, area) { 53655 if (!area) { 53656 return false; 53657 } 53658 return isPointInPolygon([event.clientX, event.clientY], area); 53659} 53660function Menu(props) { 53661 const rootContext = useMenuRootContext(); 53662 const parentDomCollectionContext = useOptionalDomCollectionContext(); 53663 const parentMenuContext = useOptionalMenuContext(); 53664 const optionalMenubarContext = useOptionalMenubarContext(); 53665 const optionalNavigationMenuContext = useOptionalNavigationMenuContext(); 53666 const mergedProps = mergeDefaultProps({ 53667 placement: rootContext.orientation() === "horizontal" ? "bottom-start" : "right-start" 53668 }, props); 53669 const [local, others] = splitProps(mergedProps, ["open", "defaultOpen", "onOpenChange"]); 53670 let pointerGraceTimeoutId = 0; 53671 let pointerGraceIntent = null; 53672 let pointerDir = "right"; 53673 const [triggerId, setTriggerId] = createSignal(); 53674 const [contentId, setContentId] = createSignal(); 53675 const [triggerRef, setTriggerRef] = createSignal(); 53676 const [contentRef, setContentRef] = createSignal(); 53677 const [focusStrategy, setFocusStrategy] = createSignal(true); 53678 const [currentPlacement, setCurrentPlacement] = createSignal(others.placement); 53679 const [nestedMenus, setNestedMenus] = createSignal([]); 53680 const [items, setItems] = createSignal([]); 53681 const { 53682 DomCollectionProvider 53683 } = createDomCollection({ 53684 items, 53685 onItemsChange: setItems 53686 }); 53687 const disclosureState = createDisclosureState({ 53688 open: () => local.open, 53689 defaultOpen: () => local.defaultOpen, 53690 onOpenChange: (isOpen) => local.onOpenChange?.(isOpen) 53691 }); 53692 const { 53693 present: contentPresent 53694 } = index_default2({ 53695 show: () => rootContext.forceMount() || disclosureState.isOpen(), 53696 element: () => contentRef() ?? null 53697 }); 53698 const listState = createListState({ 53699 selectionMode: "none", 53700 dataSource: items 53701 }); 53702 const open = (focusStrategy2) => { 53703 setFocusStrategy(focusStrategy2); 53704 disclosureState.open(); 53705 }; 53706 const close = (recursively = false) => { 53707 disclosureState.close(); 53708 if (recursively && parentMenuContext) { 53709 parentMenuContext.close(true); 53710 } 53711 }; 53712 const toggle = (focusStrategy2) => { 53713 setFocusStrategy(focusStrategy2); 53714 disclosureState.toggle(); 53715 }; 53716 const _focusContent = () => { 53717 const content = contentRef(); 53718 if (content) { 53719 focusWithoutScrolling(content); 53720 listState.selectionManager().setFocused(true); 53721 listState.selectionManager().setFocusedKey(void 0); 53722 } 53723 }; 53724 const focusContent = () => { 53725 if (optionalNavigationMenuContext != null) 53726 setTimeout(() => _focusContent()); 53727 else 53728 _focusContent(); 53729 }; 53730 const registerNestedMenu = (element3) => { 53731 setNestedMenus((prev) => [...prev, element3]); 53732 const parentUnregister = parentMenuContext?.registerNestedMenu(element3); 53733 return () => { 53734 setNestedMenus((prev) => removeItemFromArray(prev, element3)); 53735 parentUnregister?.(); 53736 }; 53737 }; 53738 const isPointerMovingToSubmenu = (e) => { 53739 const isMovingTowards = pointerDir === pointerGraceIntent?.side; 53740 return isMovingTowards && isPointerInGraceArea(e, pointerGraceIntent?.area); 53741 }; 53742 const onItemEnter = (e) => { 53743 if (isPointerMovingToSubmenu(e)) { 53744 e.preventDefault(); 53745 } 53746 }; 53747 const onItemLeave = (e) => { 53748 if (isPointerMovingToSubmenu(e)) { 53749 return; 53750 } 53751 focusContent(); 53752 }; 53753 const onTriggerLeave = (e) => { 53754 if (isPointerMovingToSubmenu(e)) { 53755 e.preventDefault(); 53756 } 53757 }; 53758 createHideOutside({ 53759 isDisabled: () => { 53760 return !(parentMenuContext == null && disclosureState.isOpen() && rootContext.isModal()); 53761 }, 53762 targets: () => [contentRef(), ...nestedMenus()].filter(Boolean) 53763 }); 53764 createEffect(() => { 53765 const contentEl = contentRef(); 53766 if (!contentEl || !parentMenuContext) { 53767 return; 53768 } 53769 const parentUnregister = parentMenuContext.registerNestedMenu(contentEl); 53770 onCleanup(() => { 53771 parentUnregister(); 53772 }); 53773 }); 53774 createEffect(() => { 53775 if (parentMenuContext !== void 0) 53776 return; 53777 optionalMenubarContext?.registerMenu(rootContext.value(), [contentRef(), ...nestedMenus()]); 53778 }); 53779 createEffect(() => { 53780 if (parentMenuContext !== void 0 || optionalMenubarContext === void 0) 53781 return; 53782 if (optionalMenubarContext.value() === rootContext.value()) { 53783 triggerRef()?.focus(); 53784 if (optionalMenubarContext.autoFocusMenu()) 53785 open(true); 53786 } else 53787 close(); 53788 }); 53789 createEffect(() => { 53790 if (parentMenuContext !== void 0 || optionalMenubarContext === void 0) 53791 return; 53792 if (disclosureState.isOpen()) 53793 optionalMenubarContext.setValue(rootContext.value()); 53794 }); 53795 onCleanup(() => { 53796 if (parentMenuContext !== void 0) 53797 return; 53798 optionalMenubarContext?.unregisterMenu(rootContext.value()); 53799 }); 53800 const dataset = createMemo(() => ({ 53801 "data-expanded": disclosureState.isOpen() ? "" : void 0, 53802 "data-closed": !disclosureState.isOpen() ? "" : void 0 53803 })); 53804 const context3 = { 53805 dataset, 53806 isOpen: disclosureState.isOpen, 53807 contentPresent, 53808 nestedMenus, 53809 currentPlacement, 53810 pointerGraceTimeoutId: () => pointerGraceTimeoutId, 53811 autoFocus: focusStrategy, 53812 listState: () => listState, 53813 parentMenuContext: () => parentMenuContext, 53814 triggerRef, 53815 contentRef, 53816 triggerId, 53817 contentId, 53818 setTriggerRef, 53819 setContentRef, 53820 open, 53821 close, 53822 toggle, 53823 focusContent, 53824 onItemEnter, 53825 onItemLeave, 53826 onTriggerLeave, 53827 setPointerDir: (dir) => pointerDir = dir, 53828 setPointerGraceTimeoutId: (id) => pointerGraceTimeoutId = id, 53829 setPointerGraceIntent: (intent) => pointerGraceIntent = intent, 53830 registerNestedMenu, 53831 registerItemToParentDomCollection: parentDomCollectionContext?.registerItem, 53832 registerTriggerId: createRegisterId(setTriggerId), 53833 registerContentId: createRegisterId(setContentId) 53834 }; 53835 return createComponent(DomCollectionProvider, { 53836 get children() { 53837 return createComponent(MenuContext.Provider, { 53838 value: context3, 53839 get children() { 53840 return createComponent(Show, { 53841 when: optionalNavigationMenuContext === void 0, 53842 get fallback() { 53843 return others.children; 53844 }, 53845 get children() { 53846 return createComponent(Popper, mergeProps({ 53847 anchorRef: triggerRef, 53848 contentRef, 53849 onCurrentPlacementChange: setCurrentPlacement 53850 }, others)); 53851 } 53852 }); 53853 } 53854 }); 53855 } 53856 }); 53857} 53858var MenuItemContext = createContext(); 53859function useMenuItemContext() { 53860 const context3 = useContext(MenuItemContext); 53861 if (context3 === void 0) { 53862 throw new Error("[kobalte]: `useMenuItemContext` must be used within a `Menu.Item` component"); 53863 } 53864 return context3; 53865} 53866function MenuItemBase(props) { 53867 let ref; 53868 const rootContext = useMenuRootContext(); 53869 const menuContext = useMenuContext(); 53870 const mergedProps = mergeDefaultProps({ 53871 id: rootContext.generateId(`item-${createUniqueId()}`) 53872 }, props); 53873 const [local, others] = splitProps(mergedProps, ["ref", "textValue", "disabled", "closeOnSelect", "checked", "indeterminate", "onSelect", "onPointerMove", "onPointerLeave", "onPointerDown", "onPointerUp", "onClick", "onKeyDown", "onMouseDown", "onFocus"]); 53874 const [labelId, setLabelId] = createSignal(); 53875 const [descriptionId, setDescriptionId] = createSignal(); 53876 const [labelRef, setLabelRef] = createSignal(); 53877 const selectionManager = () => menuContext.listState().selectionManager(); 53878 const key = () => others.id; 53879 const isHighlighted = () => selectionManager().focusedKey() === key(); 53880 const onSelect = () => { 53881 local.onSelect?.(); 53882 if (local.closeOnSelect) { 53883 setTimeout( 53884 () => { 53885 menuContext.close(true); 53886 }, 53887 // Fix #446 53888 // Requires a delay for NavigationMenu to work on mobile. 53889 1 53890 ); 53891 } 53892 }; 53893 createDomCollectionItem({ 53894 getItem: () => ({ 53895 ref: () => ref, 53896 type: "item", 53897 key: key(), 53898 textValue: local.textValue ?? labelRef()?.textContent ?? ref?.textContent ?? "", 53899 disabled: local.disabled ?? false 53900 }) 53901 }); 53902 const selectableItem = createSelectableItem({ 53903 key, 53904 selectionManager, 53905 shouldSelectOnPressUp: true, 53906 allowsDifferentPressOrigin: true, 53907 disabled: () => local.disabled 53908 }, () => ref); 53909 const onPointerMove = (e) => { 53910 callHandler(e, local.onPointerMove); 53911 if (e.pointerType !== "mouse") { 53912 return; 53913 } 53914 if (local.disabled) { 53915 menuContext.onItemLeave(e); 53916 } else { 53917 menuContext.onItemEnter(e); 53918 if (!e.defaultPrevented) { 53919 focusWithoutScrolling(e.currentTarget); 53920 menuContext.listState().selectionManager().setFocused(true); 53921 menuContext.listState().selectionManager().setFocusedKey(key()); 53922 } 53923 } 53924 }; 53925 const onPointerLeave = (e) => { 53926 callHandler(e, local.onPointerLeave); 53927 if (e.pointerType !== "mouse") { 53928 return; 53929 } 53930 menuContext.onItemLeave(e); 53931 }; 53932 const onPointerUp = (e) => { 53933 callHandler(e, local.onPointerUp); 53934 if (!local.disabled && e.button === 0) { 53935 onSelect(); 53936 } 53937 }; 53938 const onKeyDown = (e) => { 53939 callHandler(e, local.onKeyDown); 53940 if (e.repeat) { 53941 return; 53942 } 53943 if (local.disabled) { 53944 return; 53945 } 53946 switch (e.key) { 53947 case "Enter": 53948 case " ": 53949 onSelect(); 53950 break; 53951 } 53952 }; 53953 const ariaChecked = createMemo(() => { 53954 if (local.indeterminate) { 53955 return "mixed"; 53956 } 53957 if (local.checked == null) { 53958 return void 0; 53959 } 53960 return local.checked; 53961 }); 53962 const dataset = createMemo(() => ({ 53963 "data-indeterminate": local.indeterminate ? "" : void 0, 53964 "data-checked": local.checked && !local.indeterminate ? "" : void 0, 53965 "data-disabled": local.disabled ? "" : void 0, 53966 "data-highlighted": isHighlighted() ? "" : void 0 53967 })); 53968 const context3 = { 53969 isChecked: () => local.checked, 53970 dataset, 53971 setLabelRef, 53972 generateId: createGenerateId(() => others.id), 53973 registerLabel: createRegisterId(setLabelId), 53974 registerDescription: createRegisterId(setDescriptionId) 53975 }; 53976 return createComponent(MenuItemContext.Provider, { 53977 value: context3, 53978 get children() { 53979 return createComponent(Polymorphic, mergeProps({ 53980 as: "div", 53981 ref(r$) { 53982 const _ref$ = mergeRefs((el) => ref = el, local.ref); 53983 typeof _ref$ === "function" && _ref$(r$); 53984 }, 53985 get tabIndex() { 53986 return selectableItem.tabIndex(); 53987 }, 53988 get ["aria-checked"]() { 53989 return ariaChecked(); 53990 }, 53991 get ["aria-disabled"]() { 53992 return local.disabled; 53993 }, 53994 get ["aria-labelledby"]() { 53995 return labelId(); 53996 }, 53997 get ["aria-describedby"]() { 53998 return descriptionId(); 53999 }, 54000 get ["data-key"]() { 54001 return selectableItem.dataKey(); 54002 }, 54003 get onPointerDown() { 54004 return composeEventHandlers([local.onPointerDown, selectableItem.onPointerDown]); 54005 }, 54006 get onPointerUp() { 54007 return composeEventHandlers([onPointerUp, selectableItem.onPointerUp]); 54008 }, 54009 get onClick() { 54010 return composeEventHandlers([local.onClick, selectableItem.onClick]); 54011 }, 54012 get onKeyDown() { 54013 return composeEventHandlers([onKeyDown, selectableItem.onKeyDown]); 54014 }, 54015 get onMouseDown() { 54016 return composeEventHandlers([local.onMouseDown, selectableItem.onMouseDown]); 54017 }, 54018 get onFocus() { 54019 return composeEventHandlers([local.onFocus, selectableItem.onFocus]); 54020 }, 54021 onPointerMove, 54022 onPointerLeave 54023 }, dataset, others)); 54024 } 54025 }); 54026} 54027function MenuCheckboxItem(props) { 54028 const mergedProps = mergeDefaultProps({ 54029 closeOnSelect: false 54030 }, props); 54031 const [local, others] = splitProps(mergedProps, ["checked", "defaultChecked", "onChange", "onSelect"]); 54032 const state = createToggleState({ 54033 isSelected: () => local.checked, 54034 defaultIsSelected: () => local.defaultChecked, 54035 onSelectedChange: (checked) => local.onChange?.(checked), 54036 isDisabled: () => others.disabled 54037 }); 54038 const onSelect = () => { 54039 local.onSelect?.(); 54040 state.toggle(); 54041 }; 54042 return createComponent(MenuItemBase, mergeProps({ 54043 role: "menuitemcheckbox", 54044 get checked() { 54045 return state.isSelected(); 54046 }, 54047 onSelect 54048 }, others)); 54049} 54050var MENUBAR_KEYS = { 54051 next: (dir, orientation) => dir === "ltr" ? orientation === "horizontal" ? "ArrowRight" : "ArrowDown" : orientation === "horizontal" ? "ArrowLeft" : "ArrowUp", 54052 previous: (dir, orientation) => MENUBAR_KEYS.next(dir === "ltr" ? "rtl" : "ltr", orientation) 54053}; 54054var MENU_KEYS = { 54055 first: (orientation) => orientation === "horizontal" ? "ArrowDown" : "ArrowRight", 54056 last: (orientation) => orientation === "horizontal" ? "ArrowUp" : "ArrowLeft" 54057}; 54058function MenuTrigger(props) { 54059 const rootContext = useMenuRootContext(); 54060 const context3 = useMenuContext(); 54061 const optionalMenubarContext = useOptionalMenubarContext(); 54062 const { 54063 direction 54064 } = useLocale(); 54065 const mergedProps = mergeDefaultProps({ 54066 id: rootContext.generateId("trigger") 54067 }, props); 54068 const [local, others] = splitProps(mergedProps, ["ref", "id", "disabled", "onPointerDown", "onClick", "onKeyDown", "onMouseOver", "onFocus"]); 54069 let key = () => rootContext.value(); 54070 if (optionalMenubarContext !== void 0) { 54071 key = () => rootContext.value() ?? local.id; 54072 if (optionalMenubarContext.lastValue() === void 0) 54073 optionalMenubarContext.setLastValue(key); 54074 } 54075 const tagName = createTagName(() => context3.triggerRef(), () => "button"); 54076 const isNativeLink = createMemo(() => { 54077 return tagName() === "a" && context3.triggerRef()?.getAttribute("href") != null; 54078 }); 54079 createEffect(on(() => optionalMenubarContext?.value(), (value) => { 54080 if (!isNativeLink()) 54081 return; 54082 if (value === key()) 54083 context3.triggerRef()?.focus(); 54084 })); 54085 const handleClick = () => { 54086 if (optionalMenubarContext !== void 0) { 54087 if (!context3.isOpen()) { 54088 if (!optionalMenubarContext.autoFocusMenu()) { 54089 optionalMenubarContext.setAutoFocusMenu(true); 54090 } 54091 context3.open(false); 54092 } else { 54093 if (optionalMenubarContext.value() === key()) 54094 optionalMenubarContext.closeMenu(); 54095 } 54096 } else 54097 context3.toggle(true); 54098 }; 54099 const onPointerDown = (e) => { 54100 callHandler(e, local.onPointerDown); 54101 e.currentTarget.dataset.pointerType = e.pointerType; 54102 if (!local.disabled && e.pointerType !== "touch" && e.button === 0) { 54103 handleClick(); 54104 } 54105 }; 54106 const onClick = (e) => { 54107 callHandler(e, local.onClick); 54108 if (!local.disabled) { 54109 if (e.currentTarget.dataset.pointerType === "touch") 54110 handleClick(); 54111 } 54112 }; 54113 const onKeyDown = (e) => { 54114 callHandler(e, local.onKeyDown); 54115 if (local.disabled) { 54116 return; 54117 } 54118 if (isNativeLink()) { 54119 switch (e.key) { 54120 case "Enter": 54121 case " ": 54122 return; 54123 } 54124 } 54125 switch (e.key) { 54126 case "Enter": 54127 case " ": 54128 case MENU_KEYS.first(rootContext.orientation()): 54129 e.stopPropagation(); 54130 e.preventDefault(); 54131 scrollIntoViewport(e.currentTarget); 54132 context3.open("first"); 54133 optionalMenubarContext?.setAutoFocusMenu(true); 54134 optionalMenubarContext?.setValue(key); 54135 break; 54136 case MENU_KEYS.last(rootContext.orientation()): 54137 e.stopPropagation(); 54138 e.preventDefault(); 54139 context3.open("last"); 54140 break; 54141 case MENUBAR_KEYS.next(direction(), rootContext.orientation()): 54142 if (optionalMenubarContext === void 0) 54143 break; 54144 e.stopPropagation(); 54145 e.preventDefault(); 54146 optionalMenubarContext.nextMenu(); 54147 break; 54148 case MENUBAR_KEYS.previous(direction(), rootContext.orientation()): 54149 if (optionalMenubarContext === void 0) 54150 break; 54151 e.stopPropagation(); 54152 e.preventDefault(); 54153 optionalMenubarContext.previousMenu(); 54154 break; 54155 } 54156 }; 54157 const onMouseOver = (e) => { 54158 callHandler(e, local.onMouseOver); 54159 if (context3.triggerRef()?.dataset.pointerType === "touch") 54160 return; 54161 if (!local.disabled && optionalMenubarContext !== void 0 && optionalMenubarContext.value() !== void 0) { 54162 optionalMenubarContext.setValue(key); 54163 } 54164 }; 54165 const onFocus = (e) => { 54166 callHandler(e, local.onFocus); 54167 if (optionalMenubarContext !== void 0 && e.currentTarget.dataset.pointerType !== "touch") 54168 optionalMenubarContext.setValue(key); 54169 }; 54170 createEffect(() => onCleanup(context3.registerTriggerId(local.id))); 54171 return createComponent(ButtonRoot, mergeProps({ 54172 ref(r$) { 54173 const _ref$ = mergeRefs(context3.setTriggerRef, local.ref); 54174 typeof _ref$ === "function" && _ref$(r$); 54175 }, 54176 get ["data-kb-menu-value-trigger"]() { 54177 return rootContext.value(); 54178 }, 54179 get id() { 54180 return local.id; 54181 }, 54182 get disabled() { 54183 return local.disabled; 54184 }, 54185 "aria-haspopup": "true", 54186 get ["aria-expanded"]() { 54187 return context3.isOpen(); 54188 }, 54189 get ["aria-controls"]() { 54190 return memo(() => !!context3.isOpen())() ? context3.contentId() : void 0; 54191 }, 54192 get ["data-highlighted"]() { 54193 return key() !== void 0 && optionalMenubarContext?.value() === key() ? true : void 0; 54194 }, 54195 get tabIndex() { 54196 return optionalMenubarContext !== void 0 ? optionalMenubarContext.value() === key() || optionalMenubarContext.lastValue() === key() ? 0 : -1 : void 0; 54197 }, 54198 onPointerDown, 54199 onMouseOver, 54200 onClick, 54201 onKeyDown, 54202 onFocus, 54203 role: optionalMenubarContext !== void 0 ? "menuitem" : void 0 54204 }, () => context3.dataset(), others)); 54205} 54206function MenuContentBase(props) { 54207 let ref; 54208 const rootContext = useMenuRootContext(); 54209 const context3 = useMenuContext(); 54210 const optionalMenubarContext = useOptionalMenubarContext(); 54211 const optionalNavigationMenuContext = useOptionalNavigationMenuContext(); 54212 const { 54213 direction 54214 } = useLocale(); 54215 const mergedProps = mergeDefaultProps({ 54216 id: rootContext.generateId(`content-${createUniqueId()}`) 54217 }, props); 54218 const [local, others] = splitProps(mergedProps, ["ref", "id", "style", "onOpenAutoFocus", "onCloseAutoFocus", "onEscapeKeyDown", "onFocusOutside", "onPointerEnter", "onPointerMove", "onKeyDown", "onMouseDown", "onFocusIn", "onFocusOut"]); 54219 let lastPointerX = 0; 54220 const isRootModalContent = () => { 54221 return context3.parentMenuContext() == null && optionalMenubarContext === void 0 && rootContext.isModal(); 54222 }; 54223 const selectableList = createSelectableList({ 54224 selectionManager: context3.listState().selectionManager, 54225 collection: context3.listState().collection, 54226 autoFocus: context3.autoFocus, 54227 deferAutoFocus: true, 54228 // ensure all menu items are mounted and collection is not empty before trying to autofocus. 54229 shouldFocusWrap: true, 54230 disallowTypeAhead: () => !context3.listState().selectionManager().isFocused(), 54231 orientation: () => rootContext.orientation() === "horizontal" ? "vertical" : "horizontal" 54232 }, () => ref); 54233 createFocusScope({ 54234 trapFocus: () => isRootModalContent() && context3.isOpen(), 54235 onMountAutoFocus: (event) => { 54236 if (optionalMenubarContext === void 0) 54237 local.onOpenAutoFocus?.(event); 54238 }, 54239 onUnmountAutoFocus: local.onCloseAutoFocus 54240 }, () => ref); 54241 const onKeyDown = (e) => { 54242 if (!contains(e.currentTarget, e.target)) { 54243 return; 54244 } 54245 if (e.key === "Tab" && context3.isOpen()) { 54246 e.preventDefault(); 54247 } 54248 if (optionalMenubarContext !== void 0) { 54249 if (e.currentTarget.getAttribute("aria-haspopup") !== "true") 54250 switch (e.key) { 54251 case MENUBAR_KEYS.next(direction(), rootContext.orientation()): 54252 e.stopPropagation(); 54253 e.preventDefault(); 54254 context3.close(true); 54255 optionalMenubarContext.setAutoFocusMenu(true); 54256 optionalMenubarContext.nextMenu(); 54257 break; 54258 case MENUBAR_KEYS.previous(direction(), rootContext.orientation()): 54259 if (e.currentTarget.hasAttribute("data-closed")) 54260 break; 54261 e.stopPropagation(); 54262 e.preventDefault(); 54263 context3.close(true); 54264 optionalMenubarContext.setAutoFocusMenu(true); 54265 optionalMenubarContext.previousMenu(); 54266 break; 54267 } 54268 } 54269 }; 54270 const onEscapeKeyDown = (e) => { 54271 local.onEscapeKeyDown?.(e); 54272 optionalMenubarContext?.setAutoFocusMenu(false); 54273 context3.close(true); 54274 }; 54275 const onFocusOutside = (e) => { 54276 local.onFocusOutside?.(e); 54277 if (rootContext.isModal()) { 54278 e.preventDefault(); 54279 } 54280 }; 54281 const onPointerEnter = (e) => { 54282 callHandler(e, local.onPointerEnter); 54283 if (!context3.isOpen()) { 54284 return; 54285 } 54286 context3.parentMenuContext()?.listState().selectionManager().setFocused(false); 54287 context3.parentMenuContext()?.listState().selectionManager().setFocusedKey(void 0); 54288 }; 54289 const onPointerMove = (e) => { 54290 callHandler(e, local.onPointerMove); 54291 if (e.pointerType !== "mouse") { 54292 return; 54293 } 54294 const target = e.target; 54295 const pointerXHasChanged = lastPointerX !== e.clientX; 54296 if (contains(e.currentTarget, target) && pointerXHasChanged) { 54297 context3.setPointerDir(e.clientX > lastPointerX ? "right" : "left"); 54298 lastPointerX = e.clientX; 54299 } 54300 }; 54301 createEffect(() => onCleanup(context3.registerContentId(local.id))); 54302 onCleanup(() => context3.setContentRef(void 0)); 54303 const commonAttributes = { 54304 ref: mergeRefs((el) => { 54305 context3.setContentRef(el); 54306 ref = el; 54307 }, local.ref), 54308 role: "menu", 54309 get id() { 54310 return local.id; 54311 }, 54312 get tabIndex() { 54313 return selectableList.tabIndex(); 54314 }, 54315 get "aria-labelledby"() { 54316 return context3.triggerId(); 54317 }, 54318 onKeyDown: composeEventHandlers([local.onKeyDown, selectableList.onKeyDown, onKeyDown]), 54319 onMouseDown: composeEventHandlers([local.onMouseDown, selectableList.onMouseDown]), 54320 onFocusIn: composeEventHandlers([local.onFocusIn, selectableList.onFocusIn]), 54321 onFocusOut: composeEventHandlers([local.onFocusOut, selectableList.onFocusOut]), 54322 onPointerEnter, 54323 onPointerMove, 54324 get "data-orientation"() { 54325 return rootContext.orientation(); 54326 } 54327 }; 54328 return createComponent(Show, { 54329 get when() { 54330 return context3.contentPresent(); 54331 }, 54332 get children() { 54333 return createComponent(Show, { 54334 get when() { 54335 return optionalNavigationMenuContext === void 0 || context3.parentMenuContext() != null; 54336 }, 54337 get fallback() { 54338 return createComponent(Polymorphic, mergeProps({ 54339 as: "div" 54340 }, () => context3.dataset(), commonAttributes, others)); 54341 }, 54342 get children() { 54343 return createComponent(Popper.Positioner, { 54344 get children() { 54345 return createComponent(DismissableLayer, mergeProps({ 54346 get disableOutsidePointerEvents() { 54347 return memo(() => !!isRootModalContent())() && context3.isOpen(); 54348 }, 54349 get excludedElements() { 54350 return [context3.triggerRef]; 54351 }, 54352 bypassTopMostLayerCheck: true, 54353 get style() { 54354 return combineStyle({ 54355 "--kb-menu-content-transform-origin": "var(--kb-popper-content-transform-origin)", 54356 position: "relative" 54357 }, local.style); 54358 }, 54359 onEscapeKeyDown, 54360 onFocusOutside, 54361 get onDismiss() { 54362 return context3.close; 54363 } 54364 }, () => context3.dataset(), commonAttributes, others)); 54365 } 54366 }); 54367 } 54368 }); 54369 } 54370 }); 54371} 54372function MenuContent(props) { 54373 let ref; 54374 const rootContext = useMenuRootContext(); 54375 const context3 = useMenuContext(); 54376 const [local, others] = splitProps(props, ["ref"]); 54377 index_default({ 54378 element: () => ref ?? null, 54379 enabled: () => context3.contentPresent() && rootContext.preventScroll() 54380 }); 54381 return createComponent(MenuContentBase, mergeProps({ 54382 ref(r$) { 54383 const _ref$ = mergeRefs((el) => { 54384 ref = el; 54385 }, local.ref); 54386 typeof _ref$ === "function" && _ref$(r$); 54387 } 54388 }, others)); 54389} 54390var MenuGroupContext = createContext(); 54391function useMenuGroupContext() { 54392 const context3 = useContext(MenuGroupContext); 54393 if (context3 === void 0) { 54394 throw new Error("[kobalte]: `useMenuGroupContext` must be used within a `Menu.Group` component"); 54395 } 54396 return context3; 54397} 54398function MenuGroup(props) { 54399 const rootContext = useMenuRootContext(); 54400 const mergedProps = mergeDefaultProps({ 54401 id: rootContext.generateId(`group-${createUniqueId()}`) 54402 }, props); 54403 const [labelId, setLabelId] = createSignal(); 54404 const context3 = { 54405 generateId: createGenerateId(() => mergedProps.id), 54406 registerLabelId: createRegisterId(setLabelId) 54407 }; 54408 return createComponent(MenuGroupContext.Provider, { 54409 value: context3, 54410 get children() { 54411 return createComponent(Polymorphic, mergeProps({ 54412 as: "div", 54413 role: "group", 54414 get ["aria-labelledby"]() { 54415 return labelId(); 54416 } 54417 }, mergedProps)); 54418 } 54419 }); 54420} 54421function MenuGroupLabel(props) { 54422 const context3 = useMenuGroupContext(); 54423 const mergedProps = mergeDefaultProps({ 54424 id: context3.generateId("label") 54425 }, props); 54426 const [local, others] = splitProps(mergedProps, ["id"]); 54427 createEffect(() => onCleanup(context3.registerLabelId(local.id))); 54428 return createComponent(Polymorphic, mergeProps({ 54429 as: "span", 54430 get id() { 54431 return local.id; 54432 }, 54433 "aria-hidden": "true" 54434 }, others)); 54435} 54436function MenuIcon(props) { 54437 const context3 = useMenuContext(); 54438 const mergedProps = mergeDefaultProps({ 54439 children: "\u25BC" 54440 }, props); 54441 return createComponent(Polymorphic, mergeProps({ 54442 as: "span", 54443 "aria-hidden": "true" 54444 }, () => context3.dataset(), mergedProps)); 54445} 54446function MenuItem(props) { 54447 return createComponent(MenuItemBase, mergeProps({ 54448 role: "menuitem", 54449 closeOnSelect: true 54450 }, props)); 54451} 54452function MenuItemDescription(props) { 54453 const context3 = useMenuItemContext(); 54454 const mergedProps = mergeDefaultProps({ 54455 id: context3.generateId("description") 54456 }, props); 54457 const [local, others] = splitProps(mergedProps, ["id"]); 54458 createEffect(() => onCleanup(context3.registerDescription(local.id))); 54459 return createComponent(Polymorphic, mergeProps({ 54460 as: "div", 54461 get id() { 54462 return local.id; 54463 } 54464 }, () => context3.dataset(), others)); 54465} 54466function MenuItemIndicator(props) { 54467 const context3 = useMenuItemContext(); 54468 const mergedProps = mergeDefaultProps({ 54469 id: context3.generateId("indicator") 54470 }, props); 54471 const [local, others] = splitProps(mergedProps, ["forceMount"]); 54472 return createComponent(Show, { 54473 get when() { 54474 return local.forceMount || context3.isChecked(); 54475 }, 54476 get children() { 54477 return createComponent(Polymorphic, mergeProps({ 54478 as: "div" 54479 }, () => context3.dataset(), others)); 54480 } 54481 }); 54482} 54483function MenuItemLabel(props) { 54484 const context3 = useMenuItemContext(); 54485 const mergedProps = mergeDefaultProps({ 54486 id: context3.generateId("label") 54487 }, props); 54488 const [local, others] = splitProps(mergedProps, ["ref", "id"]); 54489 createEffect(() => onCleanup(context3.registerLabel(local.id))); 54490 return createComponent(Polymorphic, mergeProps({ 54491 as: "div", 54492 ref(r$) { 54493 const _ref$ = mergeRefs(context3.setLabelRef, local.ref); 54494 typeof _ref$ === "function" && _ref$(r$); 54495 }, 54496 get id() { 54497 return local.id; 54498 } 54499 }, () => context3.dataset(), others)); 54500} 54501function MenuPortal(props) { 54502 const context3 = useMenuContext(); 54503 return createComponent(Show, { 54504 get when() { 54505 return context3.contentPresent(); 54506 }, 54507 get children() { 54508 return createComponent(Portal, props); 54509 } 54510 }); 54511} 54512var MenuRadioGroupContext = createContext(); 54513function useMenuRadioGroupContext() { 54514 const context3 = useContext(MenuRadioGroupContext); 54515 if (context3 === void 0) { 54516 throw new Error("[kobalte]: `useMenuRadioGroupContext` must be used within a `Menu.RadioGroup` component"); 54517 } 54518 return context3; 54519} 54520function MenuRadioGroup(props) { 54521 const rootContext = useMenuRootContext(); 54522 const defaultId = rootContext.generateId(`radiogroup-${createUniqueId()}`); 54523 const mergedProps = mergeDefaultProps({ 54524 id: defaultId 54525 }, props); 54526 const [local, others] = splitProps(mergedProps, ["value", "defaultValue", "onChange", "disabled"]); 54527 const [selected, setSelected] = createControllableSignal({ 54528 value: () => local.value, 54529 defaultValue: () => local.defaultValue, 54530 onChange: (value) => local.onChange?.(value) 54531 }); 54532 const context3 = { 54533 isDisabled: () => local.disabled, 54534 isSelectedValue: (value) => value === selected(), 54535 setSelectedValue: (value) => setSelected(value) 54536 }; 54537 return createComponent(MenuRadioGroupContext.Provider, { 54538 value: context3, 54539 get children() { 54540 return createComponent(MenuGroup, others); 54541 } 54542 }); 54543} 54544function MenuRadioItem(props) { 54545 const context3 = useMenuRadioGroupContext(); 54546 const mergedProps = mergeDefaultProps({ 54547 closeOnSelect: false 54548 }, props); 54549 const [local, others] = splitProps(mergedProps, ["value", "onSelect"]); 54550 const onSelect = () => { 54551 local.onSelect?.(); 54552 context3.setSelectedValue(local.value); 54553 }; 54554 return createComponent(MenuItemBase, mergeProps({ 54555 role: "menuitemradio", 54556 get checked() { 54557 return context3.isSelectedValue(local.value); 54558 }, 54559 onSelect 54560 }, others)); 54561} 54562function MenuRoot(props) { 54563 const optionalMenubarContext = useOptionalMenubarContext(); 54564 const defaultId = `menu-${createUniqueId()}`; 54565 const mergedProps = mergeDefaultProps({ 54566 id: defaultId, 54567 modal: true 54568 }, props); 54569 const [local, others] = splitProps(mergedProps, ["id", "modal", "preventScroll", "forceMount", "open", "defaultOpen", "onOpenChange", "value", "orientation"]); 54570 const disclosureState = createDisclosureState({ 54571 open: () => local.open, 54572 defaultOpen: () => local.defaultOpen, 54573 onOpenChange: (isOpen) => local.onOpenChange?.(isOpen) 54574 }); 54575 const context3 = { 54576 isModal: () => local.modal ?? true, 54577 preventScroll: () => local.preventScroll ?? context3.isModal(), 54578 forceMount: () => local.forceMount ?? false, 54579 generateId: createGenerateId(() => local.id), 54580 value: () => local.value, 54581 orientation: () => local.orientation ?? optionalMenubarContext?.orientation() ?? "horizontal" 54582 }; 54583 return createComponent(MenuRootContext.Provider, { 54584 value: context3, 54585 get children() { 54586 return createComponent(Menu, mergeProps({ 54587 get open() { 54588 return disclosureState.isOpen(); 54589 }, 54590 get onOpenChange() { 54591 return disclosureState.setIsOpen; 54592 } 54593 }, others)); 54594 } 54595 }); 54596} 54597function MenuSub(props) { 54598 const { 54599 direction 54600 } = useLocale(); 54601 return createComponent(Menu, mergeProps({ 54602 get placement() { 54603 return direction() === "rtl" ? "left-start" : "right-start"; 54604 }, 54605 flip: true 54606 }, props)); 54607} 54608var SUB_CLOSE_KEYS = { 54609 close: (dir, orientation) => { 54610 if (dir === "ltr") { 54611 return [orientation === "horizontal" ? "ArrowLeft" : "ArrowUp"]; 54612 } 54613 return [orientation === "horizontal" ? "ArrowRight" : "ArrowDown"]; 54614 } 54615}; 54616function MenuSubContent(props) { 54617 const context3 = useMenuContext(); 54618 const rootContext = useMenuRootContext(); 54619 const [local, others] = splitProps(props, ["onFocusOutside", "onKeyDown"]); 54620 const { 54621 direction 54622 } = useLocale(); 54623 const onOpenAutoFocus = (e) => { 54624 e.preventDefault(); 54625 }; 54626 const onCloseAutoFocus = (e) => { 54627 e.preventDefault(); 54628 }; 54629 const onFocusOutside = (e) => { 54630 local.onFocusOutside?.(e); 54631 const target = e.target; 54632 if (!contains(context3.triggerRef(), target)) { 54633 context3.close(); 54634 } 54635 }; 54636 const onKeyDown = (e) => { 54637 callHandler(e, local.onKeyDown); 54638 const isKeyDownInside = contains(e.currentTarget, e.target); 54639 const isCloseKey = SUB_CLOSE_KEYS.close(direction(), rootContext.orientation()).includes(e.key); 54640 const isSubMenu = context3.parentMenuContext() != null; 54641 if (isKeyDownInside && isCloseKey && isSubMenu) { 54642 context3.close(); 54643 focusWithoutScrolling(context3.triggerRef()); 54644 } 54645 }; 54646 return createComponent(MenuContentBase, mergeProps({ 54647 onOpenAutoFocus, 54648 onCloseAutoFocus, 54649 onFocusOutside, 54650 onKeyDown 54651 }, others)); 54652} 54653var SELECTION_KEYS = ["Enter", " "]; 54654var SUB_OPEN_KEYS = { 54655 open: (dir, orientation) => { 54656 if (dir === "ltr") { 54657 return [...SELECTION_KEYS, orientation === "horizontal" ? "ArrowRight" : "ArrowDown"]; 54658 } 54659 return [...SELECTION_KEYS, orientation === "horizontal" ? "ArrowLeft" : "ArrowUp"]; 54660 } 54661}; 54662function MenuSubTrigger(props) { 54663 let ref; 54664 const rootContext = useMenuRootContext(); 54665 const context3 = useMenuContext(); 54666 const mergedProps = mergeDefaultProps({ 54667 id: rootContext.generateId(`sub-trigger-${createUniqueId()}`) 54668 }, props); 54669 const [local, others] = splitProps(mergedProps, ["ref", "id", "textValue", "disabled", "onPointerMove", "onPointerLeave", "onPointerDown", "onPointerUp", "onClick", "onKeyDown", "onMouseDown", "onFocus"]); 54670 let openTimeoutId = null; 54671 const clearOpenTimeout = () => { 54672 if (isServer) { 54673 return; 54674 } 54675 if (openTimeoutId) { 54676 window.clearTimeout(openTimeoutId); 54677 } 54678 openTimeoutId = null; 54679 }; 54680 const { 54681 direction 54682 } = useLocale(); 54683 const key = () => local.id; 54684 const parentSelectionManager = () => { 54685 const parentMenuContext = context3.parentMenuContext(); 54686 if (parentMenuContext == null) { 54687 throw new Error("[kobalte]: `Menu.SubTrigger` must be used within a `Menu.Sub` component"); 54688 } 54689 return parentMenuContext.listState().selectionManager(); 54690 }; 54691 const collection = () => context3.listState().collection(); 54692 const isHighlighted = () => parentSelectionManager().focusedKey() === key(); 54693 const selectableItem = createSelectableItem({ 54694 key, 54695 selectionManager: parentSelectionManager, 54696 shouldSelectOnPressUp: true, 54697 allowsDifferentPressOrigin: true, 54698 disabled: () => local.disabled 54699 }, () => ref); 54700 const onClick = (e) => { 54701 callHandler(e, local.onClick); 54702 if (!context3.isOpen() && !local.disabled) { 54703 context3.open(true); 54704 } 54705 }; 54706 const onPointerMove = (e) => { 54707 callHandler(e, local.onPointerMove); 54708 if (e.pointerType !== "mouse") { 54709 return; 54710 } 54711 const parentMenuContext = context3.parentMenuContext(); 54712 parentMenuContext?.onItemEnter(e); 54713 if (e.defaultPrevented) { 54714 return; 54715 } 54716 if (local.disabled) { 54717 parentMenuContext?.onItemLeave(e); 54718 return; 54719 } 54720 if (!context3.isOpen() && !openTimeoutId) { 54721 context3.parentMenuContext()?.setPointerGraceIntent(null); 54722 openTimeoutId = window.setTimeout(() => { 54723 context3.open(false); 54724 clearOpenTimeout(); 54725 }, 100); 54726 } 54727 parentMenuContext?.onItemEnter(e); 54728 if (!e.defaultPrevented) { 54729 if (context3.listState().selectionManager().isFocused()) { 54730 context3.listState().selectionManager().setFocused(false); 54731 context3.listState().selectionManager().setFocusedKey(void 0); 54732 } 54733 focusWithoutScrolling(e.currentTarget); 54734 parentMenuContext?.listState().selectionManager().setFocused(true); 54735 parentMenuContext?.listState().selectionManager().setFocusedKey(key()); 54736 } 54737 }; 54738 const onPointerLeave = (e) => { 54739 callHandler(e, local.onPointerLeave); 54740 if (e.pointerType !== "mouse") { 54741 return; 54742 } 54743 clearOpenTimeout(); 54744 const parentMenuContext = context3.parentMenuContext(); 54745 const contentEl = context3.contentRef(); 54746 if (contentEl) { 54747 parentMenuContext?.setPointerGraceIntent({ 54748 area: getPointerGraceArea(context3.currentPlacement(), e, contentEl), 54749 // Safe because sub menu always open "left" or "right". 54750 side: context3.currentPlacement().split("-")[0] 54751 }); 54752 window.clearTimeout(parentMenuContext?.pointerGraceTimeoutId()); 54753 const pointerGraceTimeoutId = window.setTimeout(() => { 54754 parentMenuContext?.setPointerGraceIntent(null); 54755 }, 300); 54756 parentMenuContext?.setPointerGraceTimeoutId(pointerGraceTimeoutId); 54757 } else { 54758 parentMenuContext?.onTriggerLeave(e); 54759 if (e.defaultPrevented) { 54760 return; 54761 } 54762 parentMenuContext?.setPointerGraceIntent(null); 54763 } 54764 parentMenuContext?.onItemLeave(e); 54765 }; 54766 const onKeyDown = (e) => { 54767 callHandler(e, local.onKeyDown); 54768 if (e.repeat) { 54769 return; 54770 } 54771 if (local.disabled) { 54772 return; 54773 } 54774 if (SUB_OPEN_KEYS.open(direction(), rootContext.orientation()).includes(e.key)) { 54775 e.stopPropagation(); 54776 e.preventDefault(); 54777 parentSelectionManager().setFocused(false); 54778 parentSelectionManager().setFocusedKey(void 0); 54779 if (!context3.isOpen()) { 54780 context3.open("first"); 54781 } 54782 context3.focusContent(); 54783 context3.listState().selectionManager().setFocused(true); 54784 context3.listState().selectionManager().setFocusedKey(collection().getFirstKey()); 54785 } 54786 }; 54787 createEffect(() => { 54788 if (context3.registerItemToParentDomCollection == null) { 54789 throw new Error("[kobalte]: `Menu.SubTrigger` must be used within a `Menu.Sub` component"); 54790 } 54791 const unregister = context3.registerItemToParentDomCollection({ 54792 ref: () => ref, 54793 type: "item", 54794 key: key(), 54795 textValue: local.textValue ?? ref?.textContent ?? "", 54796 disabled: local.disabled ?? false 54797 }); 54798 onCleanup(unregister); 54799 }); 54800 createEffect(on(() => context3.parentMenuContext()?.pointerGraceTimeoutId(), (pointerGraceTimer) => { 54801 onCleanup(() => { 54802 window.clearTimeout(pointerGraceTimer); 54803 context3.parentMenuContext()?.setPointerGraceIntent(null); 54804 }); 54805 })); 54806 createEffect(() => onCleanup(context3.registerTriggerId(local.id))); 54807 onCleanup(() => { 54808 clearOpenTimeout(); 54809 }); 54810 return createComponent(Polymorphic, mergeProps({ 54811 as: "div", 54812 ref(r$) { 54813 const _ref$ = mergeRefs((el) => { 54814 context3.setTriggerRef(el); 54815 ref = el; 54816 }, local.ref); 54817 typeof _ref$ === "function" && _ref$(r$); 54818 }, 54819 get id() { 54820 return local.id; 54821 }, 54822 role: "menuitem", 54823 get tabIndex() { 54824 return selectableItem.tabIndex(); 54825 }, 54826 "aria-haspopup": "true", 54827 get ["aria-expanded"]() { 54828 return context3.isOpen(); 54829 }, 54830 get ["aria-controls"]() { 54831 return memo(() => !!context3.isOpen())() ? context3.contentId() : void 0; 54832 }, 54833 get ["aria-disabled"]() { 54834 return local.disabled; 54835 }, 54836 get ["data-key"]() { 54837 return selectableItem.dataKey(); 54838 }, 54839 get ["data-highlighted"]() { 54840 return isHighlighted() ? "" : void 0; 54841 }, 54842 get ["data-disabled"]() { 54843 return local.disabled ? "" : void 0; 54844 }, 54845 get onPointerDown() { 54846 return composeEventHandlers([local.onPointerDown, selectableItem.onPointerDown]); 54847 }, 54848 get onPointerUp() { 54849 return composeEventHandlers([local.onPointerUp, selectableItem.onPointerUp]); 54850 }, 54851 get onClick() { 54852 return composeEventHandlers([onClick, selectableItem.onClick]); 54853 }, 54854 get onKeyDown() { 54855 return composeEventHandlers([onKeyDown, selectableItem.onKeyDown]); 54856 }, 54857 get onMouseDown() { 54858 return composeEventHandlers([local.onMouseDown, selectableItem.onMouseDown]); 54859 }, 54860 get onFocus() { 54861 return composeEventHandlers([local.onFocus, selectableItem.onFocus]); 54862 }, 54863 onPointerMove, 54864 onPointerLeave 54865 }, () => context3.dataset(), others)); 54866} 54867
vendor: 2,297 bytes, lines 54868-54943
54868// node_modules/@kobalte/core/dist/chunk/JEP7F7FN.js 54869var dropdown_menu_exports = {}; 54870__export(dropdown_menu_exports, { 54871 Arrow: () => PopperArrow, 54872 CheckboxItem: () => MenuCheckboxItem, 54873 Content: () => DropdownMenuContent, 54874 DropdownMenu: () => DropdownMenu, 54875 Group: () => MenuGroup, 54876 GroupLabel: () => MenuGroupLabel, 54877 Icon: () => MenuIcon, 54878 Item: () => MenuItem, 54879 ItemDescription: () => MenuItemDescription, 54880 ItemIndicator: () => MenuItemIndicator, 54881 ItemLabel: () => MenuItemLabel, 54882 Portal: () => MenuPortal, 54883 RadioGroup: () => MenuRadioGroup, 54884 RadioItem: () => MenuRadioItem, 54885 Root: () => DropdownMenuRoot, 54886 Separator: () => SeparatorRoot, 54887 Sub: () => MenuSub, 54888 SubContent: () => MenuSubContent, 54889 SubTrigger: () => MenuSubTrigger, 54890 Trigger: () => MenuTrigger 54891}); 54892function DropdownMenuContent(props) { 54893 const rootContext = useMenuRootContext(); 54894 const context3 = useMenuContext(); 54895 const [local, others] = splitProps(props, ["onCloseAutoFocus", "onInteractOutside"]); 54896 let hasInteractedOutside = false; 54897 const onCloseAutoFocus = (e) => { 54898 local.onCloseAutoFocus?.(e); 54899 if (!hasInteractedOutside) { 54900 focusWithoutScrolling(context3.triggerRef()); 54901 } 54902 hasInteractedOutside = false; 54903 e.preventDefault(); 54904 }; 54905 const onInteractOutside = (e) => { 54906 local.onInteractOutside?.(e); 54907 if (!rootContext.isModal() || e.detail.isContextMenu) { 54908 hasInteractedOutside = true; 54909 } 54910 }; 54911 return createComponent(MenuContent, mergeProps({ 54912 onCloseAutoFocus, 54913 onInteractOutside 54914 }, others)); 54915} 54916function DropdownMenuRoot(props) { 54917 const defaultId = `dropdownmenu-${createUniqueId()}`; 54918 const mergedProps = mergeDefaultProps({ 54919 id: defaultId 54920 }, props); 54921 return createComponent(MenuRoot, mergedProps); 54922} 54923var DropdownMenu = Object.assign(DropdownMenuRoot, { 54924 Arrow: PopperArrow, 54925 CheckboxItem: MenuCheckboxItem, 54926 Content: DropdownMenuContent, 54927 Group: MenuGroup, 54928 GroupLabel: MenuGroupLabel, 54929 Icon: MenuIcon, 54930 Item: MenuItem, 54931 ItemDescription: MenuItemDescription, 54932 ItemIndicator: MenuItemIndicator, 54933 ItemLabel: MenuItemLabel, 54934 Portal: MenuPortal, 54935 RadioGroup: MenuRadioGroup, 54936 RadioItem: MenuRadioItem, 54937 Separator: SeparatorRoot, 54938 Sub: MenuSub, 54939 SubContent: MenuSubContent, 54940 SubTrigger: MenuSubTrigger, 54941 Trigger: MenuTrigger 54942}); 54943
vendor: 968 bytes, lines 54944-54978
54944// node_modules/@kobalte/core/dist/chunk/3QQCO6IA.js 54945var link_exports = {}; 54946__export(link_exports, { 54947 Link: () => Link, 54948 Root: () => LinkRoot 54949}); 54950function LinkRoot(props) { 54951 let ref; 54952 const [local, others] = splitProps(props, ["ref", "href", "disabled"]); 54953 const tagName = createTagName(() => ref, () => "a"); 54954 return createComponent(Polymorphic, mergeProps({ 54955 as: "a", 54956 ref(r$) { 54957 const _ref$ = mergeRefs((el) => ref = el, local.ref); 54958 typeof _ref$ === "function" && _ref$(r$); 54959 }, 54960 get role() { 54961 return tagName() !== "a" || local.disabled ? "link" : void 0; 54962 }, 54963 get tabIndex() { 54964 return tagName() !== "a" && !local.disabled ? 0 : void 0; 54965 }, 54966 get href() { 54967 return !local.disabled ? local.href : void 0; 54968 }, 54969 get ["aria-disabled"]() { 54970 return local.disabled ? true : void 0; 54971 }, 54972 get ["data-disabled"]() { 54973 return local.disabled ? "" : void 0; 54974 } 54975 }, others)); 54976} 54977var Link = LinkRoot; 54978
54979// src/viewer/export.jsx 54980var _tmpl$9 = /* @__PURE__ */ template(`<svg focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z">`); 54981var editUrlBase = "https://vzome.com/app/classic/index.html?design="; 54982var ExportMenu = (props) => { 54983 const { 54984 source 54985 } = useViewer(); 54986 const { 54987 exporter 54988 } = useGltfExporter(); 54989 const downloadGltf = () => { 54990 const { 54991 name 54992 } = source; 54993 const vName = name || "untitled.vZome"; 54994 const fileName = vName.substring(0, vName.length - 6).concat(".glb"); 54995 const { 54996 exportGltf 54997 } = exporter(); 54998 exportGltf((glb) => saveFileAs(fileName, glb, "model/gltf+binary")); 54999 }; 55000 const downloadVZome = () => { 55001 const { 55002 name, 55003 text, 55004 changedText 55005 } = source; 55006 const fileName = name || "untitled.vZome"; 55007 saveTextFileAs(fileName, text, "application/xml"); 55008 }; 55009 return createComponent(Show, { 55010 get when() { 55011 return source?.text || source?.changedText; 55012 }, 55013 get children() { 55014 return createComponent(DropdownMenu, { 55015 modal: true, 55016 get children() { 55017 return [createComponent(DropdownMenu.Trigger, { 55018 "class": "exports__trigger corner__icon__button", 55019 get children() { 55020 return _tmpl$9(); 55021 } 55022 }), createComponent(DropdownMenu.Portal, { 55023 get mount() { 55024 return props.root; 55025 }, 55026 get children() { 55027 return createComponent(DropdownMenu.Content, { 55028 "class": "exports__content", 55029 get children() { 55030 return [createComponent(DropdownMenu.Item, { 55031 closeOnSelect: true, 55032 "class": "exports__item", 55033 get disabled() { 55034 return !source?.url; 55035 }, 55036 get children() { 55037 return createComponent(Link, { 55038 "class": "link", 55039 get href() { 55040 return editUrlBase + source.url; 55041 }, 55042 target: "_blank", 55043 rel: "noopener", 55044 children: "Open in Online vZome" 55045 }); 55046 } 55047 }), createComponent(DropdownMenu.Item, { 55048 onSelect: downloadVZome, 55049 closeOnSelect: true, 55050 "class": "exports__item", 55051 children: "Download .vZome design" 55052 }), createComponent(DropdownMenu.Item, { 55053 closeOnSelect: true, 55054 "class": "exports__item", 55055 onSelect: downloadGltf, 55056 children: "Download glTF scene" 55057 }), createComponent(DropdownMenu.Arrow, {})]; 55058 } 55059 }); 55060 } 55061 })]; 55062 } 55063 }); 55064 } 55065 }); 55066}; 55067
vendor: 3,243 bytes, lines 55068-55145
55068// node_modules/@kobalte/core/dist/chunk/YKGT7A57.js 55069var FORM_CONTROL_PROP_NAMES = ["id", "name", "validationState", "required", "disabled", "readOnly"]; 55070function createFormControl(props) { 55071 const defaultId = `form-control-${createUniqueId()}`; 55072 const mergedProps = mergeDefaultProps({ 55073 id: defaultId 55074 }, props); 55075 const [labelId, setLabelId] = createSignal(); 55076 const [fieldId, setFieldId] = createSignal(); 55077 const [descriptionId, setDescriptionId] = createSignal(); 55078 const [errorMessageId, setErrorMessageId] = createSignal(); 55079 const getAriaLabelledBy = (fieldId2, fieldAriaLabel, fieldAriaLabelledBy) => { 55080 const hasAriaLabelledBy = fieldAriaLabelledBy != null || labelId() != null; 55081 return [ 55082 fieldAriaLabelledBy, 55083 labelId(), 55084 // If there is both an aria-label and aria-labelledby, add the field itself has an aria-labelledby 55085 hasAriaLabelledBy && fieldAriaLabel != null ? fieldId2 : void 0 55086 ].filter(Boolean).join(" ") || void 0; 55087 }; 55088 const getAriaDescribedBy = (fieldAriaDescribedBy) => { 55089 return [ 55090 descriptionId(), 55091 // Use aria-describedby for error message because aria-errormessage is unsupported using VoiceOver or NVDA. 55092 // See https://github.com/adobe/react-spectrum/issues/1346#issuecomment-740136268 55093 errorMessageId(), 55094 fieldAriaDescribedBy 55095 ].filter(Boolean).join(" ") || void 0; 55096 }; 55097 const dataset = createMemo(() => ({ 55098 "data-valid": access4(mergedProps.validationState) === "valid" ? "" : void 0, 55099 "data-invalid": access4(mergedProps.validationState) === "invalid" ? "" : void 0, 55100 "data-required": access4(mergedProps.required) ? "" : void 0, 55101 "data-disabled": access4(mergedProps.disabled) ? "" : void 0, 55102 "data-readonly": access4(mergedProps.readOnly) ? "" : void 0 55103 })); 55104 const formControlContext = { 55105 name: () => access4(mergedProps.name) ?? access4(mergedProps.id), 55106 dataset, 55107 validationState: () => access4(mergedProps.validationState), 55108 isRequired: () => access4(mergedProps.required), 55109 isDisabled: () => access4(mergedProps.disabled), 55110 isReadOnly: () => access4(mergedProps.readOnly), 55111 labelId, 55112 fieldId, 55113 descriptionId, 55114 errorMessageId, 55115 getAriaLabelledBy, 55116 getAriaDescribedBy, 55117 generateId: createGenerateId(() => access4(mergedProps.id)), 55118 registerLabel: createRegisterId(setLabelId), 55119 registerField: createRegisterId(setFieldId), 55120 registerDescription: createRegisterId(setDescriptionId), 55121 registerErrorMessage: createRegisterId(setErrorMessageId) 55122 }; 55123 return { 55124 formControlContext 55125 }; 55126} 55127var FormControlContext = createContext(); 55128function useFormControlContext() { 55129 const context3 = useContext(FormControlContext); 55130 if (context3 === void 0) { 55131 throw new Error("[kobalte]: `useFormControlContext` must be used within a `FormControlContext.Provider` component"); 55132 } 55133 return context3; 55134} 55135function FormControlDescription(props) { 55136 const context3 = useFormControlContext(); 55137 const mergedProps = mergeDefaultProps({ 55138 id: context3.generateId("description") 55139 }, props); 55140 createEffect(() => onCleanup(context3.registerDescription(mergedProps.id))); 55141 return createComponent(Polymorphic, mergeProps({ 55142 as: "div" 55143 }, () => context3.dataset(), mergedProps)); 55144} 55145
vendor: 815 bytes, lines 55146-55163
55146// node_modules/@kobalte/core/dist/chunk/K6P57S75.js 55147var FORM_CONTROL_FIELD_PROP_NAMES = ["id", "aria-label", "aria-labelledby", "aria-describedby"]; 55148function createFormControlField(props) { 55149 const context3 = useFormControlContext(); 55150 const mergedProps = mergeDefaultProps({ 55151 id: context3.generateId("field") 55152 }, props); 55153 createRenderEffect(() => onCleanup(context3.registerField(access4(mergedProps.id)))); 55154 return { 55155 fieldProps: { 55156 id: () => access4(mergedProps.id), 55157 ariaLabel: () => access4(mergedProps["aria-label"]), 55158 ariaLabelledBy: () => context3.getAriaLabelledBy(access4(mergedProps.id), access4(mergedProps["aria-label"]), access4(mergedProps["aria-labelledby"])), 55159 ariaDescribedBy: () => context3.getAriaDescribedBy(access4(mergedProps["aria-describedby"])) 55160 } 55161 }; 55162} 55163
vendor: 769 bytes, lines 55164-55185
55164// node_modules/@kobalte/core/dist/chunk/7ZHN3PYD.js 55165function FormControlLabel(props) { 55166 let ref; 55167 const context3 = useFormControlContext(); 55168 const mergedProps = mergeDefaultProps({ 55169 id: context3.generateId("label") 55170 }, props); 55171 const [local, others] = splitProps(mergedProps, ["ref"]); 55172 const tagName = createTagName(() => ref, () => "label"); 55173 createEffect(() => onCleanup(context3.registerLabel(others.id))); 55174 return createComponent(Polymorphic, mergeProps({ 55175 as: "label", 55176 ref(r$) { 55177 const _ref$ = mergeRefs((el) => ref = el, local.ref); 55178 typeof _ref$ === "function" && _ref$(r$); 55179 }, 55180 get ["for"]() { 55181 return memo(() => tagName() === "label")() ? context3.fieldId() : void 0; 55182 } 55183 }, () => context3.dataset(), others)); 55184} 55185
vendor: 689 bytes, lines 55186-55210
55186// node_modules/@kobalte/core/dist/chunk/ANN3A2QM.js 55187function createFormResetListener(element3, handler) { 55188 createEffect( 55189 on(element3, (element22) => { 55190 if (element22 == null) { 55191 return; 55192 } 55193 const form = getClosestForm(element22); 55194 if (form == null) { 55195 return; 55196 } 55197 form.addEventListener("reset", handler, { passive: true }); 55198 onCleanup(() => { 55199 form.removeEventListener("reset", handler); 55200 }); 55201 }) 55202 ); 55203} 55204function getClosestForm(element3) { 55205 return isFormElement(element3) ? element3.form : element3.closest("form"); 55206} 55207function isFormElement(element3) { 55208 return element3.matches("textarea, input, select, button"); 55209} 55210
vendor: 761 bytes, lines 55211-55236
55211// node_modules/@kobalte/core/dist/chunk/ICNSTULC.js 55212function FormControlErrorMessage(props) { 55213 const context3 = useFormControlContext(); 55214 const mergedProps = mergeDefaultProps({ 55215 id: context3.generateId("error-message") 55216 }, props); 55217 const [local, others] = splitProps(mergedProps, ["forceMount"]); 55218 const isInvalid = () => context3.validationState() === "invalid"; 55219 createEffect(() => { 55220 if (!isInvalid()) { 55221 return; 55222 } 55223 onCleanup(context3.registerErrorMessage(others.id)); 55224 }); 55225 return createComponent(Show, { 55226 get when() { 55227 return local.forceMount || isInvalid(); 55228 }, 55229 get children() { 55230 return createComponent(Polymorphic, mergeProps({ 55231 as: "div" 55232 }, () => context3.dataset(), others)); 55233 } 55234 }); 55235} 55236
vendor: 7,714 bytes, lines 55237-55485
55237// node_modules/@kobalte/core/dist/chunk/YPUNLYJC.js 55238var switch_exports = {}; 55239__export(switch_exports, { 55240 Control: () => SwitchControl, 55241 Description: () => SwitchDescription, 55242 ErrorMessage: () => SwitchErrorMessage, 55243 Input: () => SwitchInput, 55244 Label: () => SwitchLabel, 55245 Root: () => SwitchRoot, 55246 Switch: () => Switch3, 55247 Thumb: () => SwitchThumb, 55248 useSwitchContext: () => useSwitchContext 55249}); 55250var SwitchContext = createContext(); 55251function useSwitchContext() { 55252 const context3 = useContext(SwitchContext); 55253 if (context3 === void 0) { 55254 throw new Error("[kobalte]: `useSwitchContext` must be used within a `Switch` component"); 55255 } 55256 return context3; 55257} 55258function SwitchControl(props) { 55259 const formControlContext = useFormControlContext(); 55260 const context3 = useSwitchContext(); 55261 const mergedProps = mergeDefaultProps({ 55262 id: context3.generateId("control") 55263 }, props); 55264 const [local, others] = splitProps(mergedProps, ["onClick", "onKeyDown"]); 55265 const onClick = (e) => { 55266 callHandler(e, local.onClick); 55267 context3.toggle(); 55268 context3.inputRef()?.focus({ 55269 preventScroll: true 55270 }); 55271 }; 55272 const onKeyDown = (e) => { 55273 callHandler(e, local.onKeyDown); 55274 if (e.key === EventKey.Space) { 55275 context3.toggle(); 55276 context3.inputRef()?.focus({ 55277 preventScroll: true 55278 }); 55279 } 55280 }; 55281 return createComponent(Polymorphic, mergeProps({ 55282 as: "div", 55283 onClick, 55284 onKeyDown 55285 }, () => formControlContext.dataset(), () => context3.dataset(), others)); 55286} 55287function SwitchDescription(props) { 55288 const context3 = useSwitchContext(); 55289 return createComponent(FormControlDescription, mergeProps(() => context3.dataset(), props)); 55290} 55291function SwitchErrorMessage(props) { 55292 const context3 = useSwitchContext(); 55293 return createComponent(FormControlErrorMessage, mergeProps(() => context3.dataset(), props)); 55294} 55295function SwitchInput(props) { 55296 const formControlContext = useFormControlContext(); 55297 const context3 = useSwitchContext(); 55298 const mergedProps = mergeDefaultProps({ 55299 id: context3.generateId("input") 55300 }, props); 55301 const [local, formControlFieldProps, others] = splitProps(mergedProps, ["ref", "style", "onChange", "onFocus", "onBlur"], FORM_CONTROL_FIELD_PROP_NAMES); 55302 const { 55303 fieldProps 55304 } = createFormControlField(formControlFieldProps); 55305 const onChange = (e) => { 55306 callHandler(e, local.onChange); 55307 e.stopPropagation(); 55308 const target = e.target; 55309 context3.setIsChecked(target.checked); 55310 target.checked = context3.checked(); 55311 }; 55312 const onFocus = (e) => { 55313 callHandler(e, local.onFocus); 55314 context3.setIsFocused(true); 55315 }; 55316 const onBlur = (e) => { 55317 callHandler(e, local.onBlur); 55318 context3.setIsFocused(false); 55319 }; 55320 return createComponent(Polymorphic, mergeProps({ 55321 as: "input", 55322 ref(r$) { 55323 const _ref$ = mergeRefs(context3.setInputRef, local.ref); 55324 typeof _ref$ === "function" && _ref$(r$); 55325 }, 55326 type: "checkbox", 55327 role: "switch", 55328 get id() { 55329 return fieldProps.id(); 55330 }, 55331 get name() { 55332 return formControlContext.name(); 55333 }, 55334 get value() { 55335 return context3.value(); 55336 }, 55337 get checked() { 55338 return context3.checked(); 55339 }, 55340 get required() { 55341 return formControlContext.isRequired(); 55342 }, 55343 get disabled() { 55344 return formControlContext.isDisabled(); 55345 }, 55346 get readonly() { 55347 return formControlContext.isReadOnly(); 55348 }, 55349 get style() { 55350 return combineStyle({ 55351 ...visuallyHiddenStyles 55352 }, local.style); 55353 }, 55354 get ["aria-checked"]() { 55355 return context3.checked(); 55356 }, 55357 get ["aria-label"]() { 55358 return fieldProps.ariaLabel(); 55359 }, 55360 get ["aria-labelledby"]() { 55361 return fieldProps.ariaLabelledBy(); 55362 }, 55363 get ["aria-describedby"]() { 55364 return fieldProps.ariaDescribedBy(); 55365 }, 55366 get ["aria-invalid"]() { 55367 return formControlContext.validationState() === "invalid" || void 0; 55368 }, 55369 get ["aria-required"]() { 55370 return formControlContext.isRequired() || void 0; 55371 }, 55372 get ["aria-disabled"]() { 55373 return formControlContext.isDisabled() || void 0; 55374 }, 55375 get ["aria-readonly"]() { 55376 return formControlContext.isReadOnly() || void 0; 55377 }, 55378 onChange, 55379 onFocus, 55380 onBlur 55381 }, () => formControlContext.dataset(), () => context3.dataset(), others)); 55382} 55383function SwitchLabel(props) { 55384 const context3 = useSwitchContext(); 55385 return createComponent(FormControlLabel, mergeProps(() => context3.dataset(), props)); 55386} 55387function SwitchRoot(props) { 55388 let ref; 55389 const defaultId = `switch-${createUniqueId()}`; 55390 const mergedProps = mergeDefaultProps({ 55391 value: "on", 55392 id: defaultId 55393 }, props); 55394 const [local, formControlProps, others] = splitProps(mergedProps, ["ref", "children", "value", "checked", "defaultChecked", "onChange", "onPointerDown"], FORM_CONTROL_PROP_NAMES); 55395 const [inputRef, setInputRef] = createSignal(); 55396 const [isFocused, setIsFocused] = createSignal(false); 55397 const { 55398 formControlContext 55399 } = createFormControl(formControlProps); 55400 const state = createToggleState({ 55401 isSelected: () => local.checked, 55402 defaultIsSelected: () => local.defaultChecked, 55403 onSelectedChange: (selected) => local.onChange?.(selected), 55404 isDisabled: () => formControlContext.isDisabled(), 55405 isReadOnly: () => formControlContext.isReadOnly() 55406 }); 55407 createFormResetListener(() => ref, () => state.setIsSelected(local.defaultChecked ?? false)); 55408 const onPointerDown = (e) => { 55409 callHandler(e, local.onPointerDown); 55410 if (isFocused()) { 55411 e.preventDefault(); 55412 } 55413 }; 55414 const dataset = createMemo(() => ({ 55415 "data-checked": state.isSelected() ? "" : void 0 55416 })); 55417 const context3 = { 55418 value: () => local.value, 55419 dataset, 55420 checked: () => state.isSelected(), 55421 inputRef, 55422 generateId: createGenerateId(() => access4(formControlProps.id)), 55423 toggle: () => state.toggle(), 55424 setIsChecked: (isChecked) => state.setIsSelected(isChecked), 55425 setIsFocused, 55426 setInputRef 55427 }; 55428 return createComponent(FormControlContext.Provider, { 55429 value: formControlContext, 55430 get children() { 55431 return createComponent(SwitchContext.Provider, { 55432 value: context3, 55433 get children() { 55434 return createComponent(Polymorphic, mergeProps({ 55435 as: "div", 55436 ref(r$) { 55437 const _ref$ = mergeRefs((el) => ref = el, local.ref); 55438 typeof _ref$ === "function" && _ref$(r$); 55439 }, 55440 role: "group", 55441 get id() { 55442 return access4(formControlProps.id); 55443 }, 55444 onPointerDown 55445 }, () => formControlContext.dataset(), dataset, others, { 55446 get children() { 55447 return createComponent(SwitchRootChild, { 55448 state: context3, 55449 get children() { 55450 return local.children; 55451 } 55452 }); 55453 } 55454 })); 55455 } 55456 }); 55457 } 55458 }); 55459} 55460function SwitchRootChild(props) { 55461 const resolvedChildren = children(() => { 55462 const body = props.children; 55463 return isFunction(body) ? body(props.state) : body; 55464 }); 55465 return memo(resolvedChildren); 55466} 55467function SwitchThumb(props) { 55468 const formControlContext = useFormControlContext(); 55469 const context3 = useSwitchContext(); 55470 const mergedProps = mergeDefaultProps({ 55471 id: context3.generateId("thumb") 55472 }, props); 55473 return createComponent(Polymorphic, mergeProps({ 55474 as: "div" 55475 }, () => formControlContext.dataset(), () => context3.dataset(), mergedProps)); 55476} 55477var Switch3 = Object.assign(SwitchRoot, { 55478 Control: SwitchControl, 55479 Description: SwitchDescription, 55480 ErrorMessage: SwitchErrorMessage, 55481 Input: SwitchInput, 55482 Label: SwitchLabel, 55483 Thumb: SwitchThumb 55484}); 55485
55486// src/viewer/settings.jsx 55487var _tmpl$10 = /* @__PURE__ */ template(`<div class="settingsdialog__header">`); 55488var _tmpl$25 = /* @__PURE__ */ template(`<div class="settingsdialog__body">`); 55489var _tmpl$32 = /* @__PURE__ */ template(`<div class="settingsdialog__positioner">`); 55490var Settings = (props) => { 55491 const { 55492 togglePerspective, 55493 toggleOutlines, 55494 state 55495 } = useCamera(); 55496 return createComponent(Dialog, { 55497 open: true, 55498 get children() { 55499 return createComponent(Dialog.Portal, { 55500 get mount() { 55501 return props.root; 55502 }, 55503 get children() { 55504 return [createComponent(Dialog.Overlay, { 55505 "class": "settingsdialog__overlay" 55506 }), (() => { 55507 const _el$ = _tmpl$32(); 55508 insert(_el$, createComponent(Dialog.Content, { 55509 "class": "settingsdialog__content", 55510 get children() { 55511 return [(() => { 55512 const _el$2 = _tmpl$10(); 55513 insert(_el$2, createComponent(Dialog.Title, { 55514 "class": "settingsdialog__title", 55515 children: "View Settings" 55516 }), null); 55517 insert(_el$2, createComponent(Dialog.CloseButton, { 55518 "class": "dialog__close-button", 55519 get onClick() { 55520 return props.close; 55521 }, 55522 children: "x" 55523 }), null); 55524 return _el$2; 55525 })(), (() => { 55526 const _el$3 = _tmpl$25(); 55527 insert(_el$3, createComponent(Switch3, { 55528 "class": "switch", 55529 get checked() { 55530 return state.camera.perspective; 55531 }, 55532 onChange: togglePerspective, 55533 get children() { 55534 return [createComponent(Switch3.Label, { 55535 "class": "switch__label", 55536 children: "Perspective" 55537 }), createComponent(Switch3.Input, { 55538 "class": "switch__input" 55539 }), createComponent(Switch3.Control, { 55540 "class": "switch__control", 55541 get children() { 55542 return createComponent(Switch3.Thumb, { 55543 "class": "switch__thumb" 55544 }); 55545 } 55546 })]; 55547 } 55548 }), null); 55549 insert(_el$3, createComponent(Show, { 55550 get when() { 55551 return props.showOutlines; 55552 }, 55553 get children() { 55554 return createComponent(Switch3, { 55555 "class": "switch", 55556 get checked() { 55557 return state.outlines; 55558 }, 55559 onChange: toggleOutlines, 55560 get children() { 55561 return [createComponent(Switch3.Label, { 55562 "class": "switch__label", 55563 children: "Outlines" 55564 }), createComponent(Switch3.Input, { 55565 "class": "switch__input" 55566 }), createComponent(Switch3.Control, { 55567 "class": "switch__control", 55568 get children() { 55569 return createComponent(Switch3.Thumb, { 55570 "class": "switch__thumb" 55571 }); 55572 } 55573 })]; 55574 } 55575 }); 55576 } 55577 }), null); 55578 return _el$3; 55579 })()]; 55580 } 55581 })); 55582 return _el$; 55583 })()]; 55584 } 55585 }); 55586 } 55587 }); 55588}; 55589
55590// src/viewer/index.jsx 55591var _tmpl$11 = /* @__PURE__ */ template(`<svg aria-hidden="true" viewBox="-1 -1 25 25" focusable="false" data-testid="SettingsIcon"><g><path d="M0,0h24v24H0V0z" fill="none"></path><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z">`); 55592var _tmpl$26 = /* @__PURE__ */ template(`<div id="scene-viewer">`); 55593var _tmpl$33 = /* @__PURE__ */ template(`<div>`); 55594console.log(`vzome-viewer revision ${REVISION2}`); 55595var stylesAdded = false; 55596var normalStyle = { 55597 display: "flex", 55598 // flex is for the light dom content, usually an image 55599 height: "100%", 55600 width: "100%", 55601 position: "relative", 55602 overflow: "hidden" 55603 // curiously, this forces Canvas to recompute its size when changing back 55604}; 55605var SceneViewer = (props) => { 55606 const dynConfig = () => mergeProps({ 55607 allowFullViewport: false, 55608 showSettings: true, 55609 showOutlines: true 55610 }, props.config); 55611 const { 55612 scene 55613 } = useScene(); 55614 const [showSettings, setShowSettings] = createSignal(false); 55615 let rootRef; 55616 const [fullScreen, setFullScreen] = createSignal(false); 55617 const toggleFullScreen = () => { 55618 if (document.fullscreenElement) { 55619 document.exitFullscreen(); 55620 } else if (document.fullscreenEnabled && rootRef.requestFullscreen) { 55621 rootRef.requestFullscreen(); 55622 } 55623 }; 55624 const fullscreenListener = () => setFullScreen(!!document.fullscreenElement); 55625 document.addEventListener("fullscreenchange", fullscreenListener); 55626 getOwner() && onCleanup(() => { 55627 document.removeEventListener("fullscreenchange", fullscreenListener); 55628 if (document.fullscreenElement) { 55629 document.exitFullscreen(); 55630 } 55631 }); 55632 return (() => { 55633 const _el$ = _tmpl$26(); 55634 const _ref$ = rootRef; 55635 typeof _ref$ === "function" ? use(_ref$, _el$) : rootRef = _el$; 55636 style(_el$, normalStyle); 55637 insert(_el$, createComponent(InteractionToolProvider, { 55638 get children() { 55639 return createComponent(GltfExportProvider, { 55640 get children() { 55641 return [createComponent(Show, { 55642 when: scene, 55643 get fallback() { 55644 return props.children; 55645 }, 55646 get children() { 55647 return createComponent(SceneCanvas, { 55648 get symmetryRenderer() { 55649 return dynConfig().symmetryRenderer !== false; 55650 }, 55651 id: "scene-canvas", 55652 get height() { 55653 return props.height; 55654 }, 55655 get width() { 55656 return props.width; 55657 }, 55658 get children() { 55659 return props.children3d; 55660 } 55661 }); 55662 } 55663 }), createComponent(Show, { 55664 get when() { 55665 return dynConfig().showSettings; 55666 }, 55667 get children() { 55668 return createComponent(IconButton, { 55669 "class": "settings-button", 55670 tooltip: "Show settings", 55671 onClick: () => setShowSettings(true), 55672 root: rootRef, 55673 get children() { 55674 return _tmpl$11(); 55675 } 55676 }); 55677 } 55678 }), createComponent(Show, { 55679 get when() { 55680 return showSettings(); 55681 }, 55682 get children() { 55683 return createComponent(Settings, { 55684 root: rootRef, 55685 get showOutlines() { 55686 return memo(() => !!scene?.polygons)() && dynConfig().showOutlines; 55687 }, 55688 close: () => setShowSettings(false) 55689 }); 55690 } 55691 }), createComponent(Show, { 55692 get when() { 55693 return dynConfig().allowFullViewport; 55694 }, 55695 get children() { 55696 return createComponent(FullscreenButton, { 55697 get fullScreen() { 55698 return fullScreen(); 55699 }, 55700 root: rootRef, 55701 toggle: toggleFullScreen 55702 }); 55703 } 55704 }), memo(() => props.children)]; 55705 } 55706 }); 55707 } 55708 })); 55709 return _el$; 55710 })(); 55711}; 55712var InitializeScene = (props) => { 55713 const { 55714 showIndexedScene 55715 }
55715 = useSceneIndexing(); 55716 const { 55717 showTitledScene, 55718 sceneTitle 55719 } = useSceneTitles(); 55720 createEffect(() => { 55721 if (props.showScenes === "indexed") { 55722 showIndexedScene(1); 55723 } else if (props.showScenes === "none") { 55724 showIndexedScene(0); 55725 } else if (props.showScenes !== "managed") { 55726 showTitledScene(sceneTitle()); 55727 } 55728 }); 55729 return null; 55730}; 55731var DesignViewer = (props) => { 55732 const dynConfig = () => mergeProps({ 55733 showScenes: "none", 55734 useSpinner: false, 55735 download: true 55736 }, props.config); 55737 const { 55738 waiting 55739 } = useViewer(); 55740 const showSpinner = () => { 55741 return props.config?.useSpinner && waiting(); 55742 }; 55743 onMount(() => { 55744 if (!props.componentRoot && !stylesAdded) { 55745 document.body.appendChild(document.createElement("style")).textContent = urlViewerCSS; 55746 stylesAdded = true; 55747 } 55748 }); 55749 let rootRef; 55750 return createComponent(SceneTitlesProvider, { 55751 get show() { 55752 return dynConfig().showScenes; 55753 }, 55754 get title() { 55755 return dynConfig().sceneTitle; 55756 }, 55757 get children() { 55758 return createComponent(SceneViewer, { 55759 get children3d() { 55760 return props.children3d; 55761 }, 55762 get height() { 55763 return props.height; 55764 }, 55765 get width() { 55766 return props.width; 55767 }, 55768 get config() { 55769 return dynConfig(); 55770 }, 55771 get children() { 55772 return [createComponent(InitializeScene, { 55773 get showScenes() { 55774 return dynConfig().showScenes; 55775 } 55776 }), (() => { 55777 const _el$3 = _tmpl$33(); 55778 const _ref$2 = rootRef; 55779 typeof _ref$2 === "function" ? use(_ref$2, _el$3) : rootRef = _el$3; 55780 insert(_el$3, createComponent(Show, { 55781 get when() { 55782 return dynConfig().download; 55783 }, 55784 get children() { 55785 return createComponent(ExportMenu, { 55786 root: rootRef 55787 }); 55788 } 55789 }), null); 55790 insert(_el$3, createComponent(Show, { 55791 get when() { 55792 return showSpinner(); 55793 }, 55794 get children() { 55795 return createComponent(Spinner, { 55796 root: rootRef 55797 }); 55798 } 55799 }), null); 55800 insert(_el$3, createComponent(ErrorAlert, { 55801 root: rootRef 55802 }), null); 55803 insert(_el$3, () => props.children, null); 55804 insert(_el$3, createComponent(Show, { 55805 get when() { 55806 return dynConfig().showScenes === "all" || dynConfig().showScenes === "titled"; 55807 }, 55808 get children() { 55809 return createComponent(SceneMenu, { 55810 root: rootRef 55811 }); 55812 } 55813 }), null); 55814 return _el$3; 55815 })()]; 55816 } 55817 }); 55818 } 55819 }); 55820}; 55821var UrlViewer = (props) => { 55822 return createComponent(ImageCaptureProvider, { 55823 get children() { 55824 return createComponent(CameraProvider, { 55825 get tweening() { 55826 return props.config?.tweening; 55827 }, 55828 get children() { 55829 return createComponent(WorkerProvider, { 55830 get children() { 55831 return createComponent(ViewerProvider, { 55832 get config() { 55833 return { 55834 url: props.url, 55835 preview: true, 55836 debug: false, 55837 labels: props.config?.labels, 55838 source: props.config?.download 55839 }; 55840 }, 55841 get children() { 55842 return createComponent(SceneProvider, { 55843 get index() { 55844 return props.config.snapshot; 55845 }, 55846 get config() { 55847 return props.config; 55848 }, 55849 get children() { 55850 return createComponent(SceneIndexingProvider, { 55851 get children() { 55852 return createComponent(DesignViewer, { 55853 get config() { 55854 return { 55855 ...props.config, 55856 allowFullViewport: true 55857 }; 55858 }, 55859 get componentRoot() { 55860 return props.componentRoot; 55861 }, 55862 height: "100%", 55863 width: "100%", 55864 get children() { 55865 return props.children; 55866 } 55867 }); 55868 } 55869 }); 55870 } 55871 }); 55872 } 55873 }); 55874 } 55875 }); 55876 } 55877 }); 55878 } 55879 }); 55880}; 55881var WebComponentBindings = (props) => { 55882 const { 55883 showIndexedScene, 55884 lastSceneIndex,
55885 setLastSceneIndex 55886 } = useSceneIndexing(); 55887 const { 55888 setTweenDuration 55889 } = useCamera(); 55890 const { 55891 requestDesign, 55892 resetScenes, 55893 openText, 55894 exportAs, 55895 indexResources 55896 } = useViewer(); 55897 const { 55898 captureImage 55899 } = useImageCapture(); 55900 const { 55901 showTitledScene 55902 } = useSceneTitles(); 55903 const apiObject = { 55904 showIndexedScene, 55905 showTitledScene, 55906 requestDesign, 55907 setTweenDuration, 55908 resetScenes, 55909 openText, 55910 exportAs, 55911 captureImage 55912 }; 55913 const { 55914 subscribeFor 55915 } = useWorkerClient(); 55916 const { 55917 setApi, 55918 onAlert, 55919 onSceneRendered, 55920 onScenesDiscovered 55921 } = props.callbacks; 55922 indexResources(); 55923 setApi(apiObject); 55924 subscribeFor("ALERT_RAISED", onAlert); 55925 subscribeFor("SCENES_DISCOVERED", ({ 55926 scenes 55927 }) => { 55928 setLastSceneIndex(null); 55929 onScenesDiscovered(scenes); 55930 }); 55931 createEffect(() => { 55932 if (lastSceneIndex() !== null) { 55933 onSceneRendered(lastSceneIndex()); 55934 } 55935 }); 55936 return null; 55937}; 55938var renderViewer = (container, config, callbacks) => { 55939 const bindComponent = () => { 55940 return createComponent(UrlViewer, { 55941 config, 55942 componentRoot: container, 55943 get children() { 55944 return createComponent(WebComponentBindings, { 55945 callbacks 55946 }); 55947 } 55948 }); 55949 }; 55950 container.appendChild(document.createElement("style")).textContent = urlViewerCSS; 55951 const linkElem = document.createElement("link"); 55952 linkElem.setAttribute("rel", "stylesheet"); 55953 linkElem.setAttribute("href", "./vzome-viewer-styles.css"); 55954 container.appendChild(linkElem); 55955 render(bindComponent, container); 55956}; 55957 55958export { 55959 urlViewerCSS, 55960 SceneProvider, 55961 useScene, 55962 useSceneIndexing, 55963 SceneIndexingProvider, 55964 useSceneTitles, 55965 getSceneTitleIndex, 55966 SceneTitlesProvider, 55967 SceneChangeListener, 55968 grabTool, 55969 InteractionToolProvider, 55970 useInteractionTool, 55971 GltfExportProvider, 55972 useGltfExporter, 55973 ImageCaptureProvider, 55974 useImageCapture, 55975 useWebXRClient, 55976 LightedTrackballCanvas, 55977 ShapedGeometry, 55978 SceneCanvas, 55979 Key, 55980 combineStyle, 55981 mergeRefs, 55982 access4 as access, 55983 isFunction, 55984 createGenerateId, 55985 contains, 55986 isMac, 55987 isWebKit, 55988 callHandler, 55989 composeEventHandlers, 55990 focusWithoutScrolling, 55991 getFocusableTreeWalker, 55992 clamp7 as clamp, 55993 snapValueToStep, 55994 mergeDefaultProps, 55995 visuallyHiddenStyles, 55996 createFocusScope, 55997 createHideOutside, 55998 createInteractOutside, 55999 Polymorphic, 56000 DismissableLayer, 56001 createControllableSignal, 56002 createControllableArraySignal, 56003 createDisclosureState, 56004 __export, 56005 ButtonRoot, 56006 Button, 56007 createRegisterId, 56008 index_default, 56009 index_default2, 56010 Dialog, 56011 useLocale, 56012 createCollator, 56013 createNumberFormatter, 56014 PopperArrow, 56015 Popper, 56016 IconButton, 56017 SeparatorRoot, 56018 Selection, 56019 isSameSelection, 56020 createTypeSelect, 56021 createSelectableCollection, 56022 createSelectableItem, 56023 createListState, 56024 ListKeyboardDelegate, 56025 createSelectableList, 56026 createDomCollection, 56027 createDomCollectionItem, 56028 MenubarContext, 56029 useMenubarContext, 56030 useOptionalMenuContext, 56031 useMenuContext, 56032 useMenuRootContext, 56033 MenuCheckboxItem, 56034 MenuTrigger, 56035 MenuContent, 56036 MenuGroup, 56037 MenuGroupLabel, 56038 MenuIcon, 56039 MenuItem, 56040 MenuItemDescription, 56041 MenuItemIndicator, 56042 MenuItemLabel, 56043 MenuPortal, 56044 MenuRadioGroup, 56045 MenuRadioItem, 56046 MenuRoot, 56047 MenuSub, 56048 MenuSubContent, 56049 MenuSubTrigger, 56050 Link, 56051 FORM_CONTROL_PROP_NAMES, 56052 createFormControl, 56053 FormControlContext, 56054 useFormControlContext, 56055 FormControlDescription, 56056 FORM_CONTROL_FIELD_PROP_NAMES, 56057 createFormControlField, 56058 FormControlLabel, 56059 createFormResetListener, 56060 FormControlErrorMessage, 56061 Switch3 as Switch, 56062 SceneViewer, 56063 InitializeScene, 56064 DesignViewer, 56065 UrlViewer, 56066 renderViewer 56067}; 56068/*! Bundled license information: 56069 56070three/build/three.webgpu.js: 56071three/build/three.tsl.js: 56072 (** 56073 * @license 56074 * Copyright 2010-2026 Three.js Authors 56075 * SPDX-License-Identifier: MIT 56076 *) 56077*/
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.