super-three 0.168.0 → 0.169.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.cjs +369 -131
- package/build/three.module.js +369 -131
- package/build/three.module.min.js +1 -1
- package/build/three.webgpu.js +24644 -22406
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +79941 -0
- package/build/three.webgpu.nodes.min.js +6 -0
- package/examples/jsm/Addons.js +0 -6
- package/examples/jsm/controls/TrackballControls.js +32 -12
- package/examples/jsm/controls/TransformControls.js +97 -62
- package/examples/jsm/exporters/DRACOExporter.js +4 -2
- package/examples/jsm/exporters/EXRExporter.js +19 -11
- package/examples/jsm/exporters/KTX2Exporter.js +21 -13
- package/examples/jsm/exporters/OBJExporter.js +5 -1
- package/examples/jsm/exporters/PLYExporter.js +9 -7
- package/examples/jsm/geometries/DecalGeometry.js +4 -1
- package/examples/jsm/geometries/InstancedPointsGeometry.js +1 -1
- package/examples/jsm/helpers/LightProbeHelper.js +1 -1
- package/examples/jsm/helpers/LightProbeHelperGPU.js +65 -0
- package/examples/jsm/libs/basis/basis_transcoder.js +8 -10
- package/examples/jsm/libs/basis/basis_transcoder.wasm +0 -0
- package/examples/jsm/libs/ktx-parse.module.js +1 -1
- package/examples/jsm/lights/LightProbeGenerator.js +24 -10
- package/examples/jsm/loaders/ColladaLoader.js +9 -6
- package/examples/jsm/loaders/DRACOLoader.js +3 -1
- package/examples/jsm/loaders/FBXLoader.js +30 -20
- package/examples/jsm/loaders/GLTFLoader.js +5 -10
- package/examples/jsm/loaders/KTX2Loader.js +10 -7
- package/examples/jsm/loaders/MTLLoader.js +4 -3
- package/examples/jsm/loaders/MaterialXLoader.js +29 -10
- package/examples/jsm/loaders/OBJLoader.js +5 -3
- package/examples/jsm/loaders/PCDLoader.js +5 -4
- package/examples/jsm/loaders/PDBLoader.js +3 -2
- package/examples/jsm/loaders/PLYLoader.js +8 -5
- package/examples/jsm/loaders/STLLoader.js +3 -2
- package/examples/jsm/loaders/VRMLLoader.js +10 -10
- package/examples/jsm/loaders/VTKLoader.js +4 -3
- package/examples/jsm/loaders/XYZLoader.js +3 -2
- package/examples/jsm/misc/Timer.js +1 -1
- package/examples/jsm/modifiers/CurveModifierGPU.js +233 -0
- package/examples/jsm/objects/LensflareMesh.js +322 -0
- package/examples/jsm/objects/SkyMesh.js +1 -2
- package/examples/jsm/objects/Water2Mesh.js +2 -3
- package/examples/jsm/objects/WaterMesh.js +1 -2
- package/examples/jsm/physics/JoltPhysics.js +1 -1
- package/examples/jsm/physics/RapierPhysics.js +1 -1
- package/examples/jsm/transpiler/GLSLDecoder.js +1 -1
- package/examples/jsm/transpiler/ShaderToyDecoder.js +2 -2
- package/examples/jsm/utils/GeometryCompressionUtils.js +37 -122
- package/examples/jsm/utils/ShadowMapViewer.js +3 -8
- package/examples/jsm/utils/ShadowMapViewerGPU.js +201 -0
- package/examples/jsm/utils/SkeletonUtils.js +84 -66
- package/examples/jsm/utils/TextureUtils.js +1 -0
- package/examples/jsm/utils/TextureUtilsGPU.js +63 -0
- package/examples/jsm/webxr/XRControllerModelFactory.js +1 -1
- package/package.json +2 -2
- package/src/Three.WebGPU.Nodes.js +200 -0
- package/src/Three.WebGPU.js +2 -1
- package/src/audio/Audio.js +2 -2
- package/src/constants.js +1 -1
- package/src/core/BufferAttribute.js +0 -9
- package/src/core/Clock.js +1 -1
- package/src/core/InterleavedBuffer.js +0 -9
- package/src/extras/Controls.js +1 -1
- package/src/geometries/CylinderGeometry.js +11 -4
- package/src/loaders/MaterialLoader.js +7 -1
- package/src/loaders/nodes/NodeLoader.js +24 -4
- package/src/loaders/nodes/NodeMaterialLoader.js +21 -17
- package/src/loaders/nodes/NodeObjectLoader.js +19 -0
- package/src/materials/nodes/InstancedPointsNodeMaterial.js +19 -34
- package/src/materials/nodes/Line2NodeMaterial.js +26 -26
- package/src/materials/nodes/LineBasicNodeMaterial.js +7 -3
- package/src/materials/nodes/LineDashedNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshBasicNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshLambertNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshMatcapNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshNormalNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshPhongNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +6 -3
- package/src/materials/nodes/MeshSSSNodeMaterial.js +6 -3
- package/src/materials/nodes/MeshStandardNodeMaterial.js +7 -3
- package/src/materials/nodes/MeshToonNodeMaterial.js +7 -3
- package/src/materials/nodes/NodeMaterial.js +20 -45
- package/src/materials/nodes/NodeMaterials.js +2 -0
- package/src/materials/nodes/PointsNodeMaterial.js +7 -3
- package/src/materials/nodes/ShadowNodeMaterial.js +7 -3
- package/src/materials/nodes/SpriteNodeMaterial.js +39 -6
- package/src/materials/nodes/VolumeNodeMaterial.js +13 -9
- package/src/materials/nodes/manager/NodeMaterialObserver.js +302 -0
- package/src/math/Triangle.js +24 -0
- package/src/nodes/Nodes.js +3 -3
- package/src/nodes/TSL.js +96 -93
- package/src/nodes/accessors/BatchNode.js +7 -3
- package/src/nodes/accessors/BufferAttributeNode.js +6 -3
- package/src/nodes/accessors/BufferNode.js +6 -3
- package/src/nodes/accessors/Camera.js +10 -16
- package/src/nodes/accessors/ClippingNode.js +7 -3
- package/src/nodes/accessors/CubeTextureNode.js +6 -3
- package/src/nodes/accessors/InstanceNode.js +11 -11
- package/src/nodes/accessors/InstancedPointsMaterialNode.js +6 -3
- package/src/nodes/accessors/Lights.js +51 -0
- package/src/nodes/accessors/MaterialNode.js +8 -4
- package/src/nodes/accessors/MaterialReferenceNode.js +6 -3
- package/src/nodes/accessors/ModelNode.js +42 -7
- package/src/nodes/accessors/ModelViewProjectionNode.js +9 -5
- package/src/nodes/accessors/MorphNode.js +7 -3
- package/src/nodes/accessors/Normal.js +32 -6
- package/src/nodes/accessors/Object3DNode.js +11 -27
- package/src/nodes/accessors/PointUVNode.js +7 -3
- package/src/nodes/accessors/ReferenceBaseNode.js +32 -4
- package/src/nodes/accessors/ReferenceNode.js +40 -3
- package/src/nodes/accessors/RendererReferenceNode.js +9 -3
- package/src/nodes/accessors/SceneNode.js +7 -3
- package/src/nodes/accessors/SkinningNode.js +7 -3
- package/src/nodes/accessors/StorageBufferNode.js +21 -3
- package/src/nodes/accessors/StorageTextureNode.js +7 -4
- package/src/nodes/accessors/Texture3DNode.js +7 -4
- package/src/nodes/accessors/TextureNode.js +19 -8
- package/src/nodes/accessors/TextureSizeNode.js +8 -5
- package/src/nodes/accessors/UniformArrayNode.js +12 -9
- package/src/nodes/accessors/UserDataNode.js +9 -6
- package/src/nodes/accessors/VelocityNode.js +74 -23
- package/src/nodes/accessors/VertexColorNode.js +6 -3
- package/src/nodes/code/CodeNode.js +7 -3
- package/src/nodes/code/ExpressionNode.js +8 -4
- package/src/nodes/code/FunctionCallNode.js +6 -3
- package/src/nodes/code/FunctionNode.js +6 -3
- package/src/nodes/code/ScriptableNode.js +11 -6
- package/src/nodes/code/ScriptableValueNode.js +7 -3
- package/src/nodes/core/AssignNode.js +9 -6
- package/src/nodes/core/AttributeNode.js +7 -3
- package/src/nodes/core/BypassNode.js +8 -4
- package/src/nodes/core/CacheNode.js +8 -4
- package/src/nodes/core/ConstNode.js +6 -3
- package/src/nodes/core/ContextNode.js +7 -3
- package/src/nodes/core/IndexNode.js +25 -3
- package/src/nodes/core/InputNode.js +7 -3
- package/src/nodes/core/MRTNode.js +6 -3
- package/src/nodes/core/Node.js +10 -51
- package/src/nodes/core/NodeBuilder.js +71 -5
- package/src/nodes/core/NodeUtils.js +48 -6
- package/src/nodes/core/OutputStructNode.js +8 -4
- package/src/nodes/core/ParameterNode.js +6 -3
- package/src/nodes/core/PropertyNode.js +7 -3
- package/src/nodes/core/StackNode.js +7 -3
- package/src/nodes/core/StructTypeNode.js +7 -3
- package/src/nodes/core/TempNode.js +8 -4
- package/src/nodes/core/UniformGroupNode.js +10 -6
- package/src/nodes/core/UniformNode.js +6 -3
- package/src/nodes/core/VarNode.js +8 -4
- package/src/nodes/core/VaryingNode.js +7 -3
- package/src/nodes/display/AfterImageNode.js +6 -0
- package/src/nodes/display/AnaglyphPassNode.js +6 -0
- package/src/nodes/display/AnamorphicNode.js +6 -0
- package/src/nodes/display/BloomNode.js +6 -0
- package/src/nodes/display/BumpMapNode.js +6 -0
- package/src/nodes/display/ColorSpaceFunctions.js +4 -4
- package/src/nodes/display/ColorSpaceNode.js +43 -14
- package/src/nodes/display/DenoiseNode.js +6 -3
- package/src/nodes/display/DepthOfFieldNode.js +6 -3
- package/src/nodes/display/DotScreenNode.js +8 -5
- package/src/nodes/display/FXAANode.js +6 -3
- package/src/nodes/display/FilmNode.js +6 -3
- package/src/nodes/display/FrontFacingNode.js +7 -3
- package/src/nodes/display/GTAONode.js +6 -3
- package/src/nodes/display/GaussianBlurNode.js +6 -3
- package/src/nodes/display/Lut3DNode.js +6 -3
- package/src/nodes/display/NormalMapNode.js +8 -6
- package/src/nodes/display/ParallaxBarrierPassNode.js +8 -5
- package/src/nodes/display/PassNode.js +18 -7
- package/src/nodes/display/PixelationPassNode.js +12 -5
- package/src/nodes/display/PosterizeNode.js +6 -3
- package/src/nodes/display/RGBShiftNode.js +6 -3
- package/src/nodes/display/RenderOutputNode.js +12 -8
- package/src/nodes/display/SSAAPassNode.js +6 -3
- package/src/nodes/display/ScreenNode.js +181 -0
- package/src/nodes/display/SobelOperatorNode.js +6 -3
- package/src/nodes/display/StereoCompositePassNode.js +6 -3
- package/src/nodes/display/StereoPassNode.js +6 -3
- package/src/nodes/display/ToneMappingFunctions.js +12 -12
- package/src/nodes/display/ToneMappingNode.js +8 -7
- package/src/nodes/display/ToonOutlinePassNode.js +111 -0
- package/src/nodes/display/TransitionNode.js +6 -3
- package/src/nodes/display/ViewportDepthNode.js +7 -3
- package/src/nodes/display/ViewportDepthTextureNode.js +8 -5
- package/src/nodes/display/ViewportSharedTextureNode.js +8 -5
- package/src/nodes/display/ViewportTextureNode.js +8 -5
- package/src/nodes/fog/FogExp2Node.js +6 -3
- package/src/nodes/fog/FogNode.js +7 -3
- package/src/nodes/fog/FogRangeNode.js +6 -3
- package/src/nodes/functions/PhysicalLightingModel.js +2 -2
- package/src/nodes/functions/material/getShIrradianceAt.js +28 -0
- package/src/nodes/geometry/RangeNode.js +7 -3
- package/src/nodes/gpgpu/AtomicFunctionNode.js +99 -0
- package/src/nodes/gpgpu/BarrierNode.js +40 -0
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +98 -0
- package/src/nodes/gpgpu/ComputeNode.js +8 -4
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +100 -0
- package/src/nodes/lighting/AONode.js +6 -3
- package/src/nodes/lighting/AmbientLightNode.js +6 -3
- package/src/nodes/lighting/AnalyticLightNode.js +198 -30
- package/src/nodes/lighting/BasicEnvironmentNode.js +6 -3
- package/src/nodes/lighting/BasicLightMapNode.js +6 -3
- package/src/nodes/lighting/DirectionalLightNode.js +7 -4
- package/src/nodes/lighting/EnvironmentNode.js +6 -3
- package/src/nodes/lighting/HemisphereLightNode.js +10 -6
- package/src/nodes/lighting/IESSpotLightNode.js +6 -3
- package/src/nodes/lighting/IrradianceNode.js +6 -3
- package/src/nodes/lighting/LightProbeNode.js +8 -31
- package/src/nodes/lighting/LightingContextNode.js +6 -3
- package/src/nodes/lighting/LightingNode.js +7 -3
- package/src/nodes/lighting/LightsNode.js +24 -5
- package/src/nodes/lighting/PointLightNode.js +11 -7
- package/src/nodes/lighting/RectAreaLightNode.js +11 -7
- package/src/nodes/lighting/SpotLightNode.js +13 -10
- package/src/nodes/math/ConditionalNode.js +23 -6
- package/src/nodes/math/MathNode.js +6 -3
- package/src/nodes/math/OperatorNode.js +6 -3
- package/src/nodes/pmrem/PMREMNode.js +6 -3
- package/src/nodes/utils/ArrayElementNode.js +8 -4
- package/src/nodes/utils/ConvertNode.js +7 -3
- package/src/nodes/utils/CubeMapNode.js +6 -3
- package/src/nodes/utils/EquirectUVNode.js +6 -3
- package/src/nodes/utils/FlipNode.js +7 -4
- package/src/nodes/utils/FunctionOverloadingNode.js +7 -3
- package/src/nodes/utils/JoinNode.js +6 -3
- package/src/nodes/utils/LoopNode.js +7 -3
- package/src/nodes/utils/MatcapUVNode.js +6 -3
- package/src/nodes/utils/MaxMipLevelNode.js +6 -3
- package/src/nodes/utils/OscNode.js +7 -3
- package/src/nodes/utils/RTTNode.js +6 -3
- package/src/nodes/utils/ReflectorNode.js +8 -5
- package/src/nodes/utils/RemapNode.js +7 -3
- package/src/nodes/utils/RotateNode.js +6 -3
- package/src/nodes/utils/SetNode.js +7 -4
- package/src/nodes/utils/SplitNode.js +7 -3
- package/src/nodes/utils/SpriteSheetUVNode.js +7 -3
- package/src/nodes/utils/StorageArrayElementNode.js +9 -8
- package/src/nodes/utils/TimerNode.js +6 -3
- package/src/nodes/utils/TriplanarTexturesNode.js +7 -3
- package/src/nodes/utils/ViewportUtils.js +2 -2
- package/src/objects/BatchedMesh.js +76 -10
- package/src/objects/LOD.js +21 -0
- package/src/objects/Line.js +1 -0
- package/src/objects/Mesh.js +7 -23
- package/src/objects/Points.js +2 -0
- package/src/renderers/WebGLRenderer.js +64 -41
- package/src/renderers/common/BundleGroup.js +26 -0
- package/src/renderers/common/ClippingContext.js +4 -3
- package/src/renderers/common/RenderContext.js +4 -5
- package/src/renderers/common/RenderObject.js +116 -5
- package/src/renderers/common/RenderObjects.js +8 -1
- package/src/renderers/common/Renderer.js +57 -49
- package/src/renderers/common/extras/PMREMGenerator.js +7 -9
- package/src/renderers/common/nodes/NodeBuilderState.js +3 -3
- package/src/renderers/common/nodes/Nodes.js +33 -14
- package/src/renderers/shaders/ShaderLib/sprite.glsl.js +2 -4
- package/src/renderers/webgl/WebGLAttributes.js +45 -14
- package/src/renderers/webgl/WebGLCapabilities.js +9 -0
- package/src/renderers/webgl/WebGLProgram.js +2 -0
- package/src/renderers/webgl/WebGLPrograms.js +21 -17
- package/src/renderers/webgl/WebGLState.js +21 -0
- package/src/renderers/webgl/WebGLTextures.js +22 -0
- package/src/renderers/webgl-fallback/WebGLBackend.js +50 -45
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +4 -4
- package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +6 -0
- package/src/renderers/webgl-fallback/utils/WebGLState.js +1 -4
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +61 -16
- package/src/renderers/webgpu/WebGPUBackend.js +33 -25
- package/src/renderers/webgpu/WebGPURenderer.Nodes.js +42 -0
- package/src/renderers/webgpu/WebGPURenderer.js +5 -2
- package/src/renderers/webgpu/nodes/BasicNodeLibrary.js +59 -0
- package/src/renderers/{common → webgpu}/nodes/StandardNodeLibrary.js +11 -11
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +91 -11
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +6 -16
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +1 -1
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +7 -5
- package/src/renderers/webgpu/utils/WebGPUUtils.js +1 -1
- package/src/utils.js +33 -1
- package/examples/jsm/geometries/SDFGeometryGenerator.js +0 -144
- package/examples/jsm/loaders/TiltLoader.js +0 -520
- package/examples/jsm/utils/GPUStatsPanel.js +0 -95
- package/examples/jsm/utils/PackedPhongMaterial.js +0 -178
- package/src/nodes/display/ViewportNode.js +0 -138
- package/src/nodes/lighting/LightNode.js +0 -57
- package/src/renderers/common/StandardRenderer.js +0 -18
|
@@ -692,20 +692,22 @@ class WebGLTextureUtils {
|
|
|
692
692
|
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
-
copyFramebufferToTexture( texture, renderContext ) {
|
|
695
|
+
copyFramebufferToTexture( texture, renderContext, rectangle ) {
|
|
696
696
|
|
|
697
697
|
const { gl } = this;
|
|
698
698
|
const { state } = this.backend;
|
|
699
699
|
|
|
700
700
|
const { textureGPU } = this.backend.get( texture );
|
|
701
701
|
|
|
702
|
-
const width =
|
|
703
|
-
const height = texture.image.height;
|
|
702
|
+
const { x, y, z: width, w: height } = rectangle;
|
|
704
703
|
|
|
705
704
|
const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 );
|
|
706
705
|
|
|
706
|
+
const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y;
|
|
707
|
+
|
|
707
708
|
if ( requireDrawFrameBuffer ) {
|
|
708
709
|
|
|
710
|
+
const partial = ( x !== 0 || y !== 0 );
|
|
709
711
|
let mask;
|
|
710
712
|
let attachment;
|
|
711
713
|
|
|
@@ -727,19 +729,45 @@ class WebGLTextureUtils {
|
|
|
727
729
|
|
|
728
730
|
}
|
|
729
731
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
+
if ( partial ) {
|
|
733
|
+
|
|
734
|
+
const renderTargetContextData = this.backend.get( renderContext.renderTarget );
|
|
735
|
+
|
|
736
|
+
const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ];
|
|
737
|
+
const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer;
|
|
738
|
+
|
|
739
|
+
state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
|
|
740
|
+
state.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer );
|
|
741
|
+
|
|
742
|
+
const flippedY = srcHeight - y - height;
|
|
743
|
+
|
|
744
|
+
gl.blitFramebuffer( x, flippedY, x + width, flippedY + height, x, flippedY, x + width, flippedY + height, mask, gl.NEAREST );
|
|
732
745
|
|
|
733
|
-
|
|
746
|
+
state.bindFramebuffer( gl.READ_FRAMEBUFFER, fb );
|
|
747
|
+
|
|
748
|
+
state.bindTexture( gl.TEXTURE_2D, textureGPU );
|
|
749
|
+
|
|
750
|
+
gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, flippedY, width, height );
|
|
751
|
+
|
|
752
|
+
state.unbindTexture();
|
|
753
|
+
|
|
754
|
+
} else {
|
|
734
755
|
|
|
735
|
-
|
|
756
|
+
const fb = gl.createFramebuffer();
|
|
736
757
|
|
|
737
|
-
|
|
758
|
+
state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
|
|
759
|
+
|
|
760
|
+
gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 );
|
|
761
|
+
gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST );
|
|
762
|
+
|
|
763
|
+
gl.deleteFramebuffer( fb );
|
|
764
|
+
|
|
765
|
+
}
|
|
738
766
|
|
|
739
767
|
} else {
|
|
740
768
|
|
|
741
769
|
state.bindTexture( gl.TEXTURE_2D, textureGPU );
|
|
742
|
-
gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0,
|
|
770
|
+
gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, x, srcHeight - height - y, width, height );
|
|
743
771
|
|
|
744
772
|
state.unbindTexture();
|
|
745
773
|
|
|
@@ -806,7 +834,7 @@ class WebGLTextureUtils {
|
|
|
806
834
|
|
|
807
835
|
}
|
|
808
836
|
|
|
809
|
-
async copyTextureToBuffer( texture, x, y, width, height ) {
|
|
837
|
+
async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) {
|
|
810
838
|
|
|
811
839
|
const { backend, gl } = this;
|
|
812
840
|
|
|
@@ -815,10 +843,13 @@ class WebGLTextureUtils {
|
|
|
815
843
|
const fb = gl.createFramebuffer();
|
|
816
844
|
|
|
817
845
|
gl.bindFramebuffer( gl.READ_FRAMEBUFFER, fb );
|
|
818
|
-
|
|
846
|
+
|
|
847
|
+
const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D;
|
|
848
|
+
|
|
849
|
+
gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 );
|
|
819
850
|
|
|
820
851
|
const typedArrayType = this._getTypedArrayType( glType );
|
|
821
|
-
const bytesPerTexel = this._getBytesPerTexel( glFormat );
|
|
852
|
+
const bytesPerTexel = this._getBytesPerTexel( glType, glFormat );
|
|
822
853
|
|
|
823
854
|
const elementCount = width * height;
|
|
824
855
|
const byteLength = elementCount * bytesPerTexel;
|
|
@@ -856,19 +887,33 @@ class WebGLTextureUtils {
|
|
|
856
887
|
if ( glType === gl.UNSIGNED_SHORT ) return Uint16Array;
|
|
857
888
|
if ( glType === gl.UNSIGNED_INT ) return Uint32Array;
|
|
858
889
|
|
|
890
|
+
if ( glType === gl.HALF_FLOAT ) return Uint16Array;
|
|
859
891
|
if ( glType === gl.FLOAT ) return Float32Array;
|
|
860
892
|
|
|
861
893
|
throw new Error( `Unsupported WebGL type: ${glType}` );
|
|
862
894
|
|
|
863
895
|
}
|
|
864
896
|
|
|
865
|
-
_getBytesPerTexel( glFormat ) {
|
|
897
|
+
_getBytesPerTexel( glType, glFormat ) {
|
|
866
898
|
|
|
867
899
|
const { gl } = this;
|
|
868
900
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
if (
|
|
901
|
+
let bytesPerComponent = 0;
|
|
902
|
+
|
|
903
|
+
if ( glType === gl.UNSIGNED_BYTE ) bytesPerComponent = 1;
|
|
904
|
+
|
|
905
|
+
if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ||
|
|
906
|
+
glType === gl.UNSIGNED_SHORT_5_5_5_1 ||
|
|
907
|
+
glType === gl.UNSIGNED_SHORT_5_6_5 ||
|
|
908
|
+
glType === gl.UNSIGNED_SHORT ||
|
|
909
|
+
glType === gl.HALF_FLOAT ) bytesPerComponent = 2;
|
|
910
|
+
|
|
911
|
+
if ( glType === gl.UNSIGNED_INT ||
|
|
912
|
+
glType === gl.FLOAT ) bytesPerComponent = 4;
|
|
913
|
+
|
|
914
|
+
if ( glFormat === gl.RGBA ) return bytesPerComponent * 4;
|
|
915
|
+
if ( glFormat === gl.RGB ) return bytesPerComponent * 3;
|
|
916
|
+
if ( glFormat === gl.ALPHA ) return bytesPerComponent;
|
|
872
917
|
|
|
873
918
|
}
|
|
874
919
|
|
|
@@ -425,7 +425,7 @@ class WebGPUBackend extends Backend {
|
|
|
425
425
|
renderContextData.descriptor = descriptor;
|
|
426
426
|
renderContextData.encoder = encoder;
|
|
427
427
|
renderContextData.currentPass = currentPass;
|
|
428
|
-
renderContextData.currentSets = { attributes: {}, pipeline: null, index: null };
|
|
428
|
+
renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
|
|
429
429
|
renderContextData.renderBundles = [];
|
|
430
430
|
|
|
431
431
|
//
|
|
@@ -829,13 +829,17 @@ class WebGPUBackend extends Backend {
|
|
|
829
829
|
|
|
830
830
|
draw( renderObject, info ) {
|
|
831
831
|
|
|
832
|
-
const { object,
|
|
832
|
+
const { object, context, pipeline } = renderObject;
|
|
833
833
|
const bindings = renderObject.getBindings();
|
|
834
834
|
const renderContextData = this.get( context );
|
|
835
835
|
const pipelineGPU = this.get( pipeline ).pipeline;
|
|
836
836
|
const currentSets = renderContextData.currentSets;
|
|
837
837
|
const passEncoderGPU = renderContextData.currentPass;
|
|
838
838
|
|
|
839
|
+
const drawParms = renderObject.getDrawParameters();
|
|
840
|
+
|
|
841
|
+
if ( drawParms === null ) return;
|
|
842
|
+
|
|
839
843
|
// pipeline
|
|
840
844
|
|
|
841
845
|
if ( currentSets.pipeline !== pipelineGPU ) {
|
|
@@ -848,12 +852,19 @@ class WebGPUBackend extends Backend {
|
|
|
848
852
|
|
|
849
853
|
// bind groups
|
|
850
854
|
|
|
855
|
+
const currentBindingGroups = currentSets.bindingGroups;
|
|
856
|
+
|
|
851
857
|
for ( let i = 0, l = bindings.length; i < l; i ++ ) {
|
|
852
858
|
|
|
853
859
|
const bindGroup = bindings[ i ];
|
|
854
860
|
const bindingsData = this.get( bindGroup );
|
|
855
861
|
|
|
856
|
-
|
|
862
|
+
if ( currentBindingGroups[ bindGroup.index ] !== bindGroup.id ) {
|
|
863
|
+
|
|
864
|
+
passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group );
|
|
865
|
+
currentBindingGroups[ bindGroup.index ] = bindGroup.id;
|
|
866
|
+
|
|
867
|
+
}
|
|
857
868
|
|
|
858
869
|
}
|
|
859
870
|
|
|
@@ -929,12 +940,6 @@ class WebGPUBackend extends Backend {
|
|
|
929
940
|
|
|
930
941
|
// draw
|
|
931
942
|
|
|
932
|
-
const drawRange = renderObject.drawRange;
|
|
933
|
-
const firstVertex = drawRange.start;
|
|
934
|
-
|
|
935
|
-
const instanceCount = this.getInstanceCount( renderObject );
|
|
936
|
-
if ( instanceCount === 0 ) return;
|
|
937
|
-
|
|
938
943
|
if ( object.isBatchedMesh === true ) {
|
|
939
944
|
|
|
940
945
|
const starts = object._multiDrawStarts;
|
|
@@ -955,16 +960,15 @@ class WebGPUBackend extends Backend {
|
|
|
955
960
|
|
|
956
961
|
} else if ( hasIndex === true ) {
|
|
957
962
|
|
|
958
|
-
const
|
|
963
|
+
const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParms;
|
|
959
964
|
|
|
960
|
-
passEncoderGPU.drawIndexed( indexCount, instanceCount,
|
|
965
|
+
passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 );
|
|
961
966
|
|
|
962
967
|
info.update( object, indexCount, instanceCount );
|
|
963
968
|
|
|
964
969
|
} else {
|
|
965
970
|
|
|
966
|
-
const
|
|
967
|
-
const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count;
|
|
971
|
+
const { vertexCount, instanceCount, firstVertex } = drawParms;
|
|
968
972
|
|
|
969
973
|
passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
|
|
970
974
|
|
|
@@ -1057,7 +1061,6 @@ class WebGPUBackend extends Backend {
|
|
|
1057
1061
|
|
|
1058
1062
|
}
|
|
1059
1063
|
|
|
1060
|
-
|
|
1061
1064
|
// textures
|
|
1062
1065
|
|
|
1063
1066
|
createSampler( texture ) {
|
|
@@ -1102,9 +1105,9 @@ class WebGPUBackend extends Backend {
|
|
|
1102
1105
|
|
|
1103
1106
|
}
|
|
1104
1107
|
|
|
1105
|
-
copyTextureToBuffer( texture, x, y, width, height ) {
|
|
1108
|
+
copyTextureToBuffer( texture, x, y, width, height, faceIndex ) {
|
|
1106
1109
|
|
|
1107
|
-
return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height );
|
|
1110
|
+
return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex );
|
|
1108
1111
|
|
|
1109
1112
|
}
|
|
1110
1113
|
|
|
@@ -1253,7 +1256,7 @@ class WebGPUBackend extends Backend {
|
|
|
1253
1256
|
renderContextData._currentPass = renderContextData.currentPass;
|
|
1254
1257
|
renderContextData._currentSets = renderContextData.currentSets;
|
|
1255
1258
|
|
|
1256
|
-
renderContextData.currentSets = { attributes: {}, pipeline: null, index: null };
|
|
1259
|
+
renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
|
|
1257
1260
|
renderContextData.currentPass = this.pipelineUtils.createBundleEncoder( renderContext );
|
|
1258
1261
|
|
|
1259
1262
|
}
|
|
@@ -1361,9 +1364,11 @@ class WebGPUBackend extends Backend {
|
|
|
1361
1364
|
|
|
1362
1365
|
let dstX = 0;
|
|
1363
1366
|
let dstY = 0;
|
|
1367
|
+
let dstLayer = 0;
|
|
1364
1368
|
|
|
1365
1369
|
let srcX = 0;
|
|
1366
1370
|
let srcY = 0;
|
|
1371
|
+
let srcLayer = 0;
|
|
1367
1372
|
|
|
1368
1373
|
let srcWidth = srcTexture.image.width;
|
|
1369
1374
|
let srcHeight = srcTexture.image.height;
|
|
@@ -1372,6 +1377,7 @@ class WebGPUBackend extends Backend {
|
|
|
1372
1377
|
|
|
1373
1378
|
srcX = srcRegion.x;
|
|
1374
1379
|
srcY = srcRegion.y;
|
|
1380
|
+
srcLayer = srcRegion.z || 0;
|
|
1375
1381
|
srcWidth = srcRegion.width;
|
|
1376
1382
|
srcHeight = srcRegion.height;
|
|
1377
1383
|
|
|
@@ -1381,6 +1387,7 @@ class WebGPUBackend extends Backend {
|
|
|
1381
1387
|
|
|
1382
1388
|
dstX = dstPosition.x;
|
|
1383
1389
|
dstY = dstPosition.y;
|
|
1390
|
+
dstLayer = dstPosition.z || 0;
|
|
1384
1391
|
|
|
1385
1392
|
}
|
|
1386
1393
|
|
|
@@ -1393,16 +1400,17 @@ class WebGPUBackend extends Backend {
|
|
|
1393
1400
|
{
|
|
1394
1401
|
texture: sourceGPU,
|
|
1395
1402
|
mipLevel: level,
|
|
1396
|
-
origin: { x: srcX, y: srcY, z:
|
|
1403
|
+
origin: { x: srcX, y: srcY, z: srcLayer }
|
|
1397
1404
|
},
|
|
1398
1405
|
{
|
|
1399
1406
|
texture: destinationGPU,
|
|
1400
1407
|
mipLevel: level,
|
|
1401
|
-
origin: { x: dstX, y: dstY, z:
|
|
1408
|
+
origin: { x: dstX, y: dstY, z: dstLayer }
|
|
1402
1409
|
},
|
|
1403
1410
|
[
|
|
1404
1411
|
srcWidth,
|
|
1405
|
-
srcHeight
|
|
1412
|
+
srcHeight,
|
|
1413
|
+
1
|
|
1406
1414
|
]
|
|
1407
1415
|
);
|
|
1408
1416
|
|
|
@@ -1410,7 +1418,7 @@ class WebGPUBackend extends Backend {
|
|
|
1410
1418
|
|
|
1411
1419
|
}
|
|
1412
1420
|
|
|
1413
|
-
copyFramebufferToTexture( texture, renderContext ) {
|
|
1421
|
+
copyFramebufferToTexture( texture, renderContext, rectangle ) {
|
|
1414
1422
|
|
|
1415
1423
|
const renderContextData = this.get( renderContext );
|
|
1416
1424
|
|
|
@@ -1459,14 +1467,14 @@ class WebGPUBackend extends Backend {
|
|
|
1459
1467
|
encoder.copyTextureToTexture(
|
|
1460
1468
|
{
|
|
1461
1469
|
texture: sourceGPU,
|
|
1462
|
-
origin: { x:
|
|
1470
|
+
origin: { x: rectangle.x, y: rectangle.y, z: 0 }
|
|
1463
1471
|
},
|
|
1464
1472
|
{
|
|
1465
1473
|
texture: destinationGPU
|
|
1466
1474
|
},
|
|
1467
1475
|
[
|
|
1468
|
-
|
|
1469
|
-
|
|
1476
|
+
rectangle.z,
|
|
1477
|
+
rectangle.w
|
|
1470
1478
|
]
|
|
1471
1479
|
);
|
|
1472
1480
|
|
|
@@ -1482,7 +1490,7 @@ class WebGPUBackend extends Backend {
|
|
|
1482
1490
|
if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load;
|
|
1483
1491
|
|
|
1484
1492
|
renderContextData.currentPass = encoder.beginRenderPass( descriptor );
|
|
1485
|
-
renderContextData.currentSets = { attributes: {}, pipeline: null, index: null };
|
|
1493
|
+
renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
|
|
1486
1494
|
|
|
1487
1495
|
}
|
|
1488
1496
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Renderer from '../common/Renderer.js';
|
|
2
|
+
import WebGLBackend from '../webgl-fallback/WebGLBackend.js';
|
|
3
|
+
import WebGPUBackend from './WebGPUBackend.js';
|
|
4
|
+
import BasicNodeLibrary from './nodes/BasicNodeLibrary.js';
|
|
5
|
+
|
|
6
|
+
class WebGPURenderer extends Renderer {
|
|
7
|
+
|
|
8
|
+
constructor( parameters = {} ) {
|
|
9
|
+
|
|
10
|
+
let BackendClass;
|
|
11
|
+
|
|
12
|
+
if ( parameters.forceWebGL ) {
|
|
13
|
+
|
|
14
|
+
BackendClass = WebGLBackend;
|
|
15
|
+
|
|
16
|
+
} else {
|
|
17
|
+
|
|
18
|
+
BackendClass = WebGPUBackend;
|
|
19
|
+
|
|
20
|
+
parameters.getFallback = () => {
|
|
21
|
+
|
|
22
|
+
console.warn( 'THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' );
|
|
23
|
+
|
|
24
|
+
return new WebGLBackend( parameters );
|
|
25
|
+
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const backend = new BackendClass( parameters );
|
|
31
|
+
|
|
32
|
+
super( backend, parameters );
|
|
33
|
+
|
|
34
|
+
this.nodes.library = new BasicNodeLibrary();
|
|
35
|
+
|
|
36
|
+
this.isWebGPURenderer = true;
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default WebGPURenderer;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Renderer from '../common/Renderer.js';
|
|
2
2
|
import WebGLBackend from '../webgl-fallback/WebGLBackend.js';
|
|
3
3
|
import WebGPUBackend from './WebGPUBackend.js';
|
|
4
|
+
import StandardNodeLibrary from './nodes/StandardNodeLibrary.js';
|
|
4
5
|
/*
|
|
5
6
|
const debugHandler = {
|
|
6
7
|
|
|
@@ -15,7 +16,7 @@ const debugHandler = {
|
|
|
15
16
|
|
|
16
17
|
};
|
|
17
18
|
*/
|
|
18
|
-
class WebGPURenderer extends
|
|
19
|
+
class WebGPURenderer extends Renderer {
|
|
19
20
|
|
|
20
21
|
constructor( parameters = {} ) {
|
|
21
22
|
|
|
@@ -44,6 +45,8 @@ class WebGPURenderer extends StandardRenderer {
|
|
|
44
45
|
//super( new Proxy( backend, debugHandler ) );
|
|
45
46
|
super( backend, parameters );
|
|
46
47
|
|
|
48
|
+
this.nodes.library = new StandardNodeLibrary();
|
|
49
|
+
|
|
47
50
|
this.isWebGPURenderer = true;
|
|
48
51
|
|
|
49
52
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import NodeLibrary from '../../common/nodes/NodeLibrary.js';
|
|
2
|
+
|
|
3
|
+
// Lights
|
|
4
|
+
import { PointLight } from '../../../lights/PointLight.js';
|
|
5
|
+
import { PointLightNode } from '../../../nodes/Nodes.js';
|
|
6
|
+
import { DirectionalLight } from '../../../lights/DirectionalLight.js';
|
|
7
|
+
import { DirectionalLightNode } from '../../../nodes/Nodes.js';
|
|
8
|
+
import { RectAreaLight } from '../../../lights/RectAreaLight.js';
|
|
9
|
+
import { RectAreaLightNode } from '../../../nodes/Nodes.js';
|
|
10
|
+
import { SpotLight } from '../../../lights/SpotLight.js';
|
|
11
|
+
import { SpotLightNode } from '../../../nodes/Nodes.js';
|
|
12
|
+
import { AmbientLight } from '../../../lights/AmbientLight.js';
|
|
13
|
+
import { AmbientLightNode } from '../../../nodes/Nodes.js';
|
|
14
|
+
import { HemisphereLight } from '../../../lights/HemisphereLight.js';
|
|
15
|
+
import { HemisphereLightNode } from '../../../nodes/Nodes.js';
|
|
16
|
+
import { LightProbe } from '../../../lights/LightProbe.js';
|
|
17
|
+
import { LightProbeNode } from '../../../nodes/Nodes.js';
|
|
18
|
+
import IESSpotLight from '../../../lights/webgpu/IESSpotLight.js';
|
|
19
|
+
import { IESSpotLightNode } from '../../../nodes/Nodes.js';
|
|
20
|
+
|
|
21
|
+
// Tone Mapping
|
|
22
|
+
import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js';
|
|
23
|
+
import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js';
|
|
24
|
+
|
|
25
|
+
// Color Space
|
|
26
|
+
import { LinearSRGBColorSpace, SRGBColorSpace } from '../../../constants.js';
|
|
27
|
+
import { linearSRGBTosRGB, sRGBToLinearSRGB } from '../../../nodes/display/ColorSpaceFunctions.js';
|
|
28
|
+
import { getColorSpaceMethod } from '../../../nodes/display/ColorSpaceNode.js';
|
|
29
|
+
|
|
30
|
+
class BasicNodeLibrary extends NodeLibrary {
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
|
|
34
|
+
super();
|
|
35
|
+
|
|
36
|
+
this.addLight( PointLightNode, PointLight );
|
|
37
|
+
this.addLight( DirectionalLightNode, DirectionalLight );
|
|
38
|
+
this.addLight( RectAreaLightNode, RectAreaLight );
|
|
39
|
+
this.addLight( SpotLightNode, SpotLight );
|
|
40
|
+
this.addLight( AmbientLightNode, AmbientLight );
|
|
41
|
+
this.addLight( HemisphereLightNode, HemisphereLight );
|
|
42
|
+
this.addLight( LightProbeNode, LightProbe );
|
|
43
|
+
this.addLight( IESSpotLightNode, IESSpotLight );
|
|
44
|
+
|
|
45
|
+
this.addToneMapping( linearToneMapping, LinearToneMapping );
|
|
46
|
+
this.addToneMapping( reinhardToneMapping, ReinhardToneMapping );
|
|
47
|
+
this.addToneMapping( cineonToneMapping, CineonToneMapping );
|
|
48
|
+
this.addToneMapping( acesFilmicToneMapping, ACESFilmicToneMapping );
|
|
49
|
+
this.addToneMapping( agxToneMapping, AgXToneMapping );
|
|
50
|
+
this.addToneMapping( neutralToneMapping, NeutralToneMapping );
|
|
51
|
+
|
|
52
|
+
this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) );
|
|
53
|
+
this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) );
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default BasicNodeLibrary;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import NodeLibrary from '
|
|
1
|
+
import NodeLibrary from '../../common/nodes/NodeLibrary.js';
|
|
2
2
|
|
|
3
3
|
// Materials
|
|
4
4
|
import { MeshPhongMaterial } from '../../../materials/MeshPhongMaterial.js';
|
|
@@ -52,12 +52,12 @@ import { IESSpotLightNode } from '../../../nodes/Nodes.js';
|
|
|
52
52
|
|
|
53
53
|
// Tone Mapping
|
|
54
54
|
import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js';
|
|
55
|
-
import
|
|
55
|
+
import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js';
|
|
56
56
|
|
|
57
57
|
// Color Space
|
|
58
58
|
import { LinearSRGBColorSpace, SRGBColorSpace } from '../../../constants.js';
|
|
59
|
+
import { linearSRGBTosRGB, sRGBToLinearSRGB } from '../../../nodes/display/ColorSpaceFunctions.js';
|
|
59
60
|
import { getColorSpaceMethod } from '../../../nodes/display/ColorSpaceNode.js';
|
|
60
|
-
import * as CSF from '../../../nodes/display/ColorSpaceFunctions.js';
|
|
61
61
|
|
|
62
62
|
class StandardNodeLibrary extends NodeLibrary {
|
|
63
63
|
|
|
@@ -88,15 +88,15 @@ class StandardNodeLibrary extends NodeLibrary {
|
|
|
88
88
|
this.addLight( LightProbeNode, LightProbe );
|
|
89
89
|
this.addLight( IESSpotLightNode, IESSpotLight );
|
|
90
90
|
|
|
91
|
-
this.addToneMapping(
|
|
92
|
-
this.addToneMapping(
|
|
93
|
-
this.addToneMapping(
|
|
94
|
-
this.addToneMapping(
|
|
95
|
-
this.addToneMapping(
|
|
96
|
-
this.addToneMapping(
|
|
91
|
+
this.addToneMapping( linearToneMapping, LinearToneMapping );
|
|
92
|
+
this.addToneMapping( reinhardToneMapping, ReinhardToneMapping );
|
|
93
|
+
this.addToneMapping( cineonToneMapping, CineonToneMapping );
|
|
94
|
+
this.addToneMapping( acesFilmicToneMapping, ACESFilmicToneMapping );
|
|
95
|
+
this.addToneMapping( agxToneMapping, AgXToneMapping );
|
|
96
|
+
this.addToneMapping( neutralToneMapping, NeutralToneMapping );
|
|
97
97
|
|
|
98
|
-
this.addColorSpace(
|
|
99
|
-
this.addColorSpace(
|
|
98
|
+
this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) );
|
|
99
|
+
this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) );
|
|
100
100
|
|
|
101
101
|
}
|
|
102
102
|
|