@react-three/drei 9.74.11 → 9.74.13

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 (189) hide show
  1. package/core/CatmullRomLine.js +2 -0
  2. package/core/Cloud.js +3 -0
  3. package/core/CubeCamera.js +1 -0
  4. package/core/CubicBezierLine.js +2 -0
  5. package/core/Environment.js +1 -0
  6. package/core/Example.js +6 -0
  7. package/core/FaceControls.cjs.js +1 -1
  8. package/core/FaceControls.js +2 -0
  9. package/core/FaceLandmarker.cjs.js +1 -1
  10. package/core/FaceLandmarker.js +3 -2
  11. package/core/Facemesh.js +2 -0
  12. package/core/GizmoHelper.js +3 -0
  13. package/core/GizmoViewcube.js +4 -0
  14. package/core/GizmoViewport.js +4 -0
  15. package/core/Gltf.js +4 -0
  16. package/core/MeshDiscardMaterial.js +2 -0
  17. package/core/MeshDistortMaterial.js +2 -1
  18. package/core/MeshReflectorMaterial.js +1 -0
  19. package/core/MeshRefractionMaterial.js +2 -0
  20. package/core/MeshTransmissionMaterial.js +1 -0
  21. package/core/OrthographicCamera.js +1 -0
  22. package/core/PerspectiveCamera.js +1 -0
  23. package/core/QuadraticBezierLine.js +2 -0
  24. package/core/Reflector.js +1 -0
  25. package/core/SpotLight.js +2 -1
  26. package/core/Stage.js +7 -0
  27. package/core/Text3D.js +1 -0
  28. package/core/Wireframe.js +1 -0
  29. package/core/index.cjs.js +1 -1
  30. package/core/index.js +0 -1
  31. package/core/useKTX2.js +1 -0
  32. package/core/useMatcapTexture.js +2 -0
  33. package/core/useNormalTexture.js +1 -0
  34. package/index.cjs.js +1 -1
  35. package/materials/DiscardMaterial.js +1 -0
  36. package/materials/MeshRefractionMaterial.js +1 -1
  37. package/native/index.cjs.js +1 -1
  38. package/native/index.js +0 -1
  39. package/package.json +9 -9
  40. package/src/core/AccumulativeShadows.js +311 -0
  41. package/src/core/AdaptiveDpr.js +28 -0
  42. package/src/core/AdaptiveEvents.js +20 -0
  43. package/src/core/ArcballControls.js +67 -0
  44. package/src/core/AsciiRenderer.js +60 -0
  45. package/src/core/BBAnchor.js +37 -0
  46. package/src/core/Backdrop.js +36 -0
  47. package/src/core/BakeShadows.js +16 -0
  48. package/src/core/Billboard.js +41 -0
  49. package/src/core/Bounds.js +245 -0
  50. package/src/core/CameraControls.js +92 -0
  51. package/src/core/CameraShake.js +61 -0
  52. package/src/core/CatmullRomLine.js +44 -0
  53. package/src/core/Caustics.js +375 -0
  54. package/src/core/Center.js +66 -0
  55. package/src/core/Clone.js +102 -0
  56. package/src/core/Cloud.js +59 -0
  57. package/src/core/ComputedAttribute.js +34 -0
  58. package/src/core/ContactShadows.js +114 -0
  59. package/src/core/CubeCamera.js +43 -0
  60. package/src/core/CubicBezierLine.js +28 -0
  61. package/src/core/CurveModifier.js +34 -0
  62. package/src/core/Decal.js +92 -0
  63. package/src/core/Detailed.js +34 -0
  64. package/src/core/DeviceOrientationControls.js +51 -0
  65. package/src/core/Edges.js +36 -0
  66. package/src/core/Effects.js +93 -0
  67. package/src/core/Environment.js +132 -0
  68. package/src/core/Example.js +42 -0
  69. package/src/core/FaceControls.js +315 -0
  70. package/src/core/FaceLandmarker.js +43 -0
  71. package/src/core/Facemesh.js +4545 -0
  72. package/src/core/FirstPersonControls.js +38 -0
  73. package/src/core/Float.js +36 -0
  74. package/src/core/FlyControls.js +55 -0
  75. package/src/core/GizmoHelper.js +111 -0
  76. package/src/core/GizmoViewcube.js +152 -0
  77. package/src/core/GizmoViewport.js +152 -0
  78. package/src/core/Gltf.js +20 -0
  79. package/src/core/GradientTexture.js +33 -0
  80. package/src/core/Grid.js +112 -0
  81. package/src/core/Hud.js +58 -0
  82. package/src/core/Image.js +119 -0
  83. package/src/core/Instances.js +215 -0
  84. package/src/core/Lightformer.js +51 -0
  85. package/src/core/Line.js +68 -0
  86. package/src/core/MapControls.js +64 -0
  87. package/src/core/MarchingCubes.js +76 -0
  88. package/src/core/Mask.js +42 -0
  89. package/src/core/MeshDiscardMaterial.js +15 -0
  90. package/src/core/MeshDistortMaterial.js +79 -0
  91. package/src/core/MeshPortalMaterial.js +381 -0
  92. package/src/core/MeshReflectorMaterial.js +182 -0
  93. package/src/core/MeshRefractionMaterial.js +79 -0
  94. package/src/core/MeshTransmissionMaterial.js +395 -0
  95. package/src/core/MeshWobbleMaterial.js +65 -0
  96. package/src/core/OrbitControls.js +82 -0
  97. package/src/core/OrthographicCamera.js +77 -0
  98. package/src/core/PerformanceMonitor.js +121 -0
  99. package/src/core/PerspectiveCamera.js +73 -0
  100. package/src/core/PointMaterial.js +36 -0
  101. package/src/core/PointerLockControls.js +90 -0
  102. package/src/core/Points.js +227 -0
  103. package/src/core/PositionalAudio.js +51 -0
  104. package/src/core/Preload.js +45 -0
  105. package/src/core/QuadraticBezierLine.js +44 -0
  106. package/src/core/Reflector.js +182 -0
  107. package/src/core/RenderTexture.js +96 -0
  108. package/src/core/Resize.js +39 -0
  109. package/src/core/RoundedBox.js +52 -0
  110. package/src/core/Sampler.js +85 -0
  111. package/src/core/ScreenQuad.js +24 -0
  112. package/src/core/ScreenSpace.js +25 -0
  113. package/src/core/Segments.js +102 -0
  114. package/src/core/Shadow.js +42 -0
  115. package/src/core/Sky.js +39 -0
  116. package/src/core/Sparkles.js +139 -0
  117. package/src/core/SpotLight.js +231 -0
  118. package/src/core/SpriteAnimator.js +342 -0
  119. package/src/core/Stage.js +135 -0
  120. package/src/core/Stars.js +108 -0
  121. package/src/core/Stats.js +30 -0
  122. package/src/core/Svg.js +59 -0
  123. package/src/core/Text.js +58 -0
  124. package/src/core/Text3D.js +76 -0
  125. package/src/core/TrackballControls.js +72 -0
  126. package/src/core/Trail.js +161 -0
  127. package/src/core/TransformControls.js +106 -0
  128. package/src/core/Wireframe.js +185 -0
  129. package/src/core/meshBounds.js +38 -0
  130. package/src/core/shaderMaterial.js +39 -0
  131. package/src/core/shapes.js +68 -0
  132. package/src/core/softShadows.js +161 -0
  133. package/src/core/useAnimations.js +56 -0
  134. package/src/core/useAspect.js +10 -0
  135. package/src/core/useBVH.js +90 -0
  136. package/src/core/useBoxProjectedEnv.js +98 -0
  137. package/src/core/useCamera.js +27 -0
  138. package/src/core/useContextBridge.js +21 -0
  139. package/src/core/useCubeCamera.js +49 -0
  140. package/src/core/useCubeTexture.js +18 -0
  141. package/src/core/useDepthBuffer.js +38 -0
  142. package/src/core/useDetectGPU.js +6 -0
  143. package/src/core/useEnvironment.js +48 -0
  144. package/src/core/useFBO.js +53 -0
  145. package/src/core/useFBX.js +12 -0
  146. package/src/core/useFont.js +20 -0
  147. package/src/core/useGLTF.js +37 -0
  148. package/src/core/useHelper.js +31 -0
  149. package/src/core/useIntersect.js +39 -0
  150. package/src/core/useKTX2.js +38 -0
  151. package/src/core/useMatcapTexture.js +45 -0
  152. package/src/core/useNormalTexture.js +30 -0
  153. package/src/core/useProgress.js +50 -0
  154. package/src/core/useTexture.js +35 -0
  155. package/src/core/useTrailTexture.js +164 -0
  156. package/src/core/useVideoTexture.js +41 -0
  157. package/src/helpers/environment-assets.js +14 -0
  158. package/src/helpers/useEffectfulState.js +18 -0
  159. package/src/materials/BlurPass.js +75 -0
  160. package/src/materials/ConvolutionMaterial.js +99 -0
  161. package/src/materials/DiscardMaterial.js +5 -0
  162. package/src/materials/MeshReflectorMaterial.js +290 -0
  163. package/src/materials/MeshRefractionMaterial.js +171 -0
  164. package/src/materials/SpotLightMaterial.js +111 -0
  165. package/src/materials/WireframeMaterial.js +235 -0
  166. package/src/web/CycleRaycast.js +97 -0
  167. package/src/web/Html.js +417 -0
  168. package/src/web/KeyboardControls.js +101 -0
  169. package/src/web/Loader.js +98 -0
  170. package/src/web/PresentationControls.js +86 -0
  171. package/src/web/ScrollControls.js +246 -0
  172. package/src/web/Select.js +175 -0
  173. package/src/web/View.js +206 -0
  174. package/src/web/pivotControls/AxisArrow.js +202 -0
  175. package/src/web/pivotControls/AxisRotator.js +235 -0
  176. package/src/web/pivotControls/PlaneSlider.js +211 -0
  177. package/src/web/pivotControls/context.js +5 -0
  178. package/src/web/pivotControls/index.js +223 -0
  179. package/src/web/useCursor.js +12 -0
  180. package/web/Loader.js +2 -0
  181. package/web/index.cjs.js +1 -1
  182. package/web/index.js +0 -1
  183. package/web/pivotControls/AxisArrow.js +3 -0
  184. package/web/pivotControls/AxisRotator.js +3 -0
  185. package/web/pivotControls/PlaneSlider.js +3 -0
  186. package/web/pivotControls/index.js +5 -0
  187. /package/{helpers → src/helpers}/glsl/DefaultSpotlightShadowShadows.glsl.js +0 -0
  188. /package/{helpers → src/helpers}/glsl/distort.vert.glsl.js +0 -0
  189. /package/{index.js → src/index.js} +0 -0
