super-three 0.157.1 → 0.158.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.
Files changed (178) hide show
  1. package/README.md +6 -4
  2. package/build/three.cjs +1013 -790
  3. package/build/three.js +1013 -790
  4. package/build/three.min.js +1 -1
  5. package/build/three.module.js +1008 -791
  6. package/build/three.module.min.js +1 -1
  7. package/examples/jsm/Addons.js +290 -0
  8. package/examples/jsm/controls/FlyControls.js +26 -0
  9. package/examples/jsm/controls/OrbitControls.js +12 -1
  10. package/examples/jsm/controls/TransformControls.js +27 -11
  11. package/examples/jsm/csm/CSMShader.js +1 -1
  12. package/examples/jsm/exporters/GLTFExporter.js +72 -2
  13. package/examples/jsm/geometries/InstancedPointsGeometry.js +174 -0
  14. package/examples/jsm/geometries/SDFGeometryGenerator.js +144 -0
  15. package/examples/jsm/libs/lottie_canvas.module.js +6 -1
  16. package/examples/jsm/libs/opentype.module.js +13 -75
  17. package/examples/jsm/libs/surfaceNet.js +201 -0
  18. package/examples/jsm/loaders/GLTFLoader.js +12 -3
  19. package/examples/jsm/loaders/LUTImageLoader.js +162 -0
  20. package/examples/jsm/loaders/lwo/IFFParser.js +89 -93
  21. package/examples/jsm/materials/MeshGouraudMaterial.js +2 -0
  22. package/examples/jsm/math/Capsule.js +0 -55
  23. package/examples/jsm/math/Octree.js +70 -3
  24. package/examples/jsm/modifiers/SimplifyModifier.js +103 -11
  25. package/examples/jsm/modifiers/TessellateModifier.js +3 -3
  26. package/examples/jsm/nodes/Nodes.js +6 -6
  27. package/examples/jsm/nodes/accessors/CubeTextureNode.js +3 -3
  28. package/examples/jsm/nodes/accessors/InstanceNode.js +3 -3
  29. package/examples/jsm/nodes/accessors/InstancedPointsMaterialNode.js +21 -0
  30. package/examples/jsm/nodes/accessors/MaterialNode.js +68 -31
  31. package/examples/jsm/nodes/accessors/ModelNode.js +1 -2
  32. package/examples/jsm/nodes/accessors/MorphNode.js +5 -5
  33. package/examples/jsm/nodes/accessors/NormalNode.js +1 -1
  34. package/examples/jsm/nodes/accessors/PositionNode.js +1 -1
  35. package/examples/jsm/nodes/accessors/SkinningNode.js +13 -3
  36. package/examples/jsm/nodes/accessors/TextureNode.js +3 -3
  37. package/examples/jsm/nodes/code/FunctionNode.js +1 -1
  38. package/examples/jsm/nodes/core/AssignNode.js +72 -0
  39. package/examples/jsm/nodes/core/LightingModel.js +3 -1
  40. package/examples/jsm/nodes/core/Node.js +7 -12
  41. package/examples/jsm/nodes/core/NodeBuilder.js +126 -16
  42. package/examples/jsm/nodes/core/NodeUtils.js +4 -2
  43. package/examples/jsm/nodes/core/OutputStructNode.js +1 -1
  44. package/examples/jsm/nodes/core/ParameterNode.js +33 -0
  45. package/examples/jsm/nodes/core/PropertyNode.js +4 -10
  46. package/examples/jsm/nodes/core/StackNode.js +7 -17
  47. package/examples/jsm/nodes/core/TempNode.js +1 -1
  48. package/examples/jsm/nodes/core/VarNode.js +6 -35
  49. package/examples/jsm/nodes/core/VaryingNode.js +2 -0
  50. package/examples/jsm/nodes/display/BumpMapNode.js +35 -13
  51. package/examples/jsm/nodes/display/NormalMapNode.js +3 -1
  52. package/examples/jsm/nodes/display/ViewportNode.js +14 -4
  53. package/examples/jsm/nodes/functions/BSDF/BRDF_Sheen.js +20 -6
  54. package/examples/jsm/nodes/functions/BSDF/DFGApprox.js +8 -7
  55. package/examples/jsm/nodes/functions/BSDF/D_GGX.js +8 -3
  56. package/examples/jsm/nodes/functions/BSDF/Schlick_to_F0.js +8 -0
  57. package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +8 -0
  58. package/examples/jsm/nodes/functions/PhysicalLightingModel.js +93 -43
  59. package/examples/jsm/nodes/gpgpu/ComputeNode.js +2 -2
  60. package/examples/jsm/nodes/lighting/AmbientLightNode.js +1 -1
  61. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +19 -5
  62. package/examples/jsm/nodes/lighting/DirectionalLightNode.js +1 -1
  63. package/examples/jsm/nodes/lighting/EnvironmentNode.js +0 -6
  64. package/examples/jsm/nodes/lighting/LightingContextNode.js +21 -57
  65. package/examples/jsm/nodes/lighting/LightsNode.js +62 -4
  66. package/examples/jsm/nodes/lighting/PointLightNode.js +1 -1
  67. package/examples/jsm/nodes/lighting/SpotLightNode.js +1 -1
  68. package/examples/jsm/nodes/materials/InstancedPointsNodeMaterial.js +162 -0
  69. package/examples/jsm/nodes/materials/Line2NodeMaterial.js +70 -71
  70. package/examples/jsm/nodes/materials/LineDashedNodeMaterial.js +5 -5
  71. package/examples/jsm/nodes/materials/Materials.js +1 -0
  72. package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +2 -2
  73. package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +3 -3
  74. package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +47 -20
  75. package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +6 -6
  76. package/examples/jsm/nodes/materials/NodeMaterial.js +17 -20
  77. package/examples/jsm/nodes/materialx/lib/mx_noise.js +5 -5
  78. package/examples/jsm/nodes/math/OperatorNode.js +5 -21
  79. package/examples/jsm/nodes/shadernode/ShaderNode.js +128 -9
  80. package/examples/jsm/nodes/utils/ArrayElementNode.js +2 -0
  81. package/examples/jsm/nodes/utils/DiscardNode.js +3 -2
  82. package/examples/jsm/nodes/utils/JoinNode.js +11 -1
  83. package/examples/jsm/nodes/utils/LoopNode.js +36 -24
  84. package/examples/jsm/nodes/utils/SplitNode.js +2 -0
  85. package/examples/jsm/objects/BatchedMesh.js +586 -0
  86. package/examples/jsm/objects/InstancedPoints.js +21 -0
  87. package/examples/jsm/objects/Lensflare.js +20 -0
  88. package/examples/jsm/objects/ReflectorForSSRPass.js +3 -0
  89. package/examples/jsm/objects/Refractor.js +3 -0
  90. package/examples/jsm/objects/Sky.js +5 -3
  91. package/examples/jsm/objects/Water.js +5 -2
  92. package/examples/jsm/objects/Water2.js +3 -0
  93. package/examples/jsm/physics/AmmoPhysics.js +21 -0
  94. package/examples/jsm/physics/RapierPhysics.js +21 -0
  95. package/examples/jsm/postprocessing/BokehPass.js +3 -2
  96. package/examples/jsm/postprocessing/LUTPass.js +2 -1
  97. package/examples/jsm/postprocessing/OutputPass.js +1 -0
  98. package/examples/jsm/postprocessing/Pass.js +14 -3
  99. package/examples/jsm/postprocessing/SAOPass.js +0 -1
  100. package/examples/jsm/postprocessing/SMAAPass.js +0 -2
  101. package/examples/jsm/postprocessing/TAARenderPass.js +1 -2
  102. package/examples/jsm/renderers/CSS3DRenderer.js +3 -9
  103. package/examples/jsm/renderers/SVGRenderer.js +9 -6
  104. package/examples/jsm/renderers/common/Bindings.js +1 -1
  105. package/examples/jsm/renderers/common/RenderObject.js +8 -1
  106. package/examples/jsm/renderers/common/RenderObjects.js +1 -1
  107. package/examples/jsm/renderers/common/Textures.js +4 -36
  108. package/examples/jsm/renderers/common/nodes/Nodes.js +53 -18
  109. package/examples/jsm/renderers/webgl/WebGLBackend.js +291 -50
  110. package/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +88 -12
  111. package/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js +40 -5
  112. package/examples/jsm/renderers/webgl/utils/WebGLState.js +14 -2
  113. package/examples/jsm/renderers/webgpu/WebGPUBackend.js +2 -0
  114. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +36 -4
  115. package/examples/jsm/shaders/ACESFilmicToneMappingShader.js +2 -0
  116. package/examples/jsm/shaders/AfterimageShader.js +2 -0
  117. package/examples/jsm/shaders/BasicShader.js +2 -0
  118. package/examples/jsm/shaders/BlendShader.js +2 -0
  119. package/examples/jsm/shaders/BokehShader.js +2 -0
  120. package/examples/jsm/shaders/BokehShader2.js +4 -0
  121. package/examples/jsm/shaders/BrightnessContrastShader.js +2 -0
  122. package/examples/jsm/shaders/ColorCorrectionShader.js +2 -0
  123. package/examples/jsm/shaders/DOFMipMapShader.js +2 -0
  124. package/examples/jsm/shaders/DepthLimitedBlurShader.js +5 -0
  125. package/examples/jsm/shaders/FXAAShader.js +2 -0
  126. package/examples/jsm/shaders/FilmShader.js +1 -1
  127. package/examples/jsm/shaders/FocusShader.js +2 -0
  128. package/examples/jsm/shaders/FreiChenShader.js +2 -0
  129. package/examples/jsm/shaders/GodRaysShader.js +8 -0
  130. package/examples/jsm/shaders/HalftoneShader.js +2 -0
  131. package/examples/jsm/shaders/HorizontalTiltShiftShader.js +2 -0
  132. package/examples/jsm/shaders/HueSaturationShader.js +2 -0
  133. package/examples/jsm/shaders/KaleidoShader.js +2 -0
  134. package/examples/jsm/shaders/LuminosityHighPassShader.js +2 -0
  135. package/examples/jsm/shaders/LuminosityShader.js +2 -0
  136. package/examples/jsm/shaders/MMDToonShader.js +2 -0
  137. package/examples/jsm/shaders/MirrorShader.js +2 -0
  138. package/examples/jsm/shaders/NormalMapShader.js +2 -0
  139. package/examples/jsm/shaders/OutputShader.js +4 -5
  140. package/examples/jsm/shaders/SAOShader.js +5 -0
  141. package/examples/jsm/shaders/SMAAShader.js +6 -0
  142. package/examples/jsm/shaders/SSAOShader.js +6 -0
  143. package/examples/jsm/shaders/SSRShader.js +6 -0
  144. package/examples/jsm/shaders/SobelOperatorShader.js +2 -0
  145. package/examples/jsm/shaders/SubsurfaceScatteringShader.js +2 -0
  146. package/examples/jsm/shaders/TechnicolorShader.js +2 -0
  147. package/examples/jsm/shaders/TriangleBlurShader.js +2 -0
  148. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +2 -0
  149. package/examples/jsm/shaders/VelocityShader.js +2 -0
  150. package/examples/jsm/shaders/VerticalTiltShiftShader.js +2 -0
  151. package/examples/jsm/shaders/WaterRefractionShader.js +2 -0
  152. package/examples/jsm/transpiler/AST.js +231 -0
  153. package/examples/jsm/transpiler/GLSLDecoder.js +899 -0
  154. package/examples/jsm/transpiler/ShaderToyDecoder.js +49 -0
  155. package/examples/jsm/transpiler/TSLEncoder.js +611 -0
  156. package/examples/jsm/transpiler/Transpiler.js +18 -0
  157. package/examples/jsm/webxr/VRButton.js +1 -1
  158. package/examples/jsm/webxr/XRButton.js +7 -5
  159. package/examples/jsm/webxr/XREstimatedLight.js +1 -1
  160. package/package.json +4 -1
  161. package/src/constants.js +7 -1
  162. package/src/extras/PMREMGenerator.js +7 -1
  163. package/src/loaders/MaterialLoader.js +10 -2
  164. package/src/materials/Material.js +27 -13
  165. package/src/math/Box3.js +35 -18
  166. package/src/math/Vector3.js +11 -12
  167. package/src/objects/SkinnedMesh.js +6 -7
  168. package/src/renderers/WebGLRenderer.js +142 -25
  169. package/src/renderers/shaders/ShaderChunk/aomap_fragment.glsl.js +8 -0
  170. package/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl.js +3 -2
  171. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +1 -1
  172. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +8 -6
  173. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +2 -2
  174. package/src/renderers/webgl/WebGLProgram.js +80 -50
  175. package/src/renderers/webgl/WebGLPrograms.js +3 -0
  176. package/src/renderers/webgl/WebGLState.js +25 -4
  177. package/examples/jsm/nodes/accessors/ExtendedMaterialNode.js +0 -76
  178. package/examples/jsm/nodes/accessors/LineMaterialNode.js +0 -29
