@luma.gl/shadertools 9.3.6 → 9.4.0-alpha.1

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 (113) hide show
  1. package/dist/dist.dev.js +6555 -2373
  2. package/dist/dist.min.js +2984 -237
  3. package/dist/index.cjs +4356 -268
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +13 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/preprocessor/preprocessor.d.ts +11 -1
  10. package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
  11. package/dist/lib/preprocessor/preprocessor.js +47 -2
  12. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  13. package/dist/lib/shader-assembler.d.ts +10 -10
  14. package/dist/lib/shader-assembler.d.ts.map +1 -1
  15. package/dist/lib/shader-assembler.js +36 -20
  16. package/dist/lib/shader-assembler.js.map +1 -1
  17. package/dist/lib/shader-assembly/assemble-shaders.d.ts +28 -7
  18. package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
  19. package/dist/lib/shader-assembly/assemble-shaders.js +133 -15
  20. package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
  21. package/dist/lib/shader-assembly/platform-info.d.ts +2 -0
  22. package/dist/lib/shader-assembly/platform-info.d.ts.map +1 -1
  23. package/dist/lib/shader-assembly/shader-hooks.d.ts +1 -1
  24. package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
  25. package/dist/lib/shader-assembly/shader-hooks.js +6 -3
  26. package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
  27. package/dist/lib/shader-assembly/shader-injections.d.ts +4 -1
  28. package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
  29. package/dist/lib/shader-assembly/shader-injections.js +68 -11
  30. package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
  31. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +15 -0
  32. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -0
  33. package/dist/lib/shader-assembly/shader-plugin-varyings.js +412 -0
  34. package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -0
  35. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts +12 -0
  36. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts.map +1 -0
  37. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js +237 -0
  38. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js.map +1 -0
  39. package/dist/lib/shader-module/shader-module.d.ts +3 -0
  40. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  41. package/dist/lib/shader-module/shader-module.js.map +1 -1
  42. package/dist/lib/shader-module/shader-pass-pipeline.d.ts +14 -0
  43. package/dist/lib/shader-module/shader-pass-pipeline.d.ts.map +1 -0
  44. package/dist/lib/shader-module/shader-pass-pipeline.js +5 -0
  45. package/dist/lib/shader-module/shader-pass-pipeline.js.map +1 -0
  46. package/dist/lib/shader-module/shader-pass.d.ts +21 -4
  47. package/dist/lib/shader-module/shader-pass.d.ts.map +1 -1
  48. package/dist/lib/shader-plugin.d.ts +68 -0
  49. package/dist/lib/shader-plugin.d.ts.map +1 -0
  50. package/dist/lib/shader-plugin.js +98 -0
  51. package/dist/lib/shader-plugin.js.map +1 -0
  52. package/dist/lib/utils/assert.js +1 -1
  53. package/dist/lib/utils/assert.js.map +1 -1
  54. package/dist/modules/color/float-colors.d.ts +111 -5
  55. package/dist/modules/color/float-colors.d.ts.map +1 -1
  56. package/dist/modules/color/float-colors.js +200 -34
  57. package/dist/modules/color/float-colors.js.map +1 -1
  58. package/dist/modules/engine/clip/clip.d.ts +12 -0
  59. package/dist/modules/engine/clip/clip.d.ts.map +1 -0
  60. package/dist/modules/engine/clip/clip.js +129 -0
  61. package/dist/modules/engine/clip/clip.js.map +1 -0
  62. package/dist/modules/engine/filter/filter.d.ts +12 -0
  63. package/dist/modules/engine/filter/filter.d.ts.map +1 -0
  64. package/dist/modules/engine/filter/filter.js +88 -0
  65. package/dist/modules/engine/filter/filter.js.map +1 -0
  66. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts +3 -0
  67. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts.map +1 -0
  68. package/dist/modules/geospatial/dggs/dggs-wgsl.js +1892 -0
  69. package/dist/modules/geospatial/dggs/dggs-wgsl.js.map +1 -0
  70. package/dist/modules/geospatial/dggs/dggs.d.ts +6 -0
  71. package/dist/modules/geospatial/dggs/dggs.d.ts.map +1 -0
  72. package/dist/modules/geospatial/dggs/dggs.js +10 -0
  73. package/dist/modules/geospatial/dggs/dggs.js.map +1 -0
  74. package/dist/modules/lighting/water-material/water-material.d.ts +28 -0
  75. package/dist/modules/lighting/water-material/water-material.d.ts.map +1 -0
  76. package/dist/modules/lighting/water-material/water-material.js +179 -0
  77. package/dist/modules/lighting/water-material/water-material.js.map +1 -0
  78. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts +3 -0
  79. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts.map +1 -0
  80. package/dist/modules/lighting/water-material/water-shaders-glsl.js +232 -0
  81. package/dist/modules/lighting/water-material/water-shaders-glsl.js.map +1 -0
  82. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts +2 -0
  83. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts.map +1 -0
  84. package/dist/modules/lighting/water-material/water-shaders-wgsl.js +230 -0
  85. package/dist/modules/lighting/water-material/water-shaders-wgsl.js.map +1 -0
  86. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -1
  87. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -1
  88. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +268 -0
  89. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -1
  90. package/package.json +2 -2
  91. package/src/index.ts +50 -3
  92. package/src/lib/preprocessor/preprocessor.ts +68 -3
  93. package/src/lib/shader-assembler.ts +49 -20
  94. package/src/lib/shader-assembly/assemble-shaders.ts +242 -30
  95. package/src/lib/shader-assembly/platform-info.ts +2 -0
  96. package/src/lib/shader-assembly/shader-hooks.ts +7 -3
  97. package/src/lib/shader-assembly/shader-injections.ts +96 -11
  98. package/src/lib/shader-assembly/shader-plugin-varyings.ts +524 -0
  99. package/src/lib/shader-assembly/shader-plugin-vertex-inputs.ts +279 -0
  100. package/src/lib/shader-module/shader-module.ts +3 -0
  101. package/src/lib/shader-module/shader-pass-pipeline.ts +19 -0
  102. package/src/lib/shader-module/shader-pass.ts +29 -4
  103. package/src/lib/shader-plugin.ts +214 -0
  104. package/src/lib/utils/assert.ts +1 -1
  105. package/src/modules/color/float-colors.ts +272 -37
  106. package/src/modules/engine/clip/clip.ts +149 -0
  107. package/src/modules/engine/filter/filter.ts +107 -0
  108. package/src/modules/geospatial/dggs/dggs-wgsl.ts +1892 -0
  109. package/src/modules/geospatial/dggs/dggs.ts +12 -0
  110. package/src/modules/lighting/water-material/water-material.ts +234 -0
  111. package/src/modules/lighting/water-material/water-shaders-glsl.ts +233 -0
  112. package/src/modules/lighting/water-material/water-shaders-wgsl.ts +230 -0
  113. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +268 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"water-shaders-glsl.js","sourceRoot":"","sources":["../../../../src/modules/lighting/water-material/water-shaders-glsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAEpC,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBlC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6MlC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const WATER_WGSL = "struct waterMaterialUniforms {\n time: f32,\n baseColor: vec3<f32>,\n opacity: f32,\n fresnelColor: vec3<f32>,\n fresnelPower: f32,\n specularIntensity: f32,\n normalStrength: f32,\n mappingMode: i32,\n coordinateScale: vec2<f32>,\n coordinateOffset: vec2<f32>,\n waveADirection: vec2<f32>,\n waveASpeed: f32,\n waveAFrequency: f32,\n waveAAmplitude: f32,\n waveBDirection: vec2<f32>,\n waveBSpeed: f32,\n waveBFrequency: f32,\n waveBAmplitude: f32,\n};\n\n@group(3) @binding(auto) var<uniform> waterMaterial : waterMaterialUniforms;\n\nfn water_getDirection(direction: vec2<f32>) -> vec2<f32> {\n let directionLength = length(direction);\n if (directionLength > 0.0) {\n return direction / directionLength;\n }\n\n return vec2<f32>(1.0, 0.0);\n}\n\nfn water_getCoordinates(\n position_worldspace: vec3<f32>,\n position_objectspace: vec3<f32>,\n uv: vec2<f32>\n) -> vec2<f32> {\n var baseCoordinates = uv;\n if (waterMaterial.mappingMode == 1) {\n baseCoordinates = position_worldspace.xz;\n } else if (waterMaterial.mappingMode == 2) {\n let globeDirection = normalize(position_objectspace);\n let longitude = atan2(globeDirection.x, globeDirection.z);\n let latitude = asin(clamp(globeDirection.y, -1.0, 1.0));\n baseCoordinates = vec2<f32>(longitude, latitude);\n }\n\n return baseCoordinates * waterMaterial.coordinateScale + waterMaterial.coordinateOffset;\n}\n\nfn water_getWaveGradient(\n coordinates: vec2<f32>,\n direction: vec2<f32>,\n speed: f32,\n frequency: f32,\n amplitude: f32\n) -> vec2<f32> {\n let normalizedDirection = water_getDirection(direction);\n let phase = dot(coordinates * frequency, normalizedDirection) + waterMaterial.time * speed;\n return cos(phase) * normalizedDirection * frequency * amplitude;\n}\n\nfn water_getTangent(normal_worldspace: vec3<f32>) -> vec3<f32> {\n var referenceAxis = vec3<f32>(0.0, 0.0, 1.0);\n if (abs(normal_worldspace.z) >= 0.999) {\n referenceAxis = vec3<f32>(0.0, 1.0, 0.0);\n }\n\n return normalize(cross(referenceAxis, normal_worldspace));\n}\n\nfn water_getNormal(\n position_worldspace: vec3<f32>,\n position_objectspace: vec3<f32>,\n normal_worldspace: vec3<f32>,\n uv: vec2<f32>\n) -> vec3<f32> {\n let coordinates = water_getCoordinates(position_worldspace, position_objectspace, uv);\n let gradient =\n water_getWaveGradient(\n coordinates,\n waterMaterial.waveADirection,\n waterMaterial.waveASpeed,\n waterMaterial.waveAFrequency,\n waterMaterial.waveAAmplitude\n ) +\n water_getWaveGradient(\n coordinates,\n waterMaterial.waveBDirection,\n waterMaterial.waveBSpeed,\n waterMaterial.waveBFrequency,\n waterMaterial.waveBAmplitude\n );\n let tangent = water_getTangent(normal_worldspace);\n let bitangent = normalize(cross(normal_worldspace, tangent));\n let perturbation =\n waterMaterial.normalStrength * (gradient.x * tangent + gradient.y * bitangent);\n\n return normalize(normal_worldspace + perturbation);\n}\n\nfn water_getSpecularContribution(\n light_direction: vec3<f32>,\n view_direction: vec3<f32>,\n normal_worldspace: vec3<f32>,\n light_color: vec3<f32>,\n fresnel: f32\n) -> vec3<f32> {\n let halfwayDirection = normalize(light_direction + view_direction);\n let specular =\n pow(max(dot(normal_worldspace, halfwayDirection), 0.0), 72.0) *\n waterMaterial.specularIntensity *\n (0.25 + 0.75 * fresnel);\n\n return waterMaterial.fresnelColor * light_color * specular;\n}\n\nfn water_getColorMapped(\n cameraPosition: vec3<f32>,\n position_worldspace: vec3<f32>,\n position_objectspace: vec3<f32>,\n normal_worldspace: vec3<f32>,\n uv: vec2<f32>\n) -> vec4<f32> {\n let waterNormal = water_getNormal(\n position_worldspace,\n position_objectspace,\n normalize(normal_worldspace),\n uv\n );\n let viewDirection = normalize(cameraPosition - position_worldspace);\n let fresnel =\n pow(\n 1.0 - max(dot(viewDirection, waterNormal), 0.0),\n max(waterMaterial.fresnelPower, 0.0001)\n );\n let surfaceColor = mix(\n waterMaterial.baseColor,\n waterMaterial.fresnelColor,\n clamp(fresnel * 0.6, 0.0, 1.0)\n );\n\n if (lighting.enabled == 0) {\n return vec4<f32>(surfaceColor, waterMaterial.opacity);\n }\n\n var lightColor = surfaceColor * (0.15 + 0.85 * lighting.ambientColor);\n\n for (var i: i32 = 0; i < lighting.pointLightCount; i++) {\n let pointLight = lighting_getPointLight(i);\n let lightPosition = pointLight.position;\n let lightDirection = normalize(lightPosition - position_worldspace);\n let attenuation = getPointLightAttenuation(\n pointLight,\n distance(lightPosition, position_worldspace)\n );\n let incidentLight = pointLight.color / attenuation;\n let diffuse = max(dot(waterNormal, lightDirection), 0.0);\n\n lightColor += surfaceColor * incidentLight * diffuse;\n lightColor += water_getSpecularContribution(\n lightDirection,\n viewDirection,\n waterNormal,\n incidentLight,\n fresnel\n );\n }\n\n for (var i: i32 = 0; i < lighting.spotLightCount; i++) {\n let spotLight = lighting_getSpotLight(i);\n let lightPosition = spotLight.position;\n let lightDirection = normalize(lightPosition - position_worldspace);\n let attenuation = getSpotLightAttenuation(spotLight, position_worldspace);\n let incidentLight = spotLight.color / attenuation;\n let diffuse = max(dot(waterNormal, lightDirection), 0.0);\n\n lightColor += surfaceColor * incidentLight * diffuse;\n lightColor += water_getSpecularContribution(\n lightDirection,\n viewDirection,\n waterNormal,\n incidentLight,\n fresnel\n );\n }\n\n for (var i: i32 = 0; i < lighting.directionalLightCount; i++) {\n let directionalLight = lighting_getDirectionalLight(i);\n let lightDirection = normalize(-directionalLight.direction);\n let diffuse = max(dot(waterNormal, lightDirection), 0.0);\n\n lightColor += surfaceColor * directionalLight.color * diffuse;\n lightColor += water_getSpecularContribution(\n lightDirection,\n viewDirection,\n waterNormal,\n directionalLight.color,\n fresnel\n );\n }\n\n lightColor = mix(\n lightColor,\n waterMaterial.fresnelColor,\n clamp(fresnel, 0.0, 1.0) * 0.35\n );\n return vec4<f32>(lightColor, waterMaterial.opacity);\n}\n\nfn water_getColor(\n cameraPosition: vec3<f32>,\n position_worldspace: vec3<f32>,\n normal_worldspace: vec3<f32>,\n uv: vec2<f32>\n) -> vec4<f32> {\n return water_getColorMapped(\n cameraPosition,\n position_worldspace,\n position_worldspace,\n normal_worldspace,\n uv\n );\n}\n";
2
+ //# sourceMappingURL=water-shaders-wgsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"water-shaders-wgsl.d.ts","sourceRoot":"","sources":["../../../../src/modules/lighting/water-material/water-shaders-wgsl.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,sjNAiOtB,CAAC"}
@@ -0,0 +1,230 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ export const WATER_WGSL = /* wgsl */ `\
5
+ struct waterMaterialUniforms {
6
+ time: f32,
7
+ baseColor: vec3<f32>,
8
+ opacity: f32,
9
+ fresnelColor: vec3<f32>,
10
+ fresnelPower: f32,
11
+ specularIntensity: f32,
12
+ normalStrength: f32,
13
+ mappingMode: i32,
14
+ coordinateScale: vec2<f32>,
15
+ coordinateOffset: vec2<f32>,
16
+ waveADirection: vec2<f32>,
17
+ waveASpeed: f32,
18
+ waveAFrequency: f32,
19
+ waveAAmplitude: f32,
20
+ waveBDirection: vec2<f32>,
21
+ waveBSpeed: f32,
22
+ waveBFrequency: f32,
23
+ waveBAmplitude: f32,
24
+ };
25
+
26
+ @group(3) @binding(auto) var<uniform> waterMaterial : waterMaterialUniforms;
27
+
28
+ fn water_getDirection(direction: vec2<f32>) -> vec2<f32> {
29
+ let directionLength = length(direction);
30
+ if (directionLength > 0.0) {
31
+ return direction / directionLength;
32
+ }
33
+
34
+ return vec2<f32>(1.0, 0.0);
35
+ }
36
+
37
+ fn water_getCoordinates(
38
+ position_worldspace: vec3<f32>,
39
+ position_objectspace: vec3<f32>,
40
+ uv: vec2<f32>
41
+ ) -> vec2<f32> {
42
+ var baseCoordinates = uv;
43
+ if (waterMaterial.mappingMode == 1) {
44
+ baseCoordinates = position_worldspace.xz;
45
+ } else if (waterMaterial.mappingMode == 2) {
46
+ let globeDirection = normalize(position_objectspace);
47
+ let longitude = atan2(globeDirection.x, globeDirection.z);
48
+ let latitude = asin(clamp(globeDirection.y, -1.0, 1.0));
49
+ baseCoordinates = vec2<f32>(longitude, latitude);
50
+ }
51
+
52
+ return baseCoordinates * waterMaterial.coordinateScale + waterMaterial.coordinateOffset;
53
+ }
54
+
55
+ fn water_getWaveGradient(
56
+ coordinates: vec2<f32>,
57
+ direction: vec2<f32>,
58
+ speed: f32,
59
+ frequency: f32,
60
+ amplitude: f32
61
+ ) -> vec2<f32> {
62
+ let normalizedDirection = water_getDirection(direction);
63
+ let phase = dot(coordinates * frequency, normalizedDirection) + waterMaterial.time * speed;
64
+ return cos(phase) * normalizedDirection * frequency * amplitude;
65
+ }
66
+
67
+ fn water_getTangent(normal_worldspace: vec3<f32>) -> vec3<f32> {
68
+ var referenceAxis = vec3<f32>(0.0, 0.0, 1.0);
69
+ if (abs(normal_worldspace.z) >= 0.999) {
70
+ referenceAxis = vec3<f32>(0.0, 1.0, 0.0);
71
+ }
72
+
73
+ return normalize(cross(referenceAxis, normal_worldspace));
74
+ }
75
+
76
+ fn water_getNormal(
77
+ position_worldspace: vec3<f32>,
78
+ position_objectspace: vec3<f32>,
79
+ normal_worldspace: vec3<f32>,
80
+ uv: vec2<f32>
81
+ ) -> vec3<f32> {
82
+ let coordinates = water_getCoordinates(position_worldspace, position_objectspace, uv);
83
+ let gradient =
84
+ water_getWaveGradient(
85
+ coordinates,
86
+ waterMaterial.waveADirection,
87
+ waterMaterial.waveASpeed,
88
+ waterMaterial.waveAFrequency,
89
+ waterMaterial.waveAAmplitude
90
+ ) +
91
+ water_getWaveGradient(
92
+ coordinates,
93
+ waterMaterial.waveBDirection,
94
+ waterMaterial.waveBSpeed,
95
+ waterMaterial.waveBFrequency,
96
+ waterMaterial.waveBAmplitude
97
+ );
98
+ let tangent = water_getTangent(normal_worldspace);
99
+ let bitangent = normalize(cross(normal_worldspace, tangent));
100
+ let perturbation =
101
+ waterMaterial.normalStrength * (gradient.x * tangent + gradient.y * bitangent);
102
+
103
+ return normalize(normal_worldspace + perturbation);
104
+ }
105
+
106
+ fn water_getSpecularContribution(
107
+ light_direction: vec3<f32>,
108
+ view_direction: vec3<f32>,
109
+ normal_worldspace: vec3<f32>,
110
+ light_color: vec3<f32>,
111
+ fresnel: f32
112
+ ) -> vec3<f32> {
113
+ let halfwayDirection = normalize(light_direction + view_direction);
114
+ let specular =
115
+ pow(max(dot(normal_worldspace, halfwayDirection), 0.0), 72.0) *
116
+ waterMaterial.specularIntensity *
117
+ (0.25 + 0.75 * fresnel);
118
+
119
+ return waterMaterial.fresnelColor * light_color * specular;
120
+ }
121
+
122
+ fn water_getColorMapped(
123
+ cameraPosition: vec3<f32>,
124
+ position_worldspace: vec3<f32>,
125
+ position_objectspace: vec3<f32>,
126
+ normal_worldspace: vec3<f32>,
127
+ uv: vec2<f32>
128
+ ) -> vec4<f32> {
129
+ let waterNormal = water_getNormal(
130
+ position_worldspace,
131
+ position_objectspace,
132
+ normalize(normal_worldspace),
133
+ uv
134
+ );
135
+ let viewDirection = normalize(cameraPosition - position_worldspace);
136
+ let fresnel =
137
+ pow(
138
+ 1.0 - max(dot(viewDirection, waterNormal), 0.0),
139
+ max(waterMaterial.fresnelPower, 0.0001)
140
+ );
141
+ let surfaceColor = mix(
142
+ waterMaterial.baseColor,
143
+ waterMaterial.fresnelColor,
144
+ clamp(fresnel * 0.6, 0.0, 1.0)
145
+ );
146
+
147
+ if (lighting.enabled == 0) {
148
+ return vec4<f32>(surfaceColor, waterMaterial.opacity);
149
+ }
150
+
151
+ var lightColor = surfaceColor * (0.15 + 0.85 * lighting.ambientColor);
152
+
153
+ for (var i: i32 = 0; i < lighting.pointLightCount; i++) {
154
+ let pointLight = lighting_getPointLight(i);
155
+ let lightPosition = pointLight.position;
156
+ let lightDirection = normalize(lightPosition - position_worldspace);
157
+ let attenuation = getPointLightAttenuation(
158
+ pointLight,
159
+ distance(lightPosition, position_worldspace)
160
+ );
161
+ let incidentLight = pointLight.color / attenuation;
162
+ let diffuse = max(dot(waterNormal, lightDirection), 0.0);
163
+
164
+ lightColor += surfaceColor * incidentLight * diffuse;
165
+ lightColor += water_getSpecularContribution(
166
+ lightDirection,
167
+ viewDirection,
168
+ waterNormal,
169
+ incidentLight,
170
+ fresnel
171
+ );
172
+ }
173
+
174
+ for (var i: i32 = 0; i < lighting.spotLightCount; i++) {
175
+ let spotLight = lighting_getSpotLight(i);
176
+ let lightPosition = spotLight.position;
177
+ let lightDirection = normalize(lightPosition - position_worldspace);
178
+ let attenuation = getSpotLightAttenuation(spotLight, position_worldspace);
179
+ let incidentLight = spotLight.color / attenuation;
180
+ let diffuse = max(dot(waterNormal, lightDirection), 0.0);
181
+
182
+ lightColor += surfaceColor * incidentLight * diffuse;
183
+ lightColor += water_getSpecularContribution(
184
+ lightDirection,
185
+ viewDirection,
186
+ waterNormal,
187
+ incidentLight,
188
+ fresnel
189
+ );
190
+ }
191
+
192
+ for (var i: i32 = 0; i < lighting.directionalLightCount; i++) {
193
+ let directionalLight = lighting_getDirectionalLight(i);
194
+ let lightDirection = normalize(-directionalLight.direction);
195
+ let diffuse = max(dot(waterNormal, lightDirection), 0.0);
196
+
197
+ lightColor += surfaceColor * directionalLight.color * diffuse;
198
+ lightColor += water_getSpecularContribution(
199
+ lightDirection,
200
+ viewDirection,
201
+ waterNormal,
202
+ directionalLight.color,
203
+ fresnel
204
+ );
205
+ }
206
+
207
+ lightColor = mix(
208
+ lightColor,
209
+ waterMaterial.fresnelColor,
210
+ clamp(fresnel, 0.0, 1.0) * 0.35
211
+ );
212
+ return vec4<f32>(lightColor, waterMaterial.opacity);
213
+ }
214
+
215
+ fn water_getColor(
216
+ cameraPosition: vec3<f32>,
217
+ position_worldspace: vec3<f32>,
218
+ normal_worldspace: vec3<f32>,
219
+ uv: vec2<f32>
220
+ ) -> vec4<f32> {
221
+ return water_getColorMapped(
222
+ cameraPosition,
223
+ position_worldspace,
224
+ position_worldspace,
225
+ normal_worldspace,
226
+ uv
227
+ );
228
+ }
229
+ `;
230
+ //# sourceMappingURL=water-shaders-wgsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"water-shaders-wgsl.js","sourceRoot":"","sources":["../../../../src/modules/lighting/water-material/water-shaders-wgsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiOpC,CAAC"}
@@ -1,2 +1,3 @@
1
- export declare const fp64arithmeticWGSL = "struct Fp64ArithmeticUniforms {\n ONE: f32,\n SPLIT: f32,\n};\n\n@group(0) @binding(auto) var<uniform> fp64arithmetic : Fp64ArithmeticUniforms;\n\nfn fp64_nan(seed: f32) -> f32 {\n let nanBits = 0x7fc00000u | select(0u, 1u, seed < 0.0);\n return bitcast<f32>(nanBits);\n}\n\nfn fp64_runtime_zero() -> f32 {\n return fp64arithmetic.ONE * 0.0;\n}\n\nfn prevent_fp64_optimization(value: f32) -> f32 {\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n return value + fp64_runtime_zero();\n#else\n return value;\n#endif\n}\n\nfn split(a: f32) -> vec2f {\n let splitValue = prevent_fp64_optimization(fp64arithmetic.SPLIT + fp64_runtime_zero());\n let t = prevent_fp64_optimization(a * splitValue);\n let temp = prevent_fp64_optimization(t - a);\n let aHi = prevent_fp64_optimization(t - temp);\n let aLo = prevent_fp64_optimization(a - aHi);\n return vec2f(aHi, aLo);\n}\n\nfn split2(a: vec2f) -> vec2f {\n var b = split(a.x);\n b.y = b.y + a.y;\n return b;\n}\n\nfn quickTwoSum(a: f32, b: f32) -> vec2f {\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let sum = prevent_fp64_optimization((a + b) * fp64arithmetic.ONE);\n let err = prevent_fp64_optimization(b - (sum - a) * fp64arithmetic.ONE);\n#else\n let sum = prevent_fp64_optimization(a + b);\n let err = prevent_fp64_optimization(b - (sum - a));\n#endif\n return vec2f(sum, err);\n}\n\nfn twoSum(a: f32, b: f32) -> vec2f {\n let s = prevent_fp64_optimization(a + b);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let v = prevent_fp64_optimization((s * fp64arithmetic.ONE - a) * fp64arithmetic.ONE);\n let err =\n prevent_fp64_optimization((a - (s - v) * fp64arithmetic.ONE) *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE) +\n prevent_fp64_optimization(b - v);\n#else\n let v = prevent_fp64_optimization(s - a);\n let err = prevent_fp64_optimization(a - (s - v)) + prevent_fp64_optimization(b - v);\n#endif\n return vec2f(s, err);\n}\n\nfn twoSub(a: f32, b: f32) -> vec2f {\n let s = prevent_fp64_optimization(a - b);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let v = prevent_fp64_optimization((s * fp64arithmetic.ONE - a) * fp64arithmetic.ONE);\n let err =\n prevent_fp64_optimization((a - (s - v) * fp64arithmetic.ONE) *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE) -\n prevent_fp64_optimization(b + v);\n#else\n let v = prevent_fp64_optimization(s - a);\n let err = prevent_fp64_optimization(a - (s - v)) - prevent_fp64_optimization(b + v);\n#endif\n return vec2f(s, err);\n}\n\nfn twoSqr(a: f32) -> vec2f {\n let prod = prevent_fp64_optimization(a * a);\n let aFp64 = split(a);\n let highProduct = prevent_fp64_optimization(aFp64.x * aFp64.x);\n let crossProduct = prevent_fp64_optimization(2.0 * aFp64.x * aFp64.y);\n let lowProduct = prevent_fp64_optimization(aFp64.y * aFp64.y);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let err =\n (prevent_fp64_optimization(highProduct - prod) * fp64arithmetic.ONE +\n crossProduct * fp64arithmetic.ONE * fp64arithmetic.ONE) +\n lowProduct * fp64arithmetic.ONE * fp64arithmetic.ONE * fp64arithmetic.ONE;\n#else\n let err = ((prevent_fp64_optimization(highProduct - prod) + crossProduct) + lowProduct);\n#endif\n return vec2f(prod, err);\n}\n\nfn twoProd(a: f32, b: f32) -> vec2f {\n let prod = prevent_fp64_optimization(a * b);\n let aFp64 = split(a);\n let bFp64 = split(b);\n let highProduct = prevent_fp64_optimization(aFp64.x * bFp64.x);\n let crossProduct1 = prevent_fp64_optimization(aFp64.x * bFp64.y);\n let crossProduct2 = prevent_fp64_optimization(aFp64.y * bFp64.x);\n let lowProduct = prevent_fp64_optimization(aFp64.y * bFp64.y);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let err1 = (highProduct - prod) * fp64arithmetic.ONE;\n let err2 = crossProduct1 * fp64arithmetic.ONE * fp64arithmetic.ONE;\n let err3 = crossProduct2 * fp64arithmetic.ONE * fp64arithmetic.ONE * fp64arithmetic.ONE;\n let err4 =\n lowProduct *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE;\n#else\n let err1 = highProduct - prod;\n let err2 = crossProduct1;\n let err3 = crossProduct2;\n let err4 = lowProduct;\n#endif\n let err12InputA = prevent_fp64_optimization(err1);\n let err12InputB = prevent_fp64_optimization(err2);\n let err12 = prevent_fp64_optimization(err12InputA + err12InputB);\n let err123InputA = prevent_fp64_optimization(err12);\n let err123InputB = prevent_fp64_optimization(err3);\n let err123 = prevent_fp64_optimization(err123InputA + err123InputB);\n let err1234InputA = prevent_fp64_optimization(err123);\n let err1234InputB = prevent_fp64_optimization(err4);\n let err = prevent_fp64_optimization(err1234InputA + err1234InputB);\n return vec2f(prod, err);\n}\n\nfn sum_fp64(a: vec2f, b: vec2f) -> vec2f {\n var s = twoSum(a.x, b.x);\n let t = twoSum(a.y, b.y);\n s.y = prevent_fp64_optimization(s.y + t.x);\n s = quickTwoSum(s.x, s.y);\n s.y = prevent_fp64_optimization(s.y + t.y);\n s = quickTwoSum(s.x, s.y);\n return s;\n}\n\nfn sub_fp64(a: vec2f, b: vec2f) -> vec2f {\n var s = twoSub(a.x, b.x);\n let t = twoSub(a.y, b.y);\n s.y = prevent_fp64_optimization(s.y + t.x);\n s = quickTwoSum(s.x, s.y);\n s.y = prevent_fp64_optimization(s.y + t.y);\n s = quickTwoSum(s.x, s.y);\n return s;\n}\n\nfn mul_fp64(a: vec2f, b: vec2f) -> vec2f {\n var prod = twoProd(a.x, b.x);\n let crossProduct1 = prevent_fp64_optimization(a.x * b.y);\n prod.y = prevent_fp64_optimization(prod.y + crossProduct1);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n prod = split2(prod);\n#endif\n prod = quickTwoSum(prod.x, prod.y);\n let crossProduct2 = prevent_fp64_optimization(a.y * b.x);\n prod.y = prevent_fp64_optimization(prod.y + crossProduct2);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n prod = split2(prod);\n#endif\n prod = quickTwoSum(prod.x, prod.y);\n return prod;\n}\n\nfn div_fp64(a: vec2f, b: vec2f) -> vec2f {\n let xn = prevent_fp64_optimization(1.0 / b.x);\n let yn = mul_fp64(a, vec2f(xn, fp64_runtime_zero()));\n let diff = prevent_fp64_optimization(sub_fp64(a, mul_fp64(b, yn)).x);\n let prod = twoProd(xn, diff);\n return sum_fp64(yn, prod);\n}\n\nfn sqrt_fp64(a: vec2f) -> vec2f {\n if (a.x == 0.0 && a.y == 0.0) {\n return vec2f(0.0, 0.0);\n }\n if (a.x < 0.0) {\n let nanValue = fp64_nan(a.x);\n return vec2f(nanValue, nanValue);\n }\n\n let x = prevent_fp64_optimization(1.0 / sqrt(a.x));\n let yn = prevent_fp64_optimization(a.x * x);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let ynSqr = twoSqr(yn) * fp64arithmetic.ONE;\n#else\n let ynSqr = twoSqr(yn);\n#endif\n let diff = prevent_fp64_optimization(sub_fp64(a, ynSqr).x);\n let prod = twoProd(prevent_fp64_optimization(x * 0.5), diff);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n return sum_fp64(split(yn), prod);\n#else\n return sum_fp64(vec2f(yn, 0.0), prod);\n#endif\n}\n";
1
+ /** WGSL source for fp64 arithmetic helpers and raw binary64-to-Float32 subtraction. */
2
+ export declare const fp64arithmeticWGSL = "struct Fp64ArithmeticUniforms {\n ONE: f32,\n SPLIT: f32,\n};\n\n@group(0) @binding(auto) var<uniform> fp64arithmetic : Fp64ArithmeticUniforms;\n\nstruct Fp64Bits {\n sign: u32,\n exponent: i32,\n significand: vec2u,\n isZero: bool,\n isInf: bool,\n isNan: bool,\n};\n\nfn fp64_nan(seed: f32) -> f32 {\n let nanBits = 0x7fc00000u | select(0u, 1u, seed < 0.0);\n return bitcast<f32>(nanBits);\n}\n\nfn fp64_u64_is_zero(value: vec2u) -> bool {\n return value.x == 0u && value.y == 0u;\n}\n\nfn fp64_u64_compare(a: vec2u, b: vec2u) -> i32 {\n if (a.x != b.x) {\n return select(-1, 1, a.x > b.x);\n }\n if (a.y != b.y) {\n return select(-1, 1, a.y > b.y);\n }\n return 0;\n}\n\nfn fp64_u64_add(a: vec2u, b: vec2u) -> vec2u {\n let low = a.y + b.y;\n let carry = select(0u, 1u, low < a.y);\n return vec2u(a.x + b.x + carry, low);\n}\n\nfn fp64_u64_sub(a: vec2u, b: vec2u) -> vec2u {\n let borrow = select(0u, 1u, a.y < b.y);\n return vec2u(a.x - b.x - borrow, a.y - b.y);\n}\n\nfn fp64_u64_shift_left(value: vec2u, shift: u32) -> vec2u {\n if (shift == 0u) {\n return value;\n }\n if (shift < 32u) {\n return vec2u((value.x << shift) | (value.y >> (32u - shift)), value.y << shift);\n }\n if (shift == 32u) {\n return vec2u(value.y, 0u);\n }\n if (shift < 64u) {\n return vec2u(value.y << (shift - 32u), 0u);\n }\n return vec2u(0u);\n}\n\nfn fp64_u64_shift_right(value: vec2u, shift: u32) -> vec2u {\n if (shift == 0u) {\n return value;\n }\n if (shift < 32u) {\n return vec2u(value.x >> shift, (value.y >> shift) | (value.x << (32u - shift)));\n }\n if (shift == 32u) {\n return vec2u(0u, value.x);\n }\n if (shift < 64u) {\n return vec2u(0u, value.x >> (shift - 32u));\n }\n return vec2u(0u);\n}\n\nfn fp64_u64_get_bit(value: vec2u, bitIndex: u32) -> bool {\n if (bitIndex >= 64u) {\n return false;\n }\n if (bitIndex >= 32u) {\n return ((value.x >> (bitIndex - 32u)) & 1u) != 0u;\n }\n return ((value.y >> bitIndex) & 1u) != 0u;\n}\n\nfn fp64_u64_has_bits_below(value: vec2u, bitCount: u32) -> bool {\n if (bitCount == 0u) {\n return false;\n }\n if (bitCount >= 64u) {\n return !fp64_u64_is_zero(value);\n }\n if (bitCount > 32u) {\n let highBitCount = bitCount - 32u;\n let highMask = (1u << highBitCount) - 1u;\n return value.y != 0u || (value.x & highMask) != 0u;\n }\n if (bitCount == 32u) {\n return value.y != 0u;\n }\n let lowMask = (1u << bitCount) - 1u;\n return (value.y & lowMask) != 0u;\n}\n\nfn fp64_u64_shift_right_sticky(value: vec2u, shift: u32) -> vec2u {\n var shifted = fp64_u64_shift_right(value, shift);\n if (fp64_u64_has_bits_below(value, shift)) {\n shifted.y = shifted.y | 1u;\n }\n return shifted;\n}\n\nfn fp64_u64_count_leading_zeros(value: vec2u) -> u32 {\n if (value.x != 0u) {\n return countLeadingZeros(value.x);\n }\n return 32u + countLeadingZeros(value.y);\n}\n\nfn fp64_round_shift_right_to_u32(value: vec2u, shift: u32) -> u32 {\n if (shift == 0u) {\n return value.y;\n }\n\n let truncated = fp64_u64_shift_right(value, shift);\n var rounded = truncated.y;\n let guard = fp64_u64_get_bit(value, shift - 1u);\n let hasTrailingBits = fp64_u64_has_bits_below(value, shift - 1u);\n if (guard && (hasTrailingBits || (rounded & 1u) == 1u)) {\n rounded = rounded + 1u;\n }\n return rounded;\n}\n\nfn fp64_make_f32_bits_from_u64(sign: u32, significand: vec2u, baseExponent: i32) -> u32 {\n if (fp64_u64_is_zero(significand)) {\n return sign << 31u;\n }\n\n let leadingZeros = fp64_u64_count_leading_zeros(significand);\n let mostSignificantBit = 63u - leadingZeros;\n var exponent = baseExponent + i32(mostSignificantBit);\n\n if (exponent > 127) {\n return (sign << 31u) | 0x7f800000u;\n }\n\n if (exponent >= -126) {\n let shift = i32(mostSignificantBit) - 23;\n var significand24: u32;\n if (shift > 0) {\n significand24 = fp64_round_shift_right_to_u32(significand, u32(shift));\n } else {\n significand24 = fp64_u64_shift_left(significand, u32(-shift)).y;\n }\n\n if (significand24 >= 0x1000000u) {\n significand24 = significand24 >> 1u;\n exponent = exponent + 1;\n if (exponent > 127) {\n return (sign << 31u) | 0x7f800000u;\n }\n }\n\n return (sign << 31u) | (u32(exponent + 127) << 23u) | (significand24 & 0x7fffffu);\n }\n\n let scaleExponent = baseExponent + 149;\n var mantissa: u32;\n if (scaleExponent >= 0) {\n mantissa = fp64_u64_shift_left(significand, u32(scaleExponent)).y;\n } else {\n mantissa = fp64_round_shift_right_to_u32(significand, u32(-scaleExponent));\n }\n\n if (mantissa >= 0x800000u) {\n return (sign << 31u) | 0x00800000u;\n }\n return (sign << 31u) | mantissa;\n}\n\nfn fp64_decode_bits(bits: vec2u) -> Fp64Bits {\n let sign = bits.x >> 31u;\n let exponentBits = (bits.x >> 20u) & 0x7ffu;\n let fractionHigh = bits.x & 0xfffffu;\n let fractionLow = bits.y;\n let fraction = vec2u(fractionHigh, fractionLow);\n\n if (exponentBits == 0x7ffu) {\n let isInf = fp64_u64_is_zero(fraction);\n return Fp64Bits(sign, 0, vec2u(0u), false, isInf, !isInf);\n }\n\n if (exponentBits == 0u) {\n let isZero = fp64_u64_is_zero(fraction);\n return Fp64Bits(sign, -1022, fraction, isZero, false, false);\n }\n\n return Fp64Bits(sign, i32(exponentBits) - 1023, vec2u((1u << 20u) | fractionHigh, fractionLow), false, false, false);\n}\n\nfn fp64_finite_magnitude_compare(a: Fp64Bits, b: Fp64Bits) -> i32 {\n if (a.exponent != b.exponent) {\n return select(-1, 1, a.exponent > b.exponent);\n }\n return fp64_u64_compare(a.significand, b.significand);\n}\n\nfn fp64_add_aligned_magnitudes_to_f32_bits(sign: u32, larger: Fp64Bits, smaller: Fp64Bits) -> u32 {\n let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);\n let smallSignificand = fp64_u64_shift_right_sticky(\n fp64_u64_shift_left(smaller.significand, 3u),\n u32(larger.exponent - smaller.exponent)\n );\n let resultSignificand = fp64_u64_add(largeSignificand, smallSignificand);\n return fp64_make_f32_bits_from_u64(sign, resultSignificand, larger.exponent - 55);\n}\n\nfn fp64_sub_aligned_magnitudes_to_f32_bits(sign: u32, larger: Fp64Bits, smaller: Fp64Bits) -> u32 {\n let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);\n let smallSignificand = fp64_u64_shift_right_sticky(\n fp64_u64_shift_left(smaller.significand, 3u),\n u32(larger.exponent - smaller.exponent)\n );\n let resultSignificand = fp64_u64_sub(largeSignificand, smallSignificand);\n return fp64_make_f32_bits_from_u64(sign, resultSignificand, larger.exponent - 55);\n}\n\n// Subtract two raw binary64 values and round the exact result once to f32.\n// The input words are canonical high/low words: .x contains sign/exponent/high\n// fraction bits, and .y contains the low 32 fraction bits.\nfn sub_fp64u32_to_f32_bits(aBits: vec2u, bBits: vec2u) -> u32 {\n let a = fp64_decode_bits(aBits);\n let b = fp64_decode_bits(bBits);\n let bSubtractionSign = b.sign ^ 1u;\n\n if (a.isNan || b.isNan) {\n return 0x7fc00000u;\n }\n if (a.isInf && b.isInf) {\n if (a.sign == bSubtractionSign) {\n return (a.sign << 31u) | 0x7f800000u;\n }\n return 0x7fc00000u;\n }\n if (a.isInf) {\n return (a.sign << 31u) | 0x7f800000u;\n }\n if (b.isInf) {\n return (bSubtractionSign << 31u) | 0x7f800000u;\n }\n if (a.isZero && b.isZero) {\n return select(0u, 0x80000000u, a.sign == 1u && b.sign == 0u);\n }\n\n let magnitudeComparison = fp64_finite_magnitude_compare(a, b);\n if (a.sign == bSubtractionSign) {\n if (magnitudeComparison >= 0) {\n return fp64_add_aligned_magnitudes_to_f32_bits(a.sign, a, b);\n }\n return fp64_add_aligned_magnitudes_to_f32_bits(a.sign, b, a);\n }\n\n if (magnitudeComparison == 0) {\n return 0u;\n }\n if (magnitudeComparison > 0) {\n return fp64_sub_aligned_magnitudes_to_f32_bits(a.sign, a, b);\n }\n return fp64_sub_aligned_magnitudes_to_f32_bits(bSubtractionSign, b, a);\n}\n\nfn sub_fp64u32_to_f32(aBits: vec2u, bBits: vec2u) -> f32 {\n return bitcast<f32>(sub_fp64u32_to_f32_bits(aBits, bBits));\n}\n\nfn fp64_runtime_zero() -> f32 {\n return fp64arithmetic.ONE * 0.0;\n}\n\nfn prevent_fp64_optimization(value: f32) -> f32 {\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n return value + fp64_runtime_zero();\n#else\n return value;\n#endif\n}\n\nfn split(a: f32) -> vec2f {\n let splitValue = prevent_fp64_optimization(fp64arithmetic.SPLIT + fp64_runtime_zero());\n let t = prevent_fp64_optimization(a * splitValue);\n let temp = prevent_fp64_optimization(t - a);\n let aHi = prevent_fp64_optimization(t - temp);\n let aLo = prevent_fp64_optimization(a - aHi);\n return vec2f(aHi, aLo);\n}\n\nfn split2(a: vec2f) -> vec2f {\n var b = split(a.x);\n b.y = b.y + a.y;\n return b;\n}\n\nfn quickTwoSum(a: f32, b: f32) -> vec2f {\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let sum = prevent_fp64_optimization((a + b) * fp64arithmetic.ONE);\n let err = prevent_fp64_optimization(b - (sum - a) * fp64arithmetic.ONE);\n#else\n let sum = prevent_fp64_optimization(a + b);\n let err = prevent_fp64_optimization(b - (sum - a));\n#endif\n return vec2f(sum, err);\n}\n\nfn twoSum(a: f32, b: f32) -> vec2f {\n let s = prevent_fp64_optimization(a + b);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let v = prevent_fp64_optimization((s * fp64arithmetic.ONE - a) * fp64arithmetic.ONE);\n let err =\n prevent_fp64_optimization((a - (s - v) * fp64arithmetic.ONE) *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE) +\n prevent_fp64_optimization(b - v);\n#else\n let v = prevent_fp64_optimization(s - a);\n let err = prevent_fp64_optimization(a - (s - v)) + prevent_fp64_optimization(b - v);\n#endif\n return vec2f(s, err);\n}\n\nfn twoSub(a: f32, b: f32) -> vec2f {\n let s = prevent_fp64_optimization(a - b);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let v = prevent_fp64_optimization((s * fp64arithmetic.ONE - a) * fp64arithmetic.ONE);\n let err =\n prevent_fp64_optimization((a - (s - v) * fp64arithmetic.ONE) *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE) -\n prevent_fp64_optimization(b + v);\n#else\n let v = prevent_fp64_optimization(s - a);\n let err = prevent_fp64_optimization(a - (s - v)) - prevent_fp64_optimization(b + v);\n#endif\n return vec2f(s, err);\n}\n\nfn twoSqr(a: f32) -> vec2f {\n let prod = prevent_fp64_optimization(a * a);\n let aFp64 = split(a);\n let highProduct = prevent_fp64_optimization(aFp64.x * aFp64.x);\n let crossProduct = prevent_fp64_optimization(2.0 * aFp64.x * aFp64.y);\n let lowProduct = prevent_fp64_optimization(aFp64.y * aFp64.y);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let err =\n (prevent_fp64_optimization(highProduct - prod) * fp64arithmetic.ONE +\n crossProduct * fp64arithmetic.ONE * fp64arithmetic.ONE) +\n lowProduct * fp64arithmetic.ONE * fp64arithmetic.ONE * fp64arithmetic.ONE;\n#else\n let err = ((prevent_fp64_optimization(highProduct - prod) + crossProduct) + lowProduct);\n#endif\n return vec2f(prod, err);\n}\n\nfn twoProd(a: f32, b: f32) -> vec2f {\n let prod = prevent_fp64_optimization(a * b);\n let aFp64 = split(a);\n let bFp64 = split(b);\n let highProduct = prevent_fp64_optimization(aFp64.x * bFp64.x);\n let crossProduct1 = prevent_fp64_optimization(aFp64.x * bFp64.y);\n let crossProduct2 = prevent_fp64_optimization(aFp64.y * bFp64.x);\n let lowProduct = prevent_fp64_optimization(aFp64.y * bFp64.y);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let err1 = (highProduct - prod) * fp64arithmetic.ONE;\n let err2 = crossProduct1 * fp64arithmetic.ONE * fp64arithmetic.ONE;\n let err3 = crossProduct2 * fp64arithmetic.ONE * fp64arithmetic.ONE * fp64arithmetic.ONE;\n let err4 =\n lowProduct *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE *\n fp64arithmetic.ONE;\n#else\n let err1 = highProduct - prod;\n let err2 = crossProduct1;\n let err3 = crossProduct2;\n let err4 = lowProduct;\n#endif\n let err12InputA = prevent_fp64_optimization(err1);\n let err12InputB = prevent_fp64_optimization(err2);\n let err12 = prevent_fp64_optimization(err12InputA + err12InputB);\n let err123InputA = prevent_fp64_optimization(err12);\n let err123InputB = prevent_fp64_optimization(err3);\n let err123 = prevent_fp64_optimization(err123InputA + err123InputB);\n let err1234InputA = prevent_fp64_optimization(err123);\n let err1234InputB = prevent_fp64_optimization(err4);\n let err = prevent_fp64_optimization(err1234InputA + err1234InputB);\n return vec2f(prod, err);\n}\n\nfn sum_fp64(a: vec2f, b: vec2f) -> vec2f {\n var s = twoSum(a.x, b.x);\n let t = twoSum(a.y, b.y);\n s.y = prevent_fp64_optimization(s.y + t.x);\n s = quickTwoSum(s.x, s.y);\n s.y = prevent_fp64_optimization(s.y + t.y);\n s = quickTwoSum(s.x, s.y);\n return s;\n}\n\nfn sub_fp64(a: vec2f, b: vec2f) -> vec2f {\n var s = twoSub(a.x, b.x);\n let t = twoSub(a.y, b.y);\n s.y = prevent_fp64_optimization(s.y + t.x);\n s = quickTwoSum(s.x, s.y);\n s.y = prevent_fp64_optimization(s.y + t.y);\n s = quickTwoSum(s.x, s.y);\n return s;\n}\n\nfn mul_fp64(a: vec2f, b: vec2f) -> vec2f {\n var prod = twoProd(a.x, b.x);\n let crossProduct1 = prevent_fp64_optimization(a.x * b.y);\n prod.y = prevent_fp64_optimization(prod.y + crossProduct1);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n prod = split2(prod);\n#endif\n prod = quickTwoSum(prod.x, prod.y);\n let crossProduct2 = prevent_fp64_optimization(a.y * b.x);\n prod.y = prevent_fp64_optimization(prod.y + crossProduct2);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n prod = split2(prod);\n#endif\n prod = quickTwoSum(prod.x, prod.y);\n return prod;\n}\n\nfn div_fp64(a: vec2f, b: vec2f) -> vec2f {\n let xn = prevent_fp64_optimization(1.0 / b.x);\n let yn = mul_fp64(a, vec2f(xn, fp64_runtime_zero()));\n let diff = prevent_fp64_optimization(sub_fp64(a, mul_fp64(b, yn)).x);\n let prod = twoProd(xn, diff);\n return sum_fp64(yn, prod);\n}\n\nfn sqrt_fp64(a: vec2f) -> vec2f {\n if (a.x == 0.0 && a.y == 0.0) {\n return vec2f(0.0, 0.0);\n }\n if (a.x < 0.0) {\n let nanValue = fp64_nan(a.x);\n return vec2f(nanValue, nanValue);\n }\n\n let x = prevent_fp64_optimization(1.0 / sqrt(a.x));\n let yn = prevent_fp64_optimization(a.x * x);\n#ifdef LUMA_FP64_CODE_ELIMINATION_WORKAROUND\n let ynSqr = twoSqr(yn) * fp64arithmetic.ONE;\n#else\n let ynSqr = twoSqr(yn);\n#endif\n let diff = prevent_fp64_optimization(sub_fp64(a, ynSqr).x);\n let prod = twoProd(prevent_fp64_optimization(x * 0.5), diff);\n#ifdef LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND\n return sum_fp64(split(yn), prod);\n#else\n return sum_fp64(vec2f(yn, 0.0), prod);\n#endif\n}\n";
2
3
  //# sourceMappingURL=fp64-arithmetic-wgsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fp64-arithmetic-wgsl.d.ts","sourceRoot":"","sources":["../../../../src/modules/math/fp64/fp64-arithmetic-wgsl.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,yyNA+M9B,CAAC"}
1
+ {"version":3,"file":"fp64-arithmetic-wgsl.d.ts","sourceRoot":"","sources":["../../../../src/modules/math/fp64/fp64-arithmetic-wgsl.ts"],"names":[],"mappings":"AAIA,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,o/cA0d9B,CAAC"}
@@ -1,6 +1,7 @@
1
1
  // luma.gl
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
+ /** WGSL source for fp64 arithmetic helpers and raw binary64-to-Float32 subtraction. */
4
5
  export const fp64arithmeticWGSL = /* wgsl */ `\
5
6
  struct Fp64ArithmeticUniforms {
6
7
  ONE: f32,
@@ -9,11 +10,278 @@ struct Fp64ArithmeticUniforms {
9
10
 
10
11
  @group(0) @binding(auto) var<uniform> fp64arithmetic : Fp64ArithmeticUniforms;
11
12
 
13
+ struct Fp64Bits {
14
+ sign: u32,
15
+ exponent: i32,
16
+ significand: vec2u,
17
+ isZero: bool,
18
+ isInf: bool,
19
+ isNan: bool,
20
+ };
21
+
12
22
  fn fp64_nan(seed: f32) -> f32 {
13
23
  let nanBits = 0x7fc00000u | select(0u, 1u, seed < 0.0);
14
24
  return bitcast<f32>(nanBits);
15
25
  }
16
26
 
27
+ fn fp64_u64_is_zero(value: vec2u) -> bool {
28
+ return value.x == 0u && value.y == 0u;
29
+ }
30
+
31
+ fn fp64_u64_compare(a: vec2u, b: vec2u) -> i32 {
32
+ if (a.x != b.x) {
33
+ return select(-1, 1, a.x > b.x);
34
+ }
35
+ if (a.y != b.y) {
36
+ return select(-1, 1, a.y > b.y);
37
+ }
38
+ return 0;
39
+ }
40
+
41
+ fn fp64_u64_add(a: vec2u, b: vec2u) -> vec2u {
42
+ let low = a.y + b.y;
43
+ let carry = select(0u, 1u, low < a.y);
44
+ return vec2u(a.x + b.x + carry, low);
45
+ }
46
+
47
+ fn fp64_u64_sub(a: vec2u, b: vec2u) -> vec2u {
48
+ let borrow = select(0u, 1u, a.y < b.y);
49
+ return vec2u(a.x - b.x - borrow, a.y - b.y);
50
+ }
51
+
52
+ fn fp64_u64_shift_left(value: vec2u, shift: u32) -> vec2u {
53
+ if (shift == 0u) {
54
+ return value;
55
+ }
56
+ if (shift < 32u) {
57
+ return vec2u((value.x << shift) | (value.y >> (32u - shift)), value.y << shift);
58
+ }
59
+ if (shift == 32u) {
60
+ return vec2u(value.y, 0u);
61
+ }
62
+ if (shift < 64u) {
63
+ return vec2u(value.y << (shift - 32u), 0u);
64
+ }
65
+ return vec2u(0u);
66
+ }
67
+
68
+ fn fp64_u64_shift_right(value: vec2u, shift: u32) -> vec2u {
69
+ if (shift == 0u) {
70
+ return value;
71
+ }
72
+ if (shift < 32u) {
73
+ return vec2u(value.x >> shift, (value.y >> shift) | (value.x << (32u - shift)));
74
+ }
75
+ if (shift == 32u) {
76
+ return vec2u(0u, value.x);
77
+ }
78
+ if (shift < 64u) {
79
+ return vec2u(0u, value.x >> (shift - 32u));
80
+ }
81
+ return vec2u(0u);
82
+ }
83
+
84
+ fn fp64_u64_get_bit(value: vec2u, bitIndex: u32) -> bool {
85
+ if (bitIndex >= 64u) {
86
+ return false;
87
+ }
88
+ if (bitIndex >= 32u) {
89
+ return ((value.x >> (bitIndex - 32u)) & 1u) != 0u;
90
+ }
91
+ return ((value.y >> bitIndex) & 1u) != 0u;
92
+ }
93
+
94
+ fn fp64_u64_has_bits_below(value: vec2u, bitCount: u32) -> bool {
95
+ if (bitCount == 0u) {
96
+ return false;
97
+ }
98
+ if (bitCount >= 64u) {
99
+ return !fp64_u64_is_zero(value);
100
+ }
101
+ if (bitCount > 32u) {
102
+ let highBitCount = bitCount - 32u;
103
+ let highMask = (1u << highBitCount) - 1u;
104
+ return value.y != 0u || (value.x & highMask) != 0u;
105
+ }
106
+ if (bitCount == 32u) {
107
+ return value.y != 0u;
108
+ }
109
+ let lowMask = (1u << bitCount) - 1u;
110
+ return (value.y & lowMask) != 0u;
111
+ }
112
+
113
+ fn fp64_u64_shift_right_sticky(value: vec2u, shift: u32) -> vec2u {
114
+ var shifted = fp64_u64_shift_right(value, shift);
115
+ if (fp64_u64_has_bits_below(value, shift)) {
116
+ shifted.y = shifted.y | 1u;
117
+ }
118
+ return shifted;
119
+ }
120
+
121
+ fn fp64_u64_count_leading_zeros(value: vec2u) -> u32 {
122
+ if (value.x != 0u) {
123
+ return countLeadingZeros(value.x);
124
+ }
125
+ return 32u + countLeadingZeros(value.y);
126
+ }
127
+
128
+ fn fp64_round_shift_right_to_u32(value: vec2u, shift: u32) -> u32 {
129
+ if (shift == 0u) {
130
+ return value.y;
131
+ }
132
+
133
+ let truncated = fp64_u64_shift_right(value, shift);
134
+ var rounded = truncated.y;
135
+ let guard = fp64_u64_get_bit(value, shift - 1u);
136
+ let hasTrailingBits = fp64_u64_has_bits_below(value, shift - 1u);
137
+ if (guard && (hasTrailingBits || (rounded & 1u) == 1u)) {
138
+ rounded = rounded + 1u;
139
+ }
140
+ return rounded;
141
+ }
142
+
143
+ fn fp64_make_f32_bits_from_u64(sign: u32, significand: vec2u, baseExponent: i32) -> u32 {
144
+ if (fp64_u64_is_zero(significand)) {
145
+ return sign << 31u;
146
+ }
147
+
148
+ let leadingZeros = fp64_u64_count_leading_zeros(significand);
149
+ let mostSignificantBit = 63u - leadingZeros;
150
+ var exponent = baseExponent + i32(mostSignificantBit);
151
+
152
+ if (exponent > 127) {
153
+ return (sign << 31u) | 0x7f800000u;
154
+ }
155
+
156
+ if (exponent >= -126) {
157
+ let shift = i32(mostSignificantBit) - 23;
158
+ var significand24: u32;
159
+ if (shift > 0) {
160
+ significand24 = fp64_round_shift_right_to_u32(significand, u32(shift));
161
+ } else {
162
+ significand24 = fp64_u64_shift_left(significand, u32(-shift)).y;
163
+ }
164
+
165
+ if (significand24 >= 0x1000000u) {
166
+ significand24 = significand24 >> 1u;
167
+ exponent = exponent + 1;
168
+ if (exponent > 127) {
169
+ return (sign << 31u) | 0x7f800000u;
170
+ }
171
+ }
172
+
173
+ return (sign << 31u) | (u32(exponent + 127) << 23u) | (significand24 & 0x7fffffu);
174
+ }
175
+
176
+ let scaleExponent = baseExponent + 149;
177
+ var mantissa: u32;
178
+ if (scaleExponent >= 0) {
179
+ mantissa = fp64_u64_shift_left(significand, u32(scaleExponent)).y;
180
+ } else {
181
+ mantissa = fp64_round_shift_right_to_u32(significand, u32(-scaleExponent));
182
+ }
183
+
184
+ if (mantissa >= 0x800000u) {
185
+ return (sign << 31u) | 0x00800000u;
186
+ }
187
+ return (sign << 31u) | mantissa;
188
+ }
189
+
190
+ fn fp64_decode_bits(bits: vec2u) -> Fp64Bits {
191
+ let sign = bits.x >> 31u;
192
+ let exponentBits = (bits.x >> 20u) & 0x7ffu;
193
+ let fractionHigh = bits.x & 0xfffffu;
194
+ let fractionLow = bits.y;
195
+ let fraction = vec2u(fractionHigh, fractionLow);
196
+
197
+ if (exponentBits == 0x7ffu) {
198
+ let isInf = fp64_u64_is_zero(fraction);
199
+ return Fp64Bits(sign, 0, vec2u(0u), false, isInf, !isInf);
200
+ }
201
+
202
+ if (exponentBits == 0u) {
203
+ let isZero = fp64_u64_is_zero(fraction);
204
+ return Fp64Bits(sign, -1022, fraction, isZero, false, false);
205
+ }
206
+
207
+ return Fp64Bits(sign, i32(exponentBits) - 1023, vec2u((1u << 20u) | fractionHigh, fractionLow), false, false, false);
208
+ }
209
+
210
+ fn fp64_finite_magnitude_compare(a: Fp64Bits, b: Fp64Bits) -> i32 {
211
+ if (a.exponent != b.exponent) {
212
+ return select(-1, 1, a.exponent > b.exponent);
213
+ }
214
+ return fp64_u64_compare(a.significand, b.significand);
215
+ }
216
+
217
+ fn fp64_add_aligned_magnitudes_to_f32_bits(sign: u32, larger: Fp64Bits, smaller: Fp64Bits) -> u32 {
218
+ let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);
219
+ let smallSignificand = fp64_u64_shift_right_sticky(
220
+ fp64_u64_shift_left(smaller.significand, 3u),
221
+ u32(larger.exponent - smaller.exponent)
222
+ );
223
+ let resultSignificand = fp64_u64_add(largeSignificand, smallSignificand);
224
+ return fp64_make_f32_bits_from_u64(sign, resultSignificand, larger.exponent - 55);
225
+ }
226
+
227
+ fn fp64_sub_aligned_magnitudes_to_f32_bits(sign: u32, larger: Fp64Bits, smaller: Fp64Bits) -> u32 {
228
+ let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);
229
+ let smallSignificand = fp64_u64_shift_right_sticky(
230
+ fp64_u64_shift_left(smaller.significand, 3u),
231
+ u32(larger.exponent - smaller.exponent)
232
+ );
233
+ let resultSignificand = fp64_u64_sub(largeSignificand, smallSignificand);
234
+ return fp64_make_f32_bits_from_u64(sign, resultSignificand, larger.exponent - 55);
235
+ }
236
+
237
+ // Subtract two raw binary64 values and round the exact result once to f32.
238
+ // The input words are canonical high/low words: .x contains sign/exponent/high
239
+ // fraction bits, and .y contains the low 32 fraction bits.
240
+ fn sub_fp64u32_to_f32_bits(aBits: vec2u, bBits: vec2u) -> u32 {
241
+ let a = fp64_decode_bits(aBits);
242
+ let b = fp64_decode_bits(bBits);
243
+ let bSubtractionSign = b.sign ^ 1u;
244
+
245
+ if (a.isNan || b.isNan) {
246
+ return 0x7fc00000u;
247
+ }
248
+ if (a.isInf && b.isInf) {
249
+ if (a.sign == bSubtractionSign) {
250
+ return (a.sign << 31u) | 0x7f800000u;
251
+ }
252
+ return 0x7fc00000u;
253
+ }
254
+ if (a.isInf) {
255
+ return (a.sign << 31u) | 0x7f800000u;
256
+ }
257
+ if (b.isInf) {
258
+ return (bSubtractionSign << 31u) | 0x7f800000u;
259
+ }
260
+ if (a.isZero && b.isZero) {
261
+ return select(0u, 0x80000000u, a.sign == 1u && b.sign == 0u);
262
+ }
263
+
264
+ let magnitudeComparison = fp64_finite_magnitude_compare(a, b);
265
+ if (a.sign == bSubtractionSign) {
266
+ if (magnitudeComparison >= 0) {
267
+ return fp64_add_aligned_magnitudes_to_f32_bits(a.sign, a, b);
268
+ }
269
+ return fp64_add_aligned_magnitudes_to_f32_bits(a.sign, b, a);
270
+ }
271
+
272
+ if (magnitudeComparison == 0) {
273
+ return 0u;
274
+ }
275
+ if (magnitudeComparison > 0) {
276
+ return fp64_sub_aligned_magnitudes_to_f32_bits(a.sign, a, b);
277
+ }
278
+ return fp64_sub_aligned_magnitudes_to_f32_bits(bSubtractionSign, b, a);
279
+ }
280
+
281
+ fn sub_fp64u32_to_f32(aBits: vec2u, bBits: vec2u) -> f32 {
282
+ return bitcast<f32>(sub_fp64u32_to_f32_bits(aBits, bBits));
283
+ }
284
+
17
285
  fn fp64_runtime_zero() -> f32 {
18
286
  return fp64arithmetic.ONE * 0.0;
19
287
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fp64-arithmetic-wgsl.js","sourceRoot":"","sources":["../../../../src/modules/math/fp64/fp64-arithmetic-wgsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAEpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+M5C,CAAC"}
1
+ {"version":3,"file":"fp64-arithmetic-wgsl.js","sourceRoot":"","sources":["../../../../src/modules/math/fp64/fp64-arithmetic-wgsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAEpC,uFAAuF;AACvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0d5C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/shadertools",
3
- "version": "9.3.6",
3
+ "version": "9.4.0-alpha.1",
4
4
  "description": "Shader module system for luma.gl",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -52,5 +52,5 @@
52
52
  "@math.gl/core": "^4.1.0",
53
53
  "@math.gl/types": "^4.1.0"
54
54
  },
55
- "gitHead": "725fed5e23fd39ca65229da1e8f048235fe3d4e9"
55
+ "gitHead": "360b5ac37102a9ab1ae6470d2c70dfa473aba70d"
56
56
  }