@@ -0,0 +1,231 @@
1
+ import _extends from '@babel/runtime/helpers/esm/extends';
2
+ import * as React from 'react';
3
+ import { Vector3, CylinderGeometry, Matrix4, WebGLRenderTarget, RGBAFormat, LinearEncoding, ShaderMaterial, DoubleSide, RepeatWrapping } from 'three';
4
+ import { useThree, useFrame } from '@react-three/fiber';
5
+ import { FullScreenQuad } from 'three-stdlib';
6
+ import mergeRefs from 'react-merge-refs';
7
+ import { SpotLightMaterial } from '../materials/SpotLightMaterial.js';
8
+ import SpotlightShadowShader from '../helpers/glsl/DefaultSpotlightShadowShadows.glsl.js';
9
+
10
+ const isSpotLight = child => {
11
+ return child == null ? void 0 : child.isSpotLight;
12
+ };
13
+
14
+ function VolumetricMesh({
15
+ opacity = 1,
16
+ radiusTop,
17
+ radiusBottom,
18
+ depthBuffer,
19
+ color = 'white',
20
+ distance = 5,
21
+ angle = 0.15,
22
+ attenuation = 5,
23
+ anglePower = 5
24
+ }) {
25
+ const mesh = React.useRef(null);
26
+ const size = useThree(state => state.size);
27
+ const camera = useThree(state => state.camera);
28
+ const dpr = useThree(state => state.viewport.dpr);
29
+ const [material] = React.useState(() => new SpotLightMaterial());
30
+ const [vec] = React.useState(() => new Vector3());
31
+ radiusTop = radiusTop === undefined ? 0.1 : radiusTop;
32
+ radiusBottom = radiusBottom === undefined ? angle * 7 : radiusBottom;
33
+ useFrame(() => {
34
+ material.uniforms.spotPosition.value.copy(mesh.current.getWorldPosition(vec));
35
+ mesh.current.lookAt(mesh.current.parent.target.getWorldPosition(vec));
36
+ });
37
+ const geom = React.useMemo(() => {
38
+ const geometry = new CylinderGeometry(radiusTop, radiusBottom, distance, 128, 64, true);
39
+ geometry.applyMatrix4(new Matrix4().makeTranslation(0, -distance / 2, 0));
40
+ geometry.applyMatrix4(new Matrix4().makeRotationX(-Math.PI / 2));
41
+ return geometry;
42
+ }, [distance, radiusTop, radiusBottom]);
43
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("mesh", {
44
+ ref: mesh,
45
+ geometry: geom,
46
+ raycast: () => null
47
+ }, /*#__PURE__*/React.createElement("primitive", {
48
+ object: material,
49
+ attach: "material",
50
+ "uniforms-opacity-value": opacity,
51
+ "uniforms-lightColor-value": color,
52
+ "uniforms-attenuation-value": attenuation,
53
+ "uniforms-anglePower-value": anglePower,
54
+ "uniforms-depth-value": depthBuffer,
55
+ "uniforms-cameraNear-value": camera.near,
56
+ "uniforms-cameraFar-value": camera.far,
57
+ "uniforms-resolution-value": depthBuffer ? [size.width * dpr, size.height * dpr] : [0, 0]
58
+ })));
59
+ }
60
+
61
+ function useCommon(spotlight, mesh, width, height, distance) {
62
+ const [[pos, dir]] = React.useState(() => [new Vector3(), new Vector3()]);
63
+ React.useLayoutEffect(() => {
64
+ if (isSpotLight(spotlight.current)) {
65
+ spotlight.current.shadow.mapSize.set(width, height);
66
+ spotlight.current.shadow.needsUpdate = true;
67
+ } else {
68
+ throw new Error('SpotlightShadow must be a child of a SpotLight');
69
+ }
70
+ }, [spotlight, width, height]);
71
+ useFrame(() => {
72
+ if (!spotlight.current) return;
73
+ const A = spotlight.current.position;
74
+ const B = spotlight.current.target.position;
75
+ dir.copy(B).sub(A);
76
+ var len = dir.length();
77
+ dir.normalize().multiplyScalar(len * distance);
78
+ pos.copy(A).add(dir);
79
+ mesh.current.position.copy(pos);
80
+ mesh.current.lookAt(spotlight.current.target.position);
81
+ });
82
+ }
83
+
84
+ function SpotlightShadowWithShader({
85
+ distance = 0.4,
86
+ alphaTest = 0.5,
87
+ map,
88
+ shader = SpotlightShadowShader,
89
+ width = 512,
90
+ height = 512,
91
+ scale = 1,
92
+ children,
93
+ ...rest
94
+ }) {
95
+ const mesh = React.useRef(null);
96
+ const spotlight = rest.spotlightRef;
97
+ const debug = rest.debug;
98
+ useCommon(spotlight, mesh, width, height, distance);
99
+ const renderTarget = React.useMemo(() => new WebGLRenderTarget(width, height, {
100
+ format: RGBAFormat,
101
+ encoding: LinearEncoding,
102
+ stencilBuffer: false // depthTexture: null!
103
+
104
+ }), [width, height]);
105
+ const uniforms = React.useRef({
106
+ uShadowMap: {
107
+ value: map
108
+ },
109
+ uTime: {
110
+ value: 0
111
+ }
112
+ });
113
+ React.useEffect(() => void (uniforms.current.uShadowMap.value = map), [map]);
114
+ const fsQuad = React.useMemo(() => new FullScreenQuad(new ShaderMaterial({
115
+ uniforms: uniforms.current,
116
+ vertexShader:
117
+ /* glsl */
118
+ `
119
+ varying vec2 vUv;
120
+
121
+ void main() {
122
+ vUv = uv;
123
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
124
+ }
125
+ `,
126
+ fragmentShader: shader
127
+ })), [shader]);
128
+ React.useEffect(() => () => {
129
+ fsQuad.material.dispose();
130
+ fsQuad.dispose();
131
+ }, [fsQuad]);
132
+ React.useEffect(() => () => renderTarget.dispose(), [renderTarget]);
133
+ useFrame(({
134
+ gl
135
+ }, dt) => {
136
+ uniforms.current.uTime.value += dt;
137
+ gl.setRenderTarget(renderTarget);
138
+ fsQuad.render(gl);
139
+ gl.setRenderTarget(null);
140
+ });
141
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("mesh", {
142
+ ref: mesh,
143
+ scale: scale,
144
+ castShadow: true
145
+ }, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("meshBasicMaterial", {
146
+ transparent: true,
147
+ side: DoubleSide,
148
+ alphaTest: alphaTest,
149
+ alphaMap: renderTarget.texture,
150
+ "alphaMap-wrapS": RepeatWrapping,
151
+ "alphaMap-wrapT": RepeatWrapping,
152
+ opacity: debug ? 1 : 0
153
+ }, children)));
154
+ }
155
+
156
+ function SpotlightShadowWithoutShader({
157
+ distance = 0.4,
158
+ alphaTest = 0.5,
159
+ map,
160
+ width = 512,
161
+ height = 512,
162
+ scale,
163
+ children,
164
+ ...rest
165
+ }) {
166
+ const mesh = React.useRef(null);
167
+ const spotlight = rest.spotlightRef;
168
+ const debug = rest.debug;
169
+ useCommon(spotlight, mesh, width, height, distance);
170
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("mesh", {
171
+ ref: mesh,
172
+ scale: scale,
173
+ castShadow: true
174
+ }, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("meshBasicMaterial", {
175
+ transparent: true,
176
+ side: DoubleSide,
177
+ alphaTest: alphaTest,
178
+ alphaMap: map,
179
+ "alphaMap-wrapS": RepeatWrapping,
180
+ "alphaMap-wrapT": RepeatWrapping,
181
+ opacity: debug ? 1 : 0
182
+ }, children)));
183
+ }
184
+
185
+ function SpotLightShadow(props) {
186
+ if (props.shader) return /*#__PURE__*/React.createElement(SpotlightShadowWithShader, props);
187
+ return /*#__PURE__*/React.createElement(SpotlightShadowWithoutShader, props);
188
+ }
189
+ const SpotLight = /*#__PURE__*/React.forwardRef(({
190
+ // Volumetric
191
+ opacity = 1,
192
+ radiusTop,
193
+ radiusBottom,
194
+ depthBuffer,
195
+ color = 'white',
196
+ distance = 5,
197
+ angle = 0.15,
198
+ attenuation = 5,
199
+ anglePower = 5,
200
+ volumetric = true,
201
+ debug = false,
202
+ children,
203
+ ...props
204
+ }, ref) => {
205
+ const spotlight = React.useRef(null);
206
+ return /*#__PURE__*/React.createElement("group", null, debug && spotlight.current && /*#__PURE__*/React.createElement("spotLightHelper", {
207
+ args: [spotlight.current]
208
+ }), /*#__PURE__*/React.createElement("spotLight", _extends({
209
+ ref: mergeRefs([ref, spotlight]),
210
+ angle: angle,
211
+ color: color,
212
+ distance: distance,
213
+ castShadow: true
214
+ }, props), volumetric && /*#__PURE__*/React.createElement(VolumetricMesh, {
215
+ debug: debug,
216
+ opacity: opacity,
217
+ radiusTop: radiusTop,
218
+ radiusBottom: radiusBottom,
219
+ depthBuffer: depthBuffer,
220
+ color: color,
221
+ distance: distance,
222
+ angle: angle,
223
+ attenuation: attenuation,
224
+ anglePower: anglePower
225
+ })), children && /*#__PURE__*/React.cloneElement(children, {
226
+ spotlightRef: spotlight,
227
+ debug: debug
228
+ }));
229
+ });
230
+
231
+ export { SpotLight, SpotLightShadow };
@@ -0,0 +1,342 @@
1
+ import * as React from 'react';
2
+ import { useThree, useFrame } from '@react-three/fiber';
3
+ import * as THREE from 'three';
4
+
5
+ const SpriteAnimator = ({
6
+ startFrame,
7
+ endFrame,
8
+ fps,
9
+ frameName,
10
+ textureDataURL,
11
+ textureImageURL,
12
+ loop,
13
+ numberOfFrames,
14
+ autoPlay,
15
+ animationNames,
16
+ onStart,
17
+ onEnd,
18
+ onLoopEnd,
19
+ onFrame,
20
+ play,
21
+ pause,
22
+ flipX,
23
+ alphaTest,
24
+ children,
25
+ ...props
26
+ }, fref) => {
27
+ useThree(state => state.viewport);
28
+ const spriteData = React.useRef(null);
29
+ const [isJsonReady, setJsonReady] = React.useState(false);
30
+ const matRef = React.useRef();
31
+ const spriteRef = React.useRef();
32
+ const timerOffset = React.useRef(window.performance.now());
33
+ const textureData = React.useRef();
34
+ const currentFrame = React.useRef(startFrame || 0);
35
+ const currentFrameName = React.useRef(frameName || '');
36
+ const fpsInterval = 1000 / (fps || 30);
37
+ const [spriteTexture, setSpriteTexture] = React.useState(new THREE.Texture());
38
+ const totalFrames = React.useRef(0);
39
+ const [aspect, setAspect] = React.useState([1, 1, 1]);
40
+ const flipOffset = flipX ? -1 : 1;
41
+
42
+ function loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, callback) {
43
+ const textureLoader = new THREE.TextureLoader();
44
+ const jsonPromise = fetch(jsonUrl).then(response => response.json());
45
+ const texturePromise = new Promise(resolve => {
46
+ textureLoader.load(textureUrl, resolve);
47
+ });
48
+ Promise.all([jsonPromise, texturePromise]).then(response => {
49
+ callback(response[0], response[1]);
50
+ });
51
+ }
52
+
53
+ const calculateAspectRatio = (width, height) => {
54
+ const aspectRatio = height / width;
55
+ spriteRef.current.scale.set(1, aspectRatio, 1);
56
+ return [1, aspectRatio, 1];
57
+ }; // initial loads
58
+
59
+
60
+ React.useEffect(() => {
61
+ if (textureDataURL && textureImageURL) {
62
+ loadJsonAndTextureAndExecuteCallback(textureDataURL, textureImageURL, parseSpriteData);
63
+ } else if (textureImageURL) {
64
+ // only load the texture, this is an image sprite only
65
+ const textureLoader = new THREE.TextureLoader();
66
+ new Promise(resolve => {
67
+ textureLoader.load(textureImageURL, resolve);
68
+ }).then(texture => {
69
+ parseSpriteData(null, texture);
70
+ });
71
+ }
72
+ }, []);
73
+ React.useLayoutEffect(() => {
74
+ modifySpritePosition();
75
+ }, [spriteTexture]);
76
+ React.useEffect(() => {
77
+ }, [pause]);
78
+ React.useEffect(() => {
79
+ if (currentFrameName.current !== frameName && frameName) {
80
+ currentFrame.current = 0;
81
+ currentFrameName.current = frameName;
82
+ }
83
+ }, [frameName]);
84
+
85
+ const parseSpriteData = (json, _spriteTexture) => {
86
+ // sprite only case
87
+ if (json === null) {
88
+ if (_spriteTexture && numberOfFrames) {
89
+ //get size from texture
90
+ const width = _spriteTexture.image.width;
91
+ const height = _spriteTexture.image.height;
92
+ const frameWidth = width / numberOfFrames;
93
+ const frameHeight = height;
94
+ textureData.current = _spriteTexture;
95
+ totalFrames.current = numberOfFrames;
96
+ spriteData.current = {
97
+ frames: [],
98
+ meta: {
99
+ version: '1.0',
100
+ size: {
101
+ w: width,
102
+ h: height
103
+ },
104
+ scale: '1'
105
+ }
106
+ };
107
+
108
+ if (parseInt(frameWidth.toString(), 10) === frameWidth) {
109
+ // if it fits
110
+ for (let i = 0; i < numberOfFrames; i++) {
111
+ spriteData.current.frames.push({
112
+ frame: {
113
+ x: i * frameWidth,
114
+ y: 0,
115
+ w: frameWidth,
116
+ h: frameHeight
117
+ },
118
+ rotated: false,
119
+ trimmed: false,
120
+ spriteSourceSize: {
121
+ x: 0,
122
+ y: 0,
123
+ w: frameWidth,
124
+ h: frameHeight
125
+ },
126
+ sourceSize: {
127
+ w: frameWidth,
128
+ h: height
129
+ }
130
+ });
131
+ }
132
+ }
133
+ }
134
+ } else if (_spriteTexture) {
135
+ spriteData.current = json;
136
+ spriteData.current.frames = Array.isArray(json.frames) ? json.frames : parseFrames();
137
+ totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
138
+ textureData.current = _spriteTexture;
139
+ const {
140
+ w,
141
+ h
142
+ } = getFirstItem(json.frames).sourceSize;
143
+ const aspect = calculateAspectRatio(w, h);
144
+ setAspect(aspect);
145
+
146
+ if (matRef.current) {
147
+ matRef.current.map = _spriteTexture;
148
+ }
149
+ }
150
+
151
+ _spriteTexture.premultiplyAlpha = false;
152
+ setSpriteTexture(_spriteTexture);
153
+ }; // for frame based JSON Hash sprite data
154
+
155
+
156
+ const parseFrames = () => {
157
+ const sprites = {};
158
+ const data = spriteData.current;
159
+ const delimiters = animationNames;
160
+
161
+ if (delimiters) {
162
+ for (let i = 0; i < delimiters.length; i++) {
163
+ sprites[delimiters[i]] = [];
164
+
165
+ for (let innerKey in data['frames']) {
166
+ const value = data['frames'][innerKey];
167
+ const frameData = value['frame'];
168
+ const x = frameData['x'];
169
+ const y = frameData['y'];
170
+ const width = frameData['w'];
171
+ const height = frameData['h'];
172
+ const sourceWidth = value['sourceSize']['w'];
173
+ const sourceHeight = value['sourceSize']['h'];
174
+
175
+ if (typeof innerKey === 'string' && innerKey.toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
176
+ sprites[delimiters[i]].push({
177
+ x: x,
178
+ y: y,
179
+ w: width,
180
+ h: height,
181
+ frame: frameData,
182
+ sourceSize: {
183
+ w: sourceWidth,
184
+ h: sourceHeight
185
+ }
186
+ });
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ return sprites;
193
+ }; // modify the sprite material after json is parsed and state updated
194
+
195
+
196
+ const modifySpritePosition = () => {
197
+ if (!spriteData.current) return;
198
+ const {
199
+ meta: {
200
+ size: metaInfo
201
+ },
202
+ frames
203
+ } = spriteData.current;
204
+ const {
205
+ w: frameW,
206
+ h: frameH
207
+ } = Array.isArray(frames) ? frames[0].sourceSize : frameName ? frames[frameName] ? frames[frameName][0].sourceSize : {
208
+ w: 0,
209
+ h: 0
210
+ } : {
211
+ w: 0,
212
+ h: 0
213
+ };
214
+ matRef.current.map.wrapS = matRef.current.map.wrapT = THREE.RepeatWrapping;
215
+ matRef.current.map.center.set(0, 0);
216
+ matRef.current.map.repeat.set(1 * flipOffset / (metaInfo.w / frameW), 1 / (metaInfo.h / frameH)); //const framesH = (metaInfo.w - 1) / frameW
217
+
218
+ const framesV = (metaInfo.h - 1) / frameH;
219
+ const frameOffsetY = 1 / framesV;
220
+ matRef.current.map.offset.x = 0.0; //-matRef.current.map.repeat.x
221
+
222
+ matRef.current.map.offset.y = 1 - frameOffsetY;
223
+ setJsonReady(true);
224
+ if (onStart) onStart({
225
+ currentFrameName: frameName,
226
+ currentFrame: currentFrame.current
227
+ });
228
+ }; // run the animation on each frame
229
+
230
+
231
+ const runAnimation = () => {
232
+ //if (!frameName) return
233
+ const now = window.performance.now();
234
+ const diff = now - timerOffset.current;
235
+ const {
236
+ meta: {
237
+ size: metaInfo
238
+ },
239
+ frames
240
+ } = spriteData.current;
241
+ const {
242
+ w: frameW,
243
+ h: frameH
244
+ } = getFirstItem(frames).sourceSize;
245
+ const spriteFrames = Array.isArray(frames) ? frames : frameName ? frames[frameName] : [];
246
+ let finalValX = 0;
247
+ let finalValY = 0;
248
+
249
+ const _endFrame = endFrame || spriteFrames.length - 1;
250
+
251
+ if (currentFrame.current > _endFrame) {
252
+ currentFrame.current = loop ? startFrame !== null && startFrame !== void 0 ? startFrame : 0 : 0;
253
+
254
+ if (loop) {
255
+ onLoopEnd == null ? void 0 : onLoopEnd({
256
+ currentFrameName: frameName,
257
+ currentFrame: currentFrame.current
258
+ });
259
+ } else {
260
+ onEnd == null ? void 0 : onEnd({
261
+ currentFrameName: frameName,
262
+ currentFrame: currentFrame.current
263
+ });
264
+ }
265
+
266
+ if (!loop) return;
267
+ }
268
+
269
+ if (diff <= fpsInterval) return;
270
+ timerOffset.current = now - diff % fpsInterval;
271
+ calculateAspectRatio(frameW, frameH);
272
+ const framesH = (metaInfo.w - 1) / frameW;
273
+ const framesV = (metaInfo.h - 1) / frameH;
274
+ const {
275
+ frame: {
276
+ x: frameX,
277
+ y: frameY
278
+ },
279
+ sourceSize: {
280
+ w: originalSizeX,
281
+ h: originalSizeY
282
+ }
283
+ } = spriteFrames[currentFrame.current];
284
+ const frameOffsetX = 1 / framesH;
285
+ const frameOffsetY = 1 / framesV;
286
+ finalValX = flipOffset > 0 ? frameOffsetX * (frameX / originalSizeX) : frameOffsetX * (frameX / originalSizeX) - matRef.current.map.repeat.x;
287
+ finalValY = Math.abs(1 - frameOffsetY) - frameOffsetY * (frameY / originalSizeY);
288
+ matRef.current.map.offset.x = finalValX;
289
+ matRef.current.map.offset.y = finalValY;
290
+ currentFrame.current += 1;
291
+ }; // *** Warning! It runs on every frame! ***
292
+
293
+
294
+ useFrame((state, delta) => {
295
+ var _spriteData$current, _matRef$current;
296
+
297
+ if (!((_spriteData$current = spriteData.current) != null && _spriteData$current.frames) || !((_matRef$current = matRef.current) != null && _matRef$current.map)) {
298
+ return;
299
+ }
300
+
301
+ if (pause) {
302
+ return;
303
+ }
304
+
305
+ if (autoPlay || play) {
306
+ runAnimation();
307
+ onFrame && onFrame({
308
+ currentFrameName: currentFrameName.current,
309
+ currentFrame: currentFrame.current
310
+ });
311
+ }
312
+ }); // utils
313
+
314
+ const getFirstItem = param => {
315
+ if (Array.isArray(param)) {
316
+ return param[0];
317
+ } else if (typeof param === 'object' && param !== null) {
318
+ const keys = Object.keys(param);
319
+ return param[keys[0]][0];
320
+ } else {
321
+ return {
322
+ w: 0,
323
+ h: 0
324
+ };
325
+ }
326
+ };
327
+
328
+ return /*#__PURE__*/React.createElement("group", props, /*#__PURE__*/React.createElement(React.Suspense, {
329
+ fallback: null
330
+ }, /*#__PURE__*/React.createElement("sprite", {
331
+ ref: spriteRef,
332
+ scale: aspect
333
+ }, /*#__PURE__*/React.createElement("spriteMaterial", {
334
+ toneMapped: false,
335
+ ref: matRef,
336
+ map: spriteTexture,
337
+ transparent: true,
338
+ alphaTest: alphaTest !== null && alphaTest !== void 0 ? alphaTest : 0.0
339
+ }))), children);
340
+ };
341
+
342
+ export { SpriteAnimator };
@@ -0,0 +1,135 @@
1
+ import _extends from '@babel/runtime/helpers/esm/extends';
2
+ import * as React from 'react';
3
+ import { Environment } from './Environment.js';
4
+ import { ContactShadows } from './ContactShadows.js';
5
+ import { Center } from './Center.js';
6
+ import { AccumulativeShadows, RandomizedLight } from './AccumulativeShadows.js';
7
+ import { Bounds, useBounds } from './Bounds.js';
8
+
9
+ const presets = {
10
+ rembrandt: {
11
+ main: [1, 2, 1],
12
+ fill: [-2, -0.5, -2]
13
+ },
14
+ portrait: {
15
+ main: [-1, 2, 0.5],
16
+ fill: [-1, 0.5, -1.5]
17
+ },
18
+ upfront: {
19
+ main: [0, 2, 1],
20
+ fill: [-1, 0.5, -1.5]
21
+ },
22
+ soft: {
23
+ main: [-2, 4, 4],
24
+ fill: [-1, 0.5, -1.5]
25
+ }
26
+ };
27
+
28
+ function Refit({
29
+ radius,
30
+ adjustCamera
31
+ }) {
32
+ const api = useBounds();
33
+ React.useEffect(() => {
34
+ if (adjustCamera) api.refresh().clip().fit();
35
+ }, [radius, adjustCamera]);
36
+ return null;
37
+ }
38
+
39
+ function Stage({
40
+ children,
41
+ center,
42
+ adjustCamera = true,
43
+ intensity = 0.5,
44
+ shadows = 'contact',
45
+ environment = 'city',
46
+ preset = 'rembrandt',
47
+ ...props
48
+ }) {
49
+ var _bias, _normalBias, _size, _offset, _amount, _radius, _ambient, _intensity;
50
+
51
+ const config = typeof preset === 'string' ? presets[preset] : preset;
52
+ const [{
53
+ radius,
54
+ height
55
+ }, set] = React.useState({
56
+ radius: 0,
57
+ width: 0,
58
+ height: 0,
59
+ depth: 0
60
+ });
61
+ const shadowBias = (_bias = shadows == null ? void 0 : shadows.bias) !== null && _bias !== void 0 ? _bias : -0.0001;
62
+ const normalBias = (_normalBias = shadows == null ? void 0 : shadows.normalBias) !== null && _normalBias !== void 0 ? _normalBias : 0;
63
+ const shadowSize = (_size = shadows == null ? void 0 : shadows.size) !== null && _size !== void 0 ? _size : 1024;
64
+ const shadowOffset = (_offset = shadows == null ? void 0 : shadows.offset) !== null && _offset !== void 0 ? _offset : 0;
65
+ const contactShadow = shadows === 'contact' || (shadows == null ? void 0 : shadows.type) === 'contact';
66
+ const accumulativeShadow = shadows === 'accumulative' || (shadows == null ? void 0 : shadows.type) === 'accumulative';
67
+ const shadowSpread = { ...(typeof shadows === 'object' ? shadows : {})
68
+ };
69
+ const environmentProps = !environment ? null : typeof environment === 'string' ? {
70
+ preset: environment
71
+ } : environment;
72
+ const onCentered = React.useCallback(props => {
73
+ const {
74
+ width,
75
+ height,
76
+ depth,
77
+ boundingSphere
78
+ } = props;
79
+ set({
80
+ radius: boundingSphere.radius,
81
+ width,
82
+ height,
83
+ depth
84
+ });
85
+ if (center != null && center.onCentered) center.onCentered(props);
86
+ }, []);
87
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("ambientLight", {
88
+ intensity: intensity / 3
89
+ }), /*#__PURE__*/React.createElement("spotLight", {
90
+ penumbra: 1,
91
+ position: [config.main[0] * radius, config.main[1] * radius, config.main[2] * radius],
92
+ intensity: intensity * 2,
93
+ castShadow: !!shadows,
94
+ "shadow-bias": shadowBias,
95
+ "shadow-normalBias": normalBias,
96
+ "shadow-mapSize": shadowSize
97
+ }), /*#__PURE__*/React.createElement("pointLight", {
98
+ position: [config.fill[0] * radius, config.fill[1] * radius, config.fill[2] * radius],
99
+ intensity: intensity
100
+ }), /*#__PURE__*/React.createElement(Bounds, _extends({
101
+ fit: !!adjustCamera,
102
+ clip: !!adjustCamera,
103
+ margin: Number(adjustCamera),
104
+ observe: true
105
+ }, props), /*#__PURE__*/React.createElement(Refit, {
106
+ radius: radius,
107
+ adjustCamera: adjustCamera
108
+ }), /*#__PURE__*/React.createElement(Center, _extends({}, center, {
109
+ position: [0, shadowOffset / 2, 0],
110
+ onCentered: onCentered
111
+ }), children)), /*#__PURE__*/React.createElement("group", {
112
+ position: [0, -height / 2 - shadowOffset / 2, 0]
113
+ }, contactShadow && /*#__PURE__*/React.createElement(ContactShadows, _extends({
114
+ scale: radius * 4,
115
+ far: radius,
116
+ blur: 2
117
+ }, shadowSpread)), accumulativeShadow && /*#__PURE__*/React.createElement(AccumulativeShadows, _extends({
118
+ temporal: true,
119
+ frames: 100,
120
+ alphaTest: 0.9,
121
+ toneMapped: true,
122
+ scale: radius * 4
123
+ }, shadowSpread), /*#__PURE__*/React.createElement(RandomizedLight, {
124
+ amount: (_amount = shadowSpread.amount) !== null && _amount !== void 0 ? _amount : 8,
125
+ radius: (_radius = shadowSpread.radius) !== null && _radius !== void 0 ? _radius : radius,
126
+ ambient: (_ambient = shadowSpread.ambient) !== null && _ambient !== void 0 ? _ambient : 0.5,
127
+ intensity: (_intensity = shadowSpread.intensity) !== null && _intensity !== void 0 ? _intensity : 1,
128
+ position: [config.main[0] * radius, config.main[1] * radius, config.main[2] * radius],
129
+ size: radius * 4,
130
+ bias: -shadowBias,
131
+ mapSize: shadowSize
132
+ }))), environment && /*#__PURE__*/React.createElement(Environment, environmentProps));
133
+ }
134
+
135
+ export { Stage };