@@ -0,0 +1,899 @@
1
+ import { Program, FunctionDeclaration, For, AccessorElements, Ternary, DynamicElement, StaticElement, FunctionParameter, Unary, Conditional, VariableDeclaration, Operator, Number, FunctionCall, Return, Accessor } from './AST.js';
2
+
3
+ const unaryOperators = [
4
+ '+', '-', '~', '!', '++', '--'
5
+ ];
6
+
7
+ const precedenceOperators = [
8
+ '*', '/', '%',
9
+ '-', '+',
10
+ '<<', '>>',
11
+ '<', '>', '<=', '>=',
12
+ '==', '!=',
13
+ '&',
14
+ '^',
15
+ '|',
16
+ '&&',
17
+ '^^',
18
+ '||',
19
+ '?',
20
+ '=',
21
+ '+=', '-=', '*=', '/=', '%=', '^=', '&=', '|=', '<<=', '>>=',
22
+ ','
23
+ ].reverse();
24
+
25
+ const spaceRegExp = /^((\t| )\n*)+/;
26
+ const lineRegExp = /^\n+/;
27
+ const commentRegExp = /^\/\*[\s\S]*?\*\//;
28
+ const inlineCommentRegExp = /^\/\/.*?(\n|$)/;
29
+
30
+ const numberRegExp = /^((0x\w+)|(\.?\d+\.?\d*((e-?\d+)|\w)?))/;
31
+ const stringDoubleRegExp = /^(\"((?:[^"\\]|\\.)*)\")/;
32
+ const stringSingleRegExp = /^(\'((?:[^'\\]|\\.)*)\')/;
33
+ const literalRegExp = /^[A-Za-z](\w|\.)*/;
34
+ const operatorsRegExp = new RegExp( '^(\\' + [
35
+ '<<=', '>>=', '++', '--', '<<', '>>', '+=', '-=', '*=', '/=', '%=', '&=', '^^', '^=', '|=',
36
+ '<=', '>=', '==', '!=', '&&', '||',
37
+ '(', ')', '[', ']', '{', '}',
38
+ '.', ',', ';', '!', '=', '~', '*', '/', '%', '+', '-', '<', '>', '&', '^', '|', '?', ':', '#'
39
+ ].join( '$' ).split( '' ).join( '\\' ).replace( /\\\$/g, '|' ) + ')' );
40
+
41
+ function getGroupDelta( str ) {
42
+
43
+ if ( str === '(' || str === '[' || str === '{' ) return 1;
44
+ if ( str === ')' || str === ']' || str === '}' ) return - 1;
45
+
46
+ return 0;
47
+
48
+ }
49
+
50
+ class Token {
51
+
52
+ constructor( tokenizer, type, str, pos ) {
53
+
54
+ this.tokenizer = tokenizer;
55
+
56
+ this.type = type;
57
+
58
+ this.str = str;
59
+ this.pos = pos;
60
+
61
+ this.tag = null;
62
+
63
+ }
64
+
65
+ get endPos() {
66
+
67
+ return this.pos + this.str.length;
68
+
69
+ }
70
+
71
+ get isNumber() {
72
+
73
+ return this.type === Token.NUMBER;
74
+
75
+ }
76
+
77
+ get isString() {
78
+
79
+ return this.type === Token.STRING;
80
+
81
+ }
82
+
83
+ get isLiteral() {
84
+
85
+ return this.type === Token.LITERAL;
86
+
87
+ }
88
+
89
+ get isOperator() {
90
+
91
+ return this.type === Token.OPERATOR;
92
+
93
+ }
94
+
95
+ }
96
+
97
+ Token.LINE = 'line';
98
+ Token.COMMENT = 'comment';
99
+ Token.NUMBER = 'number';
100
+ Token.STRING = 'string';
101
+ Token.LITERAL = 'literal';
102
+ Token.OPERATOR = 'operator';
103
+
104
+ const TokenParserList = [
105
+ { type: Token.LINE, regexp: lineRegExp, isTag: true },
106
+ { type: Token.COMMENT, regexp: commentRegExp, isTag: true },
107
+ { type: Token.COMMENT, regexp: inlineCommentRegExp, isTag: true },
108
+ { type: Token.NUMBER, regexp: numberRegExp },
109
+ { type: Token.STRING, regexp: stringDoubleRegExp, group: 2 },
110
+ { type: Token.STRING, regexp: stringSingleRegExp, group: 2 },
111
+ { type: Token.LITERAL, regexp: literalRegExp },
112
+ { type: Token.OPERATOR, regexp: operatorsRegExp }
113
+ ];
114
+
115
+ class Tokenizer {
116
+
117
+ constructor( source ) {
118
+
119
+ this.source = source;
120
+ this.position = 0;
121
+
122
+ this.tokens = [];
123
+
124
+ }
125
+
126
+ tokenize() {
127
+
128
+ let token = this.readToken();
129
+
130
+ while ( token ) {
131
+
132
+ this.tokens.push( token );
133
+
134
+ token = this.readToken();
135
+
136
+ }
137
+
138
+ return this;
139
+
140
+ }
141
+
142
+ skip( ...params ) {
143
+
144
+ let remainingCode = this.source.substr( this.position );
145
+ let i = params.length;
146
+
147
+ while ( i -- ) {
148
+
149
+ const skip = params[ i ].exec( remainingCode );
150
+ const skipLength = skip ? skip[ 0 ].length : 0;
151
+
152
+ if ( skipLength > 0 ) {
153
+
154
+ this.position += skipLength;
155
+
156
+ remainingCode = this.source.substr( this.position );
157
+
158
+ // re-skip, new remainingCode is generated
159
+ // maybe exist previous regexp non detected
160
+ i = params.length;
161
+
162
+ }
163
+
164
+ }
165
+
166
+ return remainingCode;
167
+
168
+ }
169
+
170
+ readToken() {
171
+
172
+ const remainingCode = this.skip( spaceRegExp );
173
+
174
+ for ( var i = 0; i < TokenParserList.length; i ++ ) {
175
+
176
+ const parser = TokenParserList[ i ];
177
+ const result = parser.regexp.exec( remainingCode );
178
+
179
+ if ( result ) {
180
+
181
+ const token = new Token( this, parser.type, result[ parser.group || 0 ], this.position );
182
+
183
+ this.position += token.str.length;
184
+
185
+ if ( parser.isTag ) {
186
+
187
+ const nextToken = this.readToken();
188
+
189
+ if ( nextToken ) {
190
+
191
+ nextToken.tag = token;
192
+
193
+ }
194
+
195
+ return nextToken;
196
+
197
+ }
198
+
199
+ return token;
200
+
201
+ }
202
+
203
+ }
204
+
205
+ }
206
+
207
+ }
208
+
209
+ const isType = ( str ) => /void|bool|float|u?int|(u|i)?vec[234]/.test( str );
210
+
211
+ class GLSLDecoder {
212
+
213
+ constructor() {
214
+
215
+ this.index = 0;
216
+ this.tokenizer = null;
217
+ this.keywords = [];
218
+
219
+ this._currentFunction = null;
220
+
221
+ this.addKeyword( 'gl_FragCoord', 'vec2 gl_FragCoord = vec2( viewportCoordinate.x, viewportCoordinate.y.oneMinus() );' );
222
+
223
+ }
224
+
225
+ addKeyword( name, polyfill ) {
226
+
227
+ this.keywords.push( { name, polyfill } );
228
+
229
+ return this;
230
+
231
+ }
232
+
233
+ get tokens() {
234
+
235
+ return this.tokenizer.tokens;
236
+
237
+ }
238
+
239
+ readToken() {
240
+
241
+ return this.tokens[ this.index ++ ];
242
+
243
+ }
244
+
245
+ getToken( offset = 0 ) {
246
+
247
+ return this.tokens[ this.index + offset ];
248
+
249
+ }
250
+
251
+ getTokensUntil( str, tokens, offset = 0 ) {
252
+
253
+ const output = [];
254
+
255
+ let groupIndex = 0;
256
+
257
+ for ( let i = offset; i < tokens.length; i ++ ) {
258
+
259
+ const token = tokens[ i ];
260
+
261
+ groupIndex += getGroupDelta( token.str );
262
+
263
+ output.push( token );
264
+
265
+ if ( groupIndex === 0 && token.str === str ) {
266
+
267
+ break;
268
+
269
+ }
270
+
271
+ }
272
+
273
+ return output;
274
+
275
+ }
276
+
277
+ readTokensUntil( str ) {
278
+
279
+ const tokens = this.getTokensUntil( str, this.tokens, this.index );
280
+
281
+ this.index += tokens.length;
282
+
283
+ return tokens;
284
+
285
+ }
286
+
287
+ parseExpressionFromTokens( tokens ) {
288
+
289
+ if ( tokens.length === 0 ) return null;
290
+
291
+ const firstToken = tokens[ 0 ];
292
+ const lastToken = tokens[ tokens.length - 1 ];
293
+
294
+ // precedence operators
295
+
296
+ let groupIndex = 0;
297
+
298
+ for ( const operator of precedenceOperators ) {
299
+
300
+ for ( let i = 0; i < tokens.length; i ++ ) {
301
+
302
+ const token = tokens[ i ];
303
+
304
+ groupIndex += getGroupDelta( token.str );
305
+
306
+ if ( ! token.isOperator || i === 0 || i === tokens.length - 1 ) continue;
307
+
308
+ if ( groupIndex === 0 && token.str === operator ) {
309
+
310
+ if ( operator === '?' ) {
311
+
312
+ const conditionTokens = tokens.slice( 0, i );
313
+ const leftTokens = this.getTokensUntil( ':', tokens, i + 1 ).slice( 0, - 1 );
314
+ const rightTokens = tokens.slice( i + leftTokens.length + 2 );
315
+
316
+ const condition = this.parseExpressionFromTokens( conditionTokens );
317
+ const left = this.parseExpressionFromTokens( leftTokens );
318
+ const right = this.parseExpressionFromTokens( rightTokens );
319
+
320
+ return new Ternary( condition, left, right );
321
+
322
+ } else {
323
+
324
+ const left = this.parseExpressionFromTokens( tokens.slice( 0, i ) );
325
+ const right = this.parseExpressionFromTokens( tokens.slice( i + 1, tokens.length ) );
326
+
327
+ return this._evalOperator( new Operator( operator, left, right ) );
328
+
329
+ }
330
+
331
+ }
332
+
333
+ if ( groupIndex < 0 ) {
334
+
335
+ return this.parseExpressionFromTokens( tokens.slice( 0, i ) );
336
+
337
+ }
338
+
339
+ }
340
+
341
+ }
342
+
343
+ // unary operators (before)
344
+
345
+ if ( firstToken.isOperator ) {
346
+
347
+ for ( const operator of unaryOperators ) {
348
+
349
+ if ( firstToken.str === operator ) {
350
+
351
+ const right = this.parseExpressionFromTokens( tokens.slice( 1 ) );
352
+
353
+ return new Unary( operator, right );
354
+
355
+ }
356
+
357
+ }
358
+
359
+ }
360
+
361
+
362
+ // unary operators (after)
363
+
364
+ if ( lastToken.isOperator ) {
365
+
366
+ for ( const operator of unaryOperators ) {
367
+
368
+ if ( lastToken.str === operator ) {
369
+
370
+ const left = this.parseExpressionFromTokens( tokens.slice( 0, tokens.length - 1 ) );
371
+
372
+ return new Unary( operator, left, true );
373
+
374
+ }
375
+
376
+ }
377
+
378
+ }
379
+
380
+ // groups
381
+
382
+ if ( firstToken.str === '(' ) {
383
+
384
+ const leftTokens = this.getTokensUntil( ')', tokens );
385
+
386
+ const left = this.parseExpressionFromTokens( leftTokens.slice( 1, leftTokens.length - 1 ) );
387
+
388
+ const operator = tokens[ leftTokens.length ];
389
+
390
+ if ( operator ) {
391
+
392
+ const rightTokens = tokens.slice( leftTokens.length + 1 );
393
+ const right = this.parseExpressionFromTokens( rightTokens );
394
+
395
+ return this._evalOperator( new Operator( operator.str, left, right ) );
396
+
397
+ }
398
+
399
+ return left;
400
+
401
+ }
402
+
403
+ // primitives and accessors
404
+
405
+ if ( firstToken.isNumber ) {
406
+
407
+ let type;
408
+
409
+ if ( /^(0x)/.test( firstToken.str ) ) type = 'int';
410
+ else if ( /u$/.test( firstToken.str ) ) type = 'uint';
411
+ else if ( /f|e|\./.test( firstToken.str ) ) type = 'float';
412
+ else type = 'int';
413
+
414
+ const str = firstToken.str.replace( /u$/, '' );
415
+
416
+ return new Number( str, type );
417
+
418
+ } else if ( firstToken.isLiteral ) {
419
+
420
+ if ( firstToken.str === 'return' ) {
421
+
422
+ return new Return( this.parseExpressionFromTokens( tokens.slice( 1 ) ) );
423
+
424
+ }
425
+
426
+ const secondToken = tokens[ 1 ];
427
+
428
+ if ( secondToken ) {
429
+
430
+ if ( secondToken.str === '(' ) {
431
+
432
+ // function call
433
+
434
+ const paramsTokens = this.parseFunctionParametersFromTokens( tokens.slice( 2, tokens.length - 1 ) );
435
+
436
+ return new FunctionCall( firstToken.str, paramsTokens );
437
+
438
+ } else if ( secondToken.str === '[' ) {
439
+
440
+ // array accessor
441
+
442
+ const elements = [];
443
+
444
+ let currentTokens = tokens.slice( 1 );
445
+
446
+ while ( currentTokens.length > 0 ) {
447
+
448
+ const token = currentTokens[ 0 ];
449
+
450
+ if ( token.str === '[' ) {
451
+
452
+ const accessorTokens = this.getTokensUntil( ']', currentTokens );
453
+
454
+ const element = this.parseExpressionFromTokens( accessorTokens.slice( 1, accessorTokens.length - 1 ) );
455
+
456
+ currentTokens = currentTokens.slice( accessorTokens.length );
457
+
458
+ elements.push( new DynamicElement( element ) );
459
+
460
+ } else if ( token.str === '.' ) {
461
+
462
+ const accessorTokens = currentTokens.slice( 1, 2 );
463
+
464
+ const element = this.parseExpressionFromTokens( accessorTokens );
465
+
466
+ currentTokens = currentTokens.slice( 2 );
467
+
468
+ elements.push( new StaticElement( element ) );
469
+
470
+ } else {
471
+
472
+ console.error( 'Unknown accessor expression', token );
473
+
474
+ break;
475
+
476
+ }
477
+
478
+ }
479
+
480
+ return new AccessorElements( firstToken.str, elements );
481
+
482
+ }
483
+
484
+ }
485
+
486
+ return new Accessor( firstToken.str );
487
+
488
+ }
489
+
490
+ }
491
+
492
+ parseFunctionParametersFromTokens( tokens ) {
493
+
494
+ if ( tokens.length === 0 ) return [];
495
+
496
+ const expression = this.parseExpressionFromTokens( tokens );
497
+ const params = [];
498
+
499
+ let current = expression;
500
+
501
+ while ( current.type === ',' ) {
502
+
503
+ params.push( current.left );
504
+
505
+ current = current.right;
506
+
507
+ }
508
+
509
+ params.push( current );
510
+
511
+ return params;
512
+
513
+ }
514
+
515
+ parseExpression() {
516
+
517
+ const tokens = this.readTokensUntil( ';' );
518
+
519
+ const exp = this.parseExpressionFromTokens( tokens.slice( 0, tokens.length - 1 ) );
520
+
521
+ return exp;
522
+
523
+ }
524
+
525
+ parseFunctionParams( tokens ) {
526
+
527
+ const params = [];
528
+
529
+ for ( let i = 0; i < tokens.length; i ++ ) {
530
+
531
+ const immutable = tokens[ i ].str === 'const';
532
+ if ( immutable ) i ++;
533
+
534
+ let qualifier = tokens[ i ].str;
535
+
536
+ if ( /^(in|out|inout)$/.test( qualifier ) ) {
537
+
538
+ i ++;
539
+
540
+ } else {
541
+
542
+ qualifier = null;
543
+
544
+ }
545
+
546
+ const type = tokens[ i ++ ].str;
547
+ const name = tokens[ i ++ ].str;
548
+
549
+ params.push( new FunctionParameter( type, name, qualifier, immutable ) );
550
+
551
+ if ( tokens[ i ] && tokens[ i ].str !== ',' ) throw new Error( 'Expected ","' );
552
+
553
+ }
554
+
555
+ return params;
556
+
557
+ }
558
+
559
+ parseFunction() {
560
+
561
+ const type = this.readToken().str;
562
+ const name = this.readToken().str;
563
+
564
+ const paramsTokens = this.readTokensUntil( ')' );
565
+
566
+ const params = this.parseFunctionParams( paramsTokens.slice( 1, paramsTokens.length - 1 ) );
567
+
568
+ const func = new FunctionDeclaration( type, name, params );
569
+
570
+ this._currentFunction = func;
571
+
572
+ this.parseBlock( func );
573
+
574
+ this._currentFunction = null;
575
+
576
+ return func;
577
+
578
+ }
579
+
580
+ parseVariablesFromToken( tokens, type ) {
581
+
582
+ let index = 0;
583
+ const immutable = tokens[ 0 ].str === 'const';
584
+
585
+ if ( immutable ) index ++;
586
+
587
+ type = type || tokens[ index ++ ].str;
588
+ const name = tokens[ index ++ ].str;
589
+
590
+ const token = tokens[ index ];
591
+
592
+ let init = null;
593
+ let next = null;
594
+
595
+ if ( token ) {
596
+
597
+ const initTokens = this.getTokensUntil( ',', tokens, index );
598
+
599
+ if ( initTokens[ 0 ].str === '=' ) {
600
+
601
+ const expressionTokens = initTokens.slice( 1 );
602
+ if ( expressionTokens[ expressionTokens.length - 1 ].str === ',' ) expressionTokens.pop();
603
+
604
+ init = this.parseExpressionFromTokens( expressionTokens );
605
+
606
+ }
607
+
608
+ const nextTokens = tokens.slice( initTokens.length + ( index - 1 ) );
609
+
610
+ if ( nextTokens[ 0 ] && nextTokens[ 0 ].str === ',' ) {
611
+
612
+ next = this.parseVariablesFromToken( nextTokens.slice( 1 ), type );
613
+
614
+ }
615
+
616
+ }
617
+
618
+ const variable = new VariableDeclaration( type, name, init, next, immutable );
619
+
620
+ return variable;
621
+
622
+ }
623
+
624
+ parseVariables() {
625
+
626
+ const tokens = this.readTokensUntil( ';' );
627
+
628
+ return this.parseVariablesFromToken( tokens.slice( 0, tokens.length - 1 ) );
629
+
630
+ }
631
+
632
+ parseReturn() {
633
+
634
+ this.readToken(); // skip 'return'
635
+
636
+ const expression = this.parseExpression();
637
+
638
+ return new Return( expression );
639
+
640
+ }
641
+
642
+ parseFor() {
643
+
644
+ this.readToken(); // skip 'for'
645
+
646
+ const forTokens = this.readTokensUntil( ')' ).slice( 1, - 1 );
647
+
648
+ const initializationTokens = this.getTokensUntil( ';', forTokens, 0 ).slice( 0, - 1 );
649
+ const conditionTokens = this.getTokensUntil( ';', forTokens, initializationTokens.length + 1 ).slice( 0, - 1 );
650
+ const afterthoughtTokens = forTokens.slice( initializationTokens.length + conditionTokens.length + 2 );
651
+
652
+ let initialization;
653
+
654
+ if ( initializationTokens[ 0 ] && isType( initializationTokens[ 0 ].str ) ) {
655
+
656
+ initialization = this.parseVariablesFromToken( initializationTokens );
657
+
658
+ } else {
659
+
660
+ initialization = this.parseExpressionFromTokens( initializationTokens );
661
+
662
+ }
663
+
664
+ const condition = this.parseExpressionFromTokens( conditionTokens );
665
+ const afterthought = this.parseExpressionFromTokens( afterthoughtTokens );
666
+
667
+ const statement = new For( initialization, condition, afterthought );
668
+
669
+ if ( this.getToken().str === '{' ) {
670
+
671
+ this.parseBlock( statement );
672
+
673
+ } else {
674
+
675
+ statement.body.push( this.parseExpression() );
676
+
677
+ }
678
+
679
+ return statement;
680
+
681
+ }
682
+
683
+ parseIf() {
684
+
685
+ const parseIfExpression = () => {
686
+
687
+ this.readToken(); // skip 'if'
688
+
689
+ const condTokens = this.readTokensUntil( ')' );
690
+
691
+ return this.parseExpressionFromTokens( condTokens.slice( 1, condTokens.length - 1 ) );
692
+
693
+ };
694
+
695
+ const parseIfBlock = ( cond ) => {
696
+
697
+ if ( this.getToken().str === '{' ) {
698
+
699
+ this.parseBlock( cond );
700
+
701
+ } else {
702
+
703
+ cond.body.push( this.parseExpression() );
704
+
705
+ }
706
+
707
+ };
708
+
709
+ //
710
+
711
+ const conditional = new Conditional( parseIfExpression() );
712
+
713
+ parseIfBlock( conditional );
714
+
715
+ //
716
+
717
+ let current = conditional;
718
+
719
+ while ( this.getToken().str === 'else' ) {
720
+
721
+ this.readToken(); // skip 'else'
722
+
723
+ const previous = current;
724
+
725
+ if ( this.getToken().str === 'if' ) {
726
+
727
+ current = new Conditional( parseIfExpression() );
728
+
729
+ } else {
730
+
731
+ current = new Conditional();
732
+
733
+ }
734
+
735
+ previous.elseConditional = current;
736
+
737
+ parseIfBlock( current );
738
+
739
+ }
740
+
741
+ return conditional;
742
+
743
+ }
744
+
745
+ parseBlock( scope ) {
746
+
747
+ const firstToken = this.getToken();
748
+
749
+ if ( firstToken.str === '{' ) {
750
+
751
+ this.readToken(); // skip '{'
752
+
753
+ }
754
+
755
+ let groupIndex = 0;
756
+
757
+ while ( this.index < this.tokens.length ) {
758
+
759
+ const token = this.getToken();
760
+
761
+ let statement = null;
762
+
763
+ groupIndex += getGroupDelta( token.str );
764
+
765
+ if ( groupIndex < 0 ) {
766
+
767
+ this.readToken(); // skip '}'
768
+
769
+ break;
770
+
771
+ }
772
+
773
+ //
774
+
775
+ if ( token.isLiteral ) {
776
+
777
+ if ( token.str === 'const' ) {
778
+
779
+ statement = this.parseVariables();
780
+
781
+ } else if ( isType( token.str ) ) {
782
+
783
+ if ( this.getToken( 2 ).str === '(' ) {
784
+
785
+ statement = this.parseFunction();
786
+
787
+ } else {
788
+
789
+ statement = this.parseVariables();
790
+
791
+ }
792
+
793
+ } else if ( token.str === 'return' ) {
794
+
795
+ statement = this.parseReturn();
796
+
797
+ } else if ( token.str === 'if' ) {
798
+
799
+ statement = this.parseIf();
800
+
801
+ } else if ( token.str === 'for' ) {
802
+
803
+ statement = this.parseFor();
804
+
805
+ } else {
806
+
807
+ statement = this.parseExpression();
808
+
809
+ }
810
+
811
+ }
812
+
813
+ if ( statement ) {
814
+
815
+ scope.body.push( statement );
816
+
817
+ } else {
818
+
819
+ this.index ++;
820
+
821
+ }
822
+
823
+ }
824
+
825
+ }
826
+
827
+ _evalOperator( operator ) {
828
+
829
+ if ( operator.type.includes( '=' ) ) {
830
+
831
+ const parameter = this._getFunctionParameter( operator.left.property );
832
+
833
+ if ( parameter !== undefined ) {
834
+
835
+ // Parameters are immutable in WGSL
836
+
837
+ parameter.immutable = false;
838
+
839
+ }
840
+
841
+ }
842
+
843
+ return operator;
844
+
845
+ }
846
+
847
+ _getFunctionParameter( name ) {
848
+
849
+ if ( this._currentFunction ) {
850
+
851
+ for ( const param of this._currentFunction.params ) {
852
+
853
+ if ( param.name === name ) {
854
+
855
+ return param;
856
+
857
+ }
858
+
859
+ }
860
+
861
+ }
862
+
863
+ }
864
+
865
+ parse( source ) {
866
+
867
+ let polyfill = '';
868
+
869
+ for ( const keyword of this.keywords ) {
870
+
871
+ if ( new RegExp( `(^|\\b)${ keyword.name }($|\\b)`, 'gm' ).test( source ) ) {
872
+
873
+ polyfill += keyword.polyfill + '\n';
874
+
875
+ }
876
+
877
+ }
878
+
879
+ if ( polyfill ) {
880
+
881
+ polyfill = '// Polyfills\n\n' + polyfill + '\n';
882
+
883
+ }
884
+
885
+ this.index = 0;
886
+ this.tokenizer = new Tokenizer( polyfill + source ).tokenize();
887
+
888
+ const program = new Program();
889
+
890
+ this.parseBlock( program );
891
+
892
+ return program;
893
+
894
+
895
+ }
896
+
897
+ }
898
+
899
+ export default GLSLDecoder;