super-three 0.177.0 → 0.179.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/README.md +1 -1
- package/build/three.cjs +959 -231
- package/build/three.core.js +751 -170
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +210 -64
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +78 -29
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +3269 -1545
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +3093 -1545
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/Addons.js +1 -2
- package/examples/jsm/capabilities/WebGL.js +0 -27
- package/examples/jsm/capabilities/WebGPU.js +1 -1
- package/examples/jsm/controls/ArcballControls.js +1 -1
- package/examples/jsm/controls/TransformControls.js +61 -14
- package/examples/jsm/csm/CSMShadowNode.js +4 -4
- package/examples/jsm/environments/RoomEnvironment.js +8 -3
- package/examples/jsm/exporters/USDZExporter.js +676 -299
- package/examples/jsm/geometries/RoundedBoxGeometry.js +47 -8
- package/examples/jsm/interactive/HTMLMesh.js +5 -3
- package/examples/jsm/libs/meshopt_decoder.module.js +75 -58
- package/examples/jsm/lights/LightProbeGenerator.js +14 -3
- package/examples/jsm/loaders/ColladaLoader.js +1 -1
- package/examples/jsm/loaders/EXRLoader.js +210 -22
- package/examples/jsm/loaders/FBXLoader.js +2 -2
- package/examples/jsm/loaders/MaterialXLoader.js +212 -30
- package/examples/jsm/loaders/TTFLoader.js +13 -1
- package/examples/jsm/loaders/USDLoader.js +219 -0
- package/examples/jsm/loaders/USDZLoader.js +4 -892
- package/examples/jsm/loaders/usd/USDAParser.js +741 -0
- package/examples/jsm/loaders/usd/USDCParser.js +17 -0
- package/examples/jsm/objects/LensflareMesh.js +3 -3
- package/examples/jsm/objects/SkyMesh.js +2 -2
- package/examples/jsm/physics/RapierPhysics.js +95 -16
- package/examples/jsm/postprocessing/GTAOPass.js +10 -9
- package/examples/jsm/postprocessing/OutlinePass.js +17 -17
- package/examples/jsm/postprocessing/SSAOPass.js +10 -9
- package/examples/jsm/shaders/UnpackDepthRGBAShader.js +11 -2
- package/examples/jsm/transpiler/AST.js +381 -30
- package/examples/jsm/transpiler/GLSLDecoder.js +226 -86
- package/examples/jsm/transpiler/Linker.js +327 -0
- package/examples/jsm/transpiler/TSLEncoder.js +197 -92
- package/examples/jsm/transpiler/Transpiler.js +17 -1
- package/examples/jsm/transpiler/TranspilerUtils.js +29 -0
- package/examples/jsm/transpiler/WGSLEncoder.js +788 -0
- package/examples/jsm/tsl/display/BloomNode.js +8 -7
- package/examples/jsm/tsl/display/ChromaticAberrationNode.js +206 -0
- package/examples/jsm/tsl/display/GaussianBlurNode.js +8 -10
- package/examples/jsm/tsl/display/SSAAPassNode.js +2 -2
- package/examples/jsm/tsl/display/{TRAAPassNode.js → TRAANode.js} +181 -172
- package/examples/jsm/tsl/display/hashBlur.js +3 -3
- package/examples/jsm/tsl/lighting/TiledLightsNode.js +1 -1
- package/package.json +1 -1
- package/src/Three.Core.js +1 -0
- package/src/Three.TSL.js +77 -28
- package/src/Three.WebGPU.js +2 -0
- package/src/animation/KeyframeTrack.js +1 -1
- package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
- package/src/animation/tracks/StringKeyframeTrack.js +1 -1
- package/src/cameras/Camera.js +14 -0
- package/src/cameras/OrthographicCamera.js +1 -1
- package/src/cameras/PerspectiveCamera.js +1 -1
- package/src/constants.js +3 -3
- package/src/core/BufferAttribute.js +3 -3
- package/src/core/Clock.js +2 -8
- package/src/core/GLBufferAttribute.js +13 -1
- package/src/core/Object3D.js +1 -1
- package/{examples/jsm/misc → src/core}/Timer.js +4 -42
- package/src/extras/PMREMGenerator.js +11 -0
- package/src/extras/core/Path.js +22 -22
- package/src/helpers/CameraHelper.js +41 -11
- package/src/helpers/SkeletonHelper.js +35 -6
- package/src/lights/LightShadow.js +21 -8
- package/src/lights/PointLightShadow.js +1 -1
- package/src/loaders/FileLoader.js +27 -4
- package/src/loaders/ImageBitmapLoader.js +27 -4
- package/src/loaders/ImageLoader.js +55 -8
- package/src/loaders/Loader.js +14 -0
- package/src/loaders/LoadingManager.js +23 -0
- package/src/materials/MeshBasicMaterial.js +1 -1
- package/src/materials/nodes/Line2NodeMaterial.js +0 -8
- package/src/materials/nodes/MeshBasicNodeMaterial.js +4 -3
- package/src/materials/nodes/MeshMatcapNodeMaterial.js +1 -1
- package/src/materials/nodes/MeshNormalNodeMaterial.js +2 -2
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +2 -1
- package/src/materials/nodes/MeshSSSNodeMaterial.js +2 -2
- package/src/materials/nodes/NodeMaterial.js +28 -5
- package/src/materials/nodes/PointsNodeMaterial.js +5 -0
- package/src/materials/nodes/manager/NodeMaterialObserver.js +87 -2
- package/src/math/Frustum.js +25 -9
- package/src/math/FrustumArray.js +10 -5
- package/src/math/Line3.js +129 -2
- package/src/math/Matrix4.js +48 -27
- package/src/math/Quaternion.js +1 -1
- package/src/math/Spherical.js +2 -2
- package/src/nodes/Nodes.js +2 -3
- package/src/nodes/TSL.js +5 -3
- package/src/nodes/accessors/AccessorsUtils.js +7 -8
- package/src/nodes/accessors/Bitangent.js +31 -25
- package/src/nodes/accessors/Camera.js +12 -12
- package/src/nodes/accessors/Normal.js +95 -29
- package/src/nodes/accessors/Object3DNode.js +1 -1
- package/src/nodes/accessors/Position.js +7 -7
- package/src/nodes/accessors/ReferenceNode.js +18 -3
- package/src/nodes/accessors/ReflectVector.js +3 -3
- package/src/nodes/accessors/SceneNode.js +1 -1
- package/src/nodes/accessors/StorageTextureNode.js +1 -1
- package/src/nodes/accessors/Tangent.js +25 -17
- package/src/nodes/accessors/TangentUtils.js +46 -0
- package/src/nodes/accessors/TextureBicubic.js +21 -3
- package/src/nodes/accessors/TextureNode.js +12 -0
- package/src/nodes/accessors/UniformArrayNode.js +0 -16
- package/src/nodes/core/ArrayNode.js +12 -0
- package/src/nodes/core/AssignNode.js +3 -0
- package/src/nodes/core/CacheNode.js +0 -14
- package/src/nodes/core/ContextNode.js +20 -1
- package/src/nodes/core/Node.js +15 -3
- package/src/nodes/core/NodeBuilder.js +228 -92
- package/src/nodes/core/NodeUtils.js +4 -1
- package/src/nodes/core/StackNode.js +49 -29
- package/src/nodes/core/SubBuildNode.js +89 -0
- package/src/nodes/core/UniformNode.js +63 -5
- package/src/nodes/core/VarNode.js +91 -2
- package/src/nodes/core/VaryingNode.js +6 -4
- package/src/nodes/display/BlendModes.js +2 -2
- package/src/nodes/display/FrontFacingNode.js +34 -2
- package/src/nodes/display/NormalMapNode.js +19 -50
- package/src/nodes/display/PassNode.js +157 -9
- package/src/nodes/display/ScreenNode.js +0 -26
- package/src/nodes/display/ViewportTextureNode.js +67 -7
- package/src/nodes/functions/BSDF/BRDF_GGX.js +2 -6
- package/src/nodes/functions/BSDF/BRDF_Sheen.js +4 -4
- package/src/nodes/functions/PhongLightingModel.js +3 -3
- package/src/nodes/functions/PhysicalLightingModel.js +16 -16
- package/src/nodes/functions/material/getGeometryRoughness.js +2 -2
- package/src/nodes/gpgpu/AtomicFunctionNode.js +1 -1
- package/src/nodes/gpgpu/ComputeNode.js +67 -23
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +28 -3
- package/src/nodes/lighting/EnvironmentNode.js +5 -5
- package/src/nodes/lighting/LightsNode.js +4 -4
- package/src/nodes/lighting/ProjectorLightNode.js +19 -6
- package/src/nodes/lighting/ShadowFilterNode.js +1 -1
- package/src/nodes/lighting/ShadowNode.js +2 -2
- package/src/nodes/materialx/MaterialXNodes.js +131 -2
- package/src/nodes/materialx/lib/mx_noise.js +165 -1
- package/src/nodes/math/ConditionalNode.js +1 -20
- package/src/nodes/math/MathNode.js +90 -55
- package/src/nodes/math/OperatorNode.js +22 -39
- package/src/nodes/tsl/TSLBase.js +1 -0
- package/src/nodes/tsl/TSLCore.js +114 -55
- package/src/nodes/utils/DebugNode.js +1 -1
- package/src/nodes/utils/EquirectUV.js +27 -0
- package/src/nodes/utils/EventNode.js +83 -0
- package/src/nodes/utils/LoopNode.js +0 -17
- package/src/nodes/utils/MatcapUV.js +22 -0
- package/src/nodes/utils/RTTNode.js +22 -5
- package/src/nodes/utils/ReflectorNode.js +11 -4
- package/src/nodes/utils/SampleNode.js +81 -0
- package/src/nodes/utils/TriplanarTextures.js +65 -0
- package/src/objects/BatchedMesh.js +4 -2
- package/src/renderers/WebGLRenderer.js +26 -24
- package/src/renderers/common/Background.js +2 -2
- package/src/renderers/common/Bindings.js +19 -18
- package/src/renderers/common/Color4.js +2 -2
- package/src/renderers/common/CubeRenderTarget.js +1 -1
- package/src/renderers/common/PostProcessing.js +60 -5
- package/src/renderers/common/RenderObject.js +68 -3
- package/src/renderers/common/Renderer.js +19 -16
- package/src/renderers/common/SampledTexture.js +3 -71
- package/src/renderers/common/Sampler.js +79 -0
- package/src/renderers/common/Storage3DTexture.js +100 -0
- package/src/renderers/common/StorageArrayTexture.js +84 -0
- package/src/renderers/common/StorageTexture.js +19 -0
- package/src/renderers/common/Textures.js +19 -3
- package/src/renderers/common/XRManager.js +31 -12
- package/src/renderers/common/XRRenderTarget.js +21 -4
- package/src/renderers/common/extras/PMREMGenerator.js +1 -1
- package/src/renderers/common/nodes/NodeSampledTexture.js +0 -12
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +20 -2
- package/src/renderers/shaders/ShaderLib/depth.glsl.js +11 -2
- package/src/renderers/webgl/WebGLAttributes.js +4 -0
- package/src/renderers/webgl/WebGLCapabilities.js +2 -2
- package/src/renderers/webgl/WebGLProgram.js +12 -6
- package/src/renderers/webgl/WebGLPrograms.js +6 -4
- package/src/renderers/webgl/WebGLShadowMap.js +11 -1
- package/src/renderers/webgl/WebGLState.js +4 -4
- package/src/renderers/webgl/WebGLTextures.js +19 -7
- package/src/renderers/webgl-fallback/WebGLBackend.js +103 -72
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +3 -5
- package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +4 -0
- package/src/renderers/webgl-fallback/utils/WebGLState.js +4 -4
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +2 -0
- package/src/renderers/webgpu/WebGPUBackend.js +63 -16
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +64 -79
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +6 -0
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +45 -31
- package/src/renderers/webgpu/utils/WebGPUConstants.js +7 -1
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +5 -5
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +12 -65
- package/src/renderers/webgpu/utils/WebGPUUtils.js +2 -17
- package/src/renderers/webxr/WebXRDepthSensing.js +6 -10
- package/src/renderers/webxr/WebXRManager.js +68 -6
- package/src/textures/ExternalTexture.js +45 -0
- package/src/textures/FramebufferTexture.js +2 -2
- package/src/textures/Source.js +11 -1
- package/src/textures/VideoTexture.js +30 -2
- package/src/nodes/utils/EquirectUVNode.js +0 -65
- package/src/nodes/utils/MatcapUVNode.js +0 -49
- package/src/nodes/utils/TriplanarTexturesNode.js +0 -148
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
import { REVISION } from 'three/webgpu';
|
|
2
|
+
|
|
3
|
+
import { VariableDeclaration, Accessor } from './AST.js';
|
|
4
|
+
import { isExpression } from './TranspilerUtils.js';
|
|
5
|
+
|
|
6
|
+
// Note: This is a simplified list. A complete implementation would need more mappings.
|
|
7
|
+
const typeMap = {
|
|
8
|
+
'float': 'f32',
|
|
9
|
+
'int': 'i32',
|
|
10
|
+
'uint': 'u32',
|
|
11
|
+
'bool': 'bool',
|
|
12
|
+
'vec2': 'vec2f',
|
|
13
|
+
'ivec2': 'vec2i',
|
|
14
|
+
'uvec2': 'vec2u',
|
|
15
|
+
'bvec2': 'vec2b',
|
|
16
|
+
'vec3': 'vec3f',
|
|
17
|
+
'ivec3': 'vec3i',
|
|
18
|
+
'uvec3': 'vec3u',
|
|
19
|
+
'bvec3': 'vec3b',
|
|
20
|
+
'vec4': 'vec4f',
|
|
21
|
+
'ivec4': 'vec4i',
|
|
22
|
+
'uvec4': 'vec4u',
|
|
23
|
+
'bvec4': 'vec4b',
|
|
24
|
+
'mat3': 'mat3x3<f32>',
|
|
25
|
+
'mat4': 'mat4x4<f32>',
|
|
26
|
+
'texture': 'texture_2d<f32>',
|
|
27
|
+
'textureCube': 'texture_cube<f32>',
|
|
28
|
+
'texture3D': 'texture_3d<f32>',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// GLSL to WGSL built-in function mapping
|
|
32
|
+
const wgslLib = {
|
|
33
|
+
'abs': 'abs',
|
|
34
|
+
'acos': 'acos',
|
|
35
|
+
'asin': 'asin',
|
|
36
|
+
'atan': 'atan',
|
|
37
|
+
'atan2': 'atan2',
|
|
38
|
+
'ceil': 'ceil',
|
|
39
|
+
'clamp': 'clamp',
|
|
40
|
+
'cos': 'cos',
|
|
41
|
+
'cross': 'cross',
|
|
42
|
+
'degrees': 'degrees',
|
|
43
|
+
'distance': 'distance',
|
|
44
|
+
'dot': 'dot',
|
|
45
|
+
'exp': 'exp',
|
|
46
|
+
'exp2': 'exp2',
|
|
47
|
+
'faceforward': 'faceForward',
|
|
48
|
+
'floor': 'floor',
|
|
49
|
+
'fract': 'fract',
|
|
50
|
+
'inverse': 'inverse',
|
|
51
|
+
'inversesqrt': 'inverseSqrt',
|
|
52
|
+
'length': 'length',
|
|
53
|
+
'log': 'log',
|
|
54
|
+
'log2': 'log2',
|
|
55
|
+
'max': 'max',
|
|
56
|
+
'min': 'min',
|
|
57
|
+
'mix': 'mix',
|
|
58
|
+
'normalize': 'normalize',
|
|
59
|
+
'pow': 'pow',
|
|
60
|
+
'radians': 'radians',
|
|
61
|
+
'reflect': 'reflect',
|
|
62
|
+
'refract': 'refract',
|
|
63
|
+
'round': 'round',
|
|
64
|
+
'sign': 'sign',
|
|
65
|
+
'sin': 'sin',
|
|
66
|
+
'smoothstep': 'smoothstep',
|
|
67
|
+
'sqrt': 'sqrt',
|
|
68
|
+
'step': 'step',
|
|
69
|
+
'tan': 'tan',
|
|
70
|
+
'transpose': 'transpose',
|
|
71
|
+
'trunc': 'trunc',
|
|
72
|
+
'dFdx': 'dpdx',
|
|
73
|
+
'dFdy': 'dpdy',
|
|
74
|
+
'fwidth': 'fwidth',
|
|
75
|
+
// Texture functions are handled separately
|
|
76
|
+
'texture': 'textureSample',
|
|
77
|
+
'texture2D': 'textureSample',
|
|
78
|
+
'texture3D': 'textureSample',
|
|
79
|
+
'textureCube': 'textureSample',
|
|
80
|
+
'textureLod': 'textureSampleLevel',
|
|
81
|
+
'texelFetch': 'textureLoad',
|
|
82
|
+
'textureGrad': 'textureSampleGrad',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
class WGSLEncoder {
|
|
86
|
+
|
|
87
|
+
constructor() {
|
|
88
|
+
|
|
89
|
+
this.tab = '';
|
|
90
|
+
this.functions = new Map();
|
|
91
|
+
this.uniforms = [];
|
|
92
|
+
this.varyings = [];
|
|
93
|
+
this.structs = new Map();
|
|
94
|
+
this.polyfills = new Map();
|
|
95
|
+
|
|
96
|
+
// Assume a single group for simplicity
|
|
97
|
+
this.groupIndex = 0;
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getWgslType( type ) {
|
|
102
|
+
|
|
103
|
+
return typeMap[ type ] || type;
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
emitExpression( node ) {
|
|
108
|
+
|
|
109
|
+
if ( ! node ) return '';
|
|
110
|
+
|
|
111
|
+
let code;
|
|
112
|
+
|
|
113
|
+
if ( node.isAccessor ) {
|
|
114
|
+
|
|
115
|
+
// Check if this accessor is part of a uniform struct
|
|
116
|
+
const uniform = this.uniforms.find( u => u.name === node.property );
|
|
117
|
+
|
|
118
|
+
if ( uniform && ! uniform.type.includes( 'texture' ) ) {
|
|
119
|
+
|
|
120
|
+
return `uniforms.${node.property}`;
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
code = node.property;
|
|
125
|
+
|
|
126
|
+
} else if ( node.isNumber ) {
|
|
127
|
+
|
|
128
|
+
code = node.value;
|
|
129
|
+
|
|
130
|
+
// WGSL requires floating point numbers to have a decimal
|
|
131
|
+
if ( node.type === 'float' && ! code.includes( '.' ) ) {
|
|
132
|
+
|
|
133
|
+
code += '.0';
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
} else if ( node.isOperator ) {
|
|
138
|
+
|
|
139
|
+
const left = this.emitExpression( node.left );
|
|
140
|
+
const right = this.emitExpression( node.right );
|
|
141
|
+
|
|
142
|
+
code = `${ left } ${ node.type } ${ right }`;
|
|
143
|
+
|
|
144
|
+
if ( node.parent.isAssignment !== true && node.parent.isOperator ) {
|
|
145
|
+
|
|
146
|
+
code = `( ${ code } )`;
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
} else if ( node.isFunctionCall ) {
|
|
151
|
+
|
|
152
|
+
const fnName = wgslLib[ node.name ] || node.name;
|
|
153
|
+
|
|
154
|
+
if ( fnName === 'mod' ) {
|
|
155
|
+
|
|
156
|
+
const snippets = node.params.map( p => this.emitExpression( p ) );
|
|
157
|
+
const types = node.params.map( p => p.getType() );
|
|
158
|
+
|
|
159
|
+
const modFnName = 'mod_' + types.join( '_' );
|
|
160
|
+
|
|
161
|
+
if ( this.polyfills.has( modFnName ) === false ) {
|
|
162
|
+
|
|
163
|
+
this.polyfills.set( modFnName, `fn ${ modFnName }( x: ${ this.getWgslType( types[ 0 ] ) }, y: ${ this.getWgslType( types[ 1 ] ) } ) -> ${ this.getWgslType( types[ 0 ] ) } {
|
|
164
|
+
|
|
165
|
+
return x - y * floor( x / y );
|
|
166
|
+
|
|
167
|
+
}` );
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
code = `${ modFnName }( ${ snippets.join( ', ' ) } )`;
|
|
172
|
+
|
|
173
|
+
} else if ( fnName.startsWith( 'texture' ) ) {
|
|
174
|
+
|
|
175
|
+
// Handle texture functions separately due to sampler handling
|
|
176
|
+
|
|
177
|
+
code = this.emitTextureAccess( node );
|
|
178
|
+
|
|
179
|
+
} else {
|
|
180
|
+
|
|
181
|
+
const params = node.params.map( p => this.emitExpression( p ) );
|
|
182
|
+
|
|
183
|
+
if ( typeMap[ fnName ] ) {
|
|
184
|
+
|
|
185
|
+
// Handle type constructors like vec3(...)
|
|
186
|
+
|
|
187
|
+
code = this.getWgslType( fnName );
|
|
188
|
+
|
|
189
|
+
} else {
|
|
190
|
+
|
|
191
|
+
code = fnName;
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if ( params.length > 0 ) {
|
|
196
|
+
|
|
197
|
+
code += '( ' + params.join( ', ' ) + ' )';
|
|
198
|
+
|
|
199
|
+
} else {
|
|
200
|
+
|
|
201
|
+
code += '()';
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
} else if ( node.isReturn ) {
|
|
208
|
+
|
|
209
|
+
code = 'return';
|
|
210
|
+
|
|
211
|
+
if ( node.value ) {
|
|
212
|
+
|
|
213
|
+
code += ' ' + this.emitExpression( node.value );
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
} else if ( node.isDiscard ) {
|
|
218
|
+
|
|
219
|
+
code = 'discard';
|
|
220
|
+
|
|
221
|
+
} else if ( node.isBreak ) {
|
|
222
|
+
|
|
223
|
+
if ( node.parent.isSwitchCase !== true ) {
|
|
224
|
+
|
|
225
|
+
code = 'break';
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
} else if ( node.isContinue ) {
|
|
230
|
+
|
|
231
|
+
code = 'continue';
|
|
232
|
+
|
|
233
|
+
} else if ( node.isAccessorElements ) {
|
|
234
|
+
|
|
235
|
+
code = this.emitExpression( node.object );
|
|
236
|
+
|
|
237
|
+
for ( const element of node.elements ) {
|
|
238
|
+
|
|
239
|
+
const value = this.emitExpression( element.value );
|
|
240
|
+
|
|
241
|
+
if ( element.isStaticElement ) {
|
|
242
|
+
|
|
243
|
+
code += '.' + value;
|
|
244
|
+
|
|
245
|
+
} else if ( element.isDynamicElement ) {
|
|
246
|
+
|
|
247
|
+
code += `[${value}]`;
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
} else if ( node.isFor ) {
|
|
254
|
+
|
|
255
|
+
code = this.emitFor( node );
|
|
256
|
+
|
|
257
|
+
} else if ( node.isWhile ) {
|
|
258
|
+
|
|
259
|
+
code = this.emitWhile( node );
|
|
260
|
+
|
|
261
|
+
} else if ( node.isSwitch ) {
|
|
262
|
+
|
|
263
|
+
code = this.emitSwitch( node );
|
|
264
|
+
|
|
265
|
+
} else if ( node.isVariableDeclaration ) {
|
|
266
|
+
|
|
267
|
+
code = this.emitVariables( node );
|
|
268
|
+
|
|
269
|
+
} else if ( node.isUniform ) {
|
|
270
|
+
|
|
271
|
+
this.uniforms.push( node );
|
|
272
|
+
return ''; // Defer emission to the header
|
|
273
|
+
|
|
274
|
+
} else if ( node.isVarying ) {
|
|
275
|
+
|
|
276
|
+
this.varyings.push( node );
|
|
277
|
+
return ''; // Defer emission to the header
|
|
278
|
+
|
|
279
|
+
} else if ( node.isTernary ) {
|
|
280
|
+
|
|
281
|
+
const cond = this.emitExpression( node.cond );
|
|
282
|
+
const left = this.emitExpression( node.left );
|
|
283
|
+
const right = this.emitExpression( node.right );
|
|
284
|
+
|
|
285
|
+
// WGSL's equivalent to the ternary operator is select(false_val, true_val, condition)
|
|
286
|
+
code = `select( ${ right }, ${ left }, ${ cond } )`;
|
|
287
|
+
|
|
288
|
+
} else if ( node.isConditional ) {
|
|
289
|
+
|
|
290
|
+
code = this.emitConditional( node );
|
|
291
|
+
|
|
292
|
+
} else if ( node.isUnary ) {
|
|
293
|
+
|
|
294
|
+
const expr = this.emitExpression( node.expression );
|
|
295
|
+
|
|
296
|
+
if ( node.type === '++' || node.type === '--' ) {
|
|
297
|
+
|
|
298
|
+
const op = node.type === '++' ? '+' : '-';
|
|
299
|
+
|
|
300
|
+
code = `${ expr } = ${ expr } ${ op } 1`;
|
|
301
|
+
|
|
302
|
+
} else {
|
|
303
|
+
|
|
304
|
+
code = `${ node.type }${ expr }`;
|
|
305
|
+
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
} else {
|
|
309
|
+
|
|
310
|
+
console.warn( 'Unknown node type in WGSL Encoder:', node );
|
|
311
|
+
|
|
312
|
+
code = `/* unknown node: ${ node.constructor.name } */`;
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return code;
|
|
317
|
+
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
emitTextureAccess( node ) {
|
|
321
|
+
|
|
322
|
+
const wgslFn = wgslLib[ node.name ];
|
|
323
|
+
const textureName = this.emitExpression( node.params[ 0 ] );
|
|
324
|
+
const uv = this.emitExpression( node.params[ 1 ] );
|
|
325
|
+
|
|
326
|
+
// WGSL requires explicit samplers. We assume a naming convention.
|
|
327
|
+
const samplerName = `${textureName}_sampler`;
|
|
328
|
+
|
|
329
|
+
let code;
|
|
330
|
+
|
|
331
|
+
switch ( node.name ) {
|
|
332
|
+
|
|
333
|
+
case 'texture':
|
|
334
|
+
case 'texture2D':
|
|
335
|
+
case 'texture3D':
|
|
336
|
+
case 'textureCube':
|
|
337
|
+
// format: textureSample(texture, sampler, coords, [offset])
|
|
338
|
+
code = `${wgslFn}(${textureName}, ${samplerName}, ${uv}`;
|
|
339
|
+
// Handle optional bias parameter (note: WGSL uses textureSampleBias)
|
|
340
|
+
if ( node.params.length === 3 ) {
|
|
341
|
+
|
|
342
|
+
const bias = this.emitExpression( node.params[ 2 ] );
|
|
343
|
+
code = `textureSampleBias(${textureName}, ${samplerName}, ${uv}, ${bias})`;
|
|
344
|
+
|
|
345
|
+
} else {
|
|
346
|
+
|
|
347
|
+
code += ')';
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
break;
|
|
352
|
+
|
|
353
|
+
case 'textureLod':
|
|
354
|
+
// format: textureSampleLevel(texture, sampler, coords, level)
|
|
355
|
+
const lod = this.emitExpression( node.params[ 2 ] );
|
|
356
|
+
code = `${wgslFn}(${textureName}, ${samplerName}, ${uv}, ${lod})`;
|
|
357
|
+
break;
|
|
358
|
+
|
|
359
|
+
case 'textureGrad':
|
|
360
|
+
// format: textureSampleGrad(texture, sampler, coords, ddx, ddy)
|
|
361
|
+
const ddx = this.emitExpression( node.params[ 2 ] );
|
|
362
|
+
const ddy = this.emitExpression( node.params[ 3 ] );
|
|
363
|
+
code = `${wgslFn}(${textureName}, ${samplerName}, ${uv}, ${ddx}, ${ddy})`;
|
|
364
|
+
break;
|
|
365
|
+
|
|
366
|
+
case 'texelFetch':
|
|
367
|
+
// format: textureLoad(texture, coords, [level])
|
|
368
|
+
const coords = this.emitExpression( node.params[ 1 ] ); // should be ivec
|
|
369
|
+
const lodFetch = node.params.length > 2 ? this.emitExpression( node.params[ 2 ] ) : '0';
|
|
370
|
+
code = `${wgslFn}(${textureName}, ${coords}, ${lodFetch})`;
|
|
371
|
+
break;
|
|
372
|
+
|
|
373
|
+
default:
|
|
374
|
+
code = `/* unsupported texture op: ${node.name} */`;
|
|
375
|
+
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return code;
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
emitBody( body ) {
|
|
383
|
+
|
|
384
|
+
let code = '';
|
|
385
|
+
this.tab += '\t';
|
|
386
|
+
|
|
387
|
+
for ( const statement of body ) {
|
|
388
|
+
|
|
389
|
+
code += this.emitExtraLine( statement, body );
|
|
390
|
+
|
|
391
|
+
if ( statement.isComment ) {
|
|
392
|
+
|
|
393
|
+
code += this.emitComment( statement, body );
|
|
394
|
+
continue;
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const statementCode = this.emitExpression( statement );
|
|
399
|
+
|
|
400
|
+
if ( statementCode ) {
|
|
401
|
+
|
|
402
|
+
code += this.tab + statementCode;
|
|
403
|
+
|
|
404
|
+
if ( ! statementCode.endsWith( '}' ) && ! statementCode.endsWith( '{' ) ) {
|
|
405
|
+
|
|
406
|
+
code += ';';
|
|
407
|
+
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
code += '\n';
|
|
411
|
+
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
this.tab = this.tab.slice( 0, - 1 );
|
|
417
|
+
return code.slice( 0, - 1 ); // remove the last extra line
|
|
418
|
+
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
emitConditional( node ) {
|
|
422
|
+
|
|
423
|
+
const condStr = this.emitExpression( node.cond );
|
|
424
|
+
const bodyStr = this.emitBody( node.body );
|
|
425
|
+
|
|
426
|
+
let ifStr = `if ( ${ condStr } ) {\n\n${ bodyStr }\n\n${ this.tab }}`;
|
|
427
|
+
|
|
428
|
+
let current = node;
|
|
429
|
+
|
|
430
|
+
while ( current.elseConditional ) {
|
|
431
|
+
|
|
432
|
+
current = current.elseConditional;
|
|
433
|
+
const elseBodyStr = this.emitBody( current.body );
|
|
434
|
+
|
|
435
|
+
if ( current.cond ) { // This is an 'else if'
|
|
436
|
+
|
|
437
|
+
const elseCondStr = this.emitExpression( current.cond );
|
|
438
|
+
|
|
439
|
+
ifStr += ` else if ( ${ elseCondStr } ) {\n\n${ elseBodyStr }\n\n${ this.tab }}`;
|
|
440
|
+
|
|
441
|
+
} else { // This is an 'else'
|
|
442
|
+
|
|
443
|
+
ifStr += ` else {\n\n${ elseBodyStr }\n\n${ this.tab }}`;
|
|
444
|
+
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return ifStr;
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
emitFor( node ) {
|
|
454
|
+
|
|
455
|
+
const init = this.emitExpression( node.initialization );
|
|
456
|
+
const cond = this.emitExpression( node.condition );
|
|
457
|
+
const after = this.emitExpression( node.afterthought );
|
|
458
|
+
const body = this.emitBody( node.body );
|
|
459
|
+
|
|
460
|
+
return `for ( ${ init }; ${ cond }; ${ after } ) {\n\n${ body }\n\n${ this.tab }}`;
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
emitWhile( node ) {
|
|
465
|
+
|
|
466
|
+
const cond = this.emitExpression( node.condition );
|
|
467
|
+
const body = this.emitBody( node.body );
|
|
468
|
+
|
|
469
|
+
return `while ( ${ cond } ) {\n\n${ body }\n\n${ this.tab }}`;
|
|
470
|
+
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
emitSwitch( node ) {
|
|
474
|
+
|
|
475
|
+
const discriminant = this.emitExpression( node.discriminant );
|
|
476
|
+
|
|
477
|
+
let switchStr = `switch ( ${ discriminant } ) {\n\n`;
|
|
478
|
+
|
|
479
|
+
this.tab += '\t';
|
|
480
|
+
|
|
481
|
+
for ( const switchCase of node.cases ) {
|
|
482
|
+
|
|
483
|
+
const body = this.emitBody( switchCase.body );
|
|
484
|
+
|
|
485
|
+
if ( switchCase.isDefault ) {
|
|
486
|
+
|
|
487
|
+
switchStr += `${ this.tab }default: {\n\n${ body }\n\n${ this.tab }}\n\n`;
|
|
488
|
+
|
|
489
|
+
} else {
|
|
490
|
+
|
|
491
|
+
const cases = switchCase.conditions.map( c => this.emitExpression( c ) ).join( ', ' );
|
|
492
|
+
|
|
493
|
+
switchStr += `${ this.tab }case ${ cases }: {\n\n${ body }\n\n${ this.tab }}\n\n`;
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
this.tab = this.tab.slice( 0, - 1 );
|
|
500
|
+
|
|
501
|
+
switchStr += `${this.tab}}`;
|
|
502
|
+
|
|
503
|
+
return switchStr;
|
|
504
|
+
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
emitVariables( node ) {
|
|
508
|
+
|
|
509
|
+
const declarations = [];
|
|
510
|
+
|
|
511
|
+
let current = node;
|
|
512
|
+
|
|
513
|
+
while ( current ) {
|
|
514
|
+
|
|
515
|
+
const type = this.getWgslType( current.type );
|
|
516
|
+
|
|
517
|
+
let valueStr = '';
|
|
518
|
+
|
|
519
|
+
if ( current.value ) {
|
|
520
|
+
|
|
521
|
+
valueStr = ` = ${this.emitExpression( current.value )}`;
|
|
522
|
+
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// The AST linker tracks if a variable is ever reassigned.
|
|
526
|
+
// If so, use 'var'; otherwise, use 'let'.
|
|
527
|
+
|
|
528
|
+
let keyword;
|
|
529
|
+
|
|
530
|
+
if ( current.linker ) {
|
|
531
|
+
|
|
532
|
+
if ( current.linker.assignments.length > 0 ) {
|
|
533
|
+
|
|
534
|
+
keyword = 'var'; // Reassigned variable
|
|
535
|
+
|
|
536
|
+
} else {
|
|
537
|
+
|
|
538
|
+
if ( current.value && current.value.isNumericExpression ) {
|
|
539
|
+
|
|
540
|
+
keyword = 'const'; // Immutable numeric expression
|
|
541
|
+
|
|
542
|
+
} else {
|
|
543
|
+
|
|
544
|
+
keyword = 'let'; // Immutable variable
|
|
545
|
+
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
declarations.push( `${ keyword } ${ current.name }: ${ type }${ valueStr }` );
|
|
553
|
+
|
|
554
|
+
current = current.next;
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// In WGSL, multiple declarations in one line are not supported, so join with semicolons.
|
|
559
|
+
return declarations.join( ';\n' + this.tab );
|
|
560
|
+
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
emitFunction( node ) {
|
|
564
|
+
|
|
565
|
+
const name = node.name;
|
|
566
|
+
const returnType = this.getWgslType( node.type );
|
|
567
|
+
|
|
568
|
+
const params = [];
|
|
569
|
+
// We will prepend to a copy of the body, not the original AST node.
|
|
570
|
+
const body = [ ...node.body ];
|
|
571
|
+
|
|
572
|
+
for ( const param of node.params ) {
|
|
573
|
+
|
|
574
|
+
const paramName = param.name;
|
|
575
|
+
let paramType = this.getWgslType( param.type );
|
|
576
|
+
|
|
577
|
+
// Handle 'inout' and 'out' qualifiers using pointers. They are already mutable.
|
|
578
|
+
if ( param.qualifier === 'inout' || param.qualifier === 'out' ) {
|
|
579
|
+
|
|
580
|
+
paramType = `ptr<function, ${paramType}>`;
|
|
581
|
+
params.push( `${paramName}: ${paramType}` );
|
|
582
|
+
continue;
|
|
583
|
+
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// If the parameter is reassigned within the function, we need to
|
|
587
|
+
// create a local, mutable variable that shadows the parameter's name.
|
|
588
|
+
if ( param.linker && param.linker.assignments.length > 0 ) {
|
|
589
|
+
|
|
590
|
+
// 1. Rename the incoming parameter to avoid name collision.
|
|
591
|
+
const immutableParamName = `${paramName}_in`;
|
|
592
|
+
params.push( `${immutableParamName}: ${paramType}` );
|
|
593
|
+
|
|
594
|
+
// 2. Create a new Accessor node for the renamed immutable parameter.
|
|
595
|
+
const immutableAccessor = new Accessor( immutableParamName );
|
|
596
|
+
immutableAccessor.isAccessor = true;
|
|
597
|
+
immutableAccessor.property = immutableParamName;
|
|
598
|
+
|
|
599
|
+
// 3. Create a new VariableDeclaration node for the mutable local variable.
|
|
600
|
+
// This new variable will have the original parameter's name.
|
|
601
|
+
const mutableVar = new VariableDeclaration( param.type, param.name, immutableAccessor );
|
|
602
|
+
|
|
603
|
+
// 4. Mark this new variable as mutable so `emitVariables` uses `var`.
|
|
604
|
+
mutableVar.linker = { assignments: [ true ] };
|
|
605
|
+
|
|
606
|
+
// 5. Prepend this new declaration to the function's body.
|
|
607
|
+
body.unshift( mutableVar );
|
|
608
|
+
|
|
609
|
+
} else {
|
|
610
|
+
|
|
611
|
+
// This parameter is not reassigned, so treat it as a normal immutable parameter.
|
|
612
|
+
params.push( `${paramName}: ${paramType}` );
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const paramsStr = params.length > 0 ? ' ' + params.join( ', ' ) + ' ' : '';
|
|
619
|
+
const returnStr = ( returnType && returnType !== 'void' ) ? ` -> ${returnType}` : '';
|
|
620
|
+
|
|
621
|
+
// Emit the function body, which now includes our injected variable declarations.
|
|
622
|
+
const bodyStr = this.emitBody( body );
|
|
623
|
+
|
|
624
|
+
return `fn ${name}(${paramsStr})${returnStr} {\n\n${bodyStr}\n\n${this.tab}}`;
|
|
625
|
+
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
emitComment( statement, body ) {
|
|
629
|
+
|
|
630
|
+
const index = body.indexOf( statement );
|
|
631
|
+
const previous = body[ index - 1 ];
|
|
632
|
+
const next = body[ index + 1 ];
|
|
633
|
+
|
|
634
|
+
let output = '';
|
|
635
|
+
|
|
636
|
+
if ( previous && isExpression( previous ) ) {
|
|
637
|
+
|
|
638
|
+
output += '\n';
|
|
639
|
+
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
output += this.tab + statement.comment.replace( /\n/g, '\n' + this.tab ) + '\n';
|
|
643
|
+
|
|
644
|
+
if ( next && isExpression( next ) ) {
|
|
645
|
+
|
|
646
|
+
output += '\n';
|
|
647
|
+
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return output;
|
|
651
|
+
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
emitExtraLine( statement, body ) {
|
|
655
|
+
|
|
656
|
+
const index = body.indexOf( statement );
|
|
657
|
+
const previous = body[ index - 1 ];
|
|
658
|
+
|
|
659
|
+
if ( previous === undefined ) return '';
|
|
660
|
+
|
|
661
|
+
if ( statement.isReturn ) return '\n';
|
|
662
|
+
|
|
663
|
+
const lastExp = isExpression( previous );
|
|
664
|
+
const currExp = isExpression( statement );
|
|
665
|
+
|
|
666
|
+
if ( lastExp !== currExp || ( ! lastExp && ! currExp ) ) return '\n';
|
|
667
|
+
|
|
668
|
+
return '';
|
|
669
|
+
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
emit( ast ) {
|
|
673
|
+
|
|
674
|
+
const header = '// Three.js Transpiler r' + REVISION + '\n\n';
|
|
675
|
+
|
|
676
|
+
let globals = '';
|
|
677
|
+
let functions = '';
|
|
678
|
+
let dependencies = '';
|
|
679
|
+
|
|
680
|
+
// 1. Pre-process to find all global declarations
|
|
681
|
+
for ( const statement of ast.body ) {
|
|
682
|
+
|
|
683
|
+
if ( statement.isFunctionDeclaration ) {
|
|
684
|
+
|
|
685
|
+
this.functions.set( statement.name, statement );
|
|
686
|
+
|
|
687
|
+
} else if ( statement.isUniform ) {
|
|
688
|
+
|
|
689
|
+
this.uniforms.push( statement );
|
|
690
|
+
|
|
691
|
+
} else if ( statement.isVarying ) {
|
|
692
|
+
|
|
693
|
+
this.varyings.push( statement );
|
|
694
|
+
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// 2. Build resource bindings (uniforms, textures, samplers)
|
|
700
|
+
if ( this.uniforms.length > 0 ) {
|
|
701
|
+
|
|
702
|
+
let bindingIndex = 0;
|
|
703
|
+
const uniformStructMembers = [];
|
|
704
|
+
const textureGlobals = [];
|
|
705
|
+
|
|
706
|
+
for ( const uniform of this.uniforms ) {
|
|
707
|
+
|
|
708
|
+
// Textures are declared as separate global variables, not in the UBO
|
|
709
|
+
if ( uniform.type.includes( 'texture' ) ) {
|
|
710
|
+
|
|
711
|
+
textureGlobals.push( `@group(${this.groupIndex}) @binding(${bindingIndex ++}) var ${uniform.name}: ${this.getWgslType( uniform.type )};` );
|
|
712
|
+
textureGlobals.push( `@group(${this.groupIndex}) @binding(${bindingIndex ++}) var ${uniform.name}_sampler: sampler;` );
|
|
713
|
+
|
|
714
|
+
} else {
|
|
715
|
+
|
|
716
|
+
uniformStructMembers.push( `\t${uniform.name}: ${this.getWgslType( uniform.type )},` );
|
|
717
|
+
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Create a UBO struct if there are any non-texture uniforms
|
|
723
|
+
if ( uniformStructMembers.length > 0 ) {
|
|
724
|
+
|
|
725
|
+
globals += 'struct Uniforms {\n';
|
|
726
|
+
globals += uniformStructMembers.join( '\n' );
|
|
727
|
+
globals += '\n};\n';
|
|
728
|
+
globals += `@group(${this.groupIndex}) @binding(${bindingIndex ++}) var<uniform> uniforms: Uniforms;\n\n`;
|
|
729
|
+
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Add the texture and sampler globals
|
|
733
|
+
globals += textureGlobals.join( '\n' ) + '\n\n';
|
|
734
|
+
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// 3. Build varying structs for stage I/O
|
|
738
|
+
// This is a simplification; a full implementation would need to know the shader stage.
|
|
739
|
+
if ( this.varyings.length > 0 ) {
|
|
740
|
+
|
|
741
|
+
globals += 'struct Varyings {\n';
|
|
742
|
+
let location = 0;
|
|
743
|
+
for ( const varying of this.varyings ) {
|
|
744
|
+
|
|
745
|
+
globals += `\t@location(${location ++}) ${varying.name}: ${this.getWgslType( varying.type )},\n`;
|
|
746
|
+
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
globals += '};\n\n';
|
|
750
|
+
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// 4. Emit all functions and other global statements
|
|
754
|
+
for ( const statement of ast.body ) {
|
|
755
|
+
|
|
756
|
+
functions += this.emitExtraLine( statement, ast.body );
|
|
757
|
+
|
|
758
|
+
if ( statement.isFunctionDeclaration ) {
|
|
759
|
+
|
|
760
|
+
functions += this.emitFunction( statement ) + '\n';
|
|
761
|
+
|
|
762
|
+
} else if ( statement.isComment ) {
|
|
763
|
+
|
|
764
|
+
functions += this.emitComment( statement, ast.body );
|
|
765
|
+
|
|
766
|
+
} else if ( ! statement.isUniform && ! statement.isVarying ) {
|
|
767
|
+
|
|
768
|
+
// Handle other top-level statements like 'const'
|
|
769
|
+
functions += this.emitExpression( statement ) + ';\n';
|
|
770
|
+
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// 4. Build dependencies
|
|
776
|
+
for ( const value of this.polyfills.values() ) {
|
|
777
|
+
|
|
778
|
+
dependencies = `${ value }\n\n`;
|
|
779
|
+
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return header + dependencies + globals + functions.trimEnd() + '\n';
|
|
783
|
+
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
export default WGSLEncoder;
|