@react-three/drei 9.116.2 → 9.117.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/SpriteAnimator.cjs.js +1 -1
- package/core/SpriteAnimator.d.ts +25 -18
- package/core/SpriteAnimator.js +147 -193
- package/core/Text3D.d.ts +2 -2
- package/core/index.cjs.js +1 -1
- package/core/index.js +1 -1
- package/core/useFont.cjs.js +1 -1
- package/core/useFont.js +24 -6
- package/core/useSpriteLoader.cjs.js +1 -1
- package/core/useSpriteLoader.d.ts +50 -3
- package/core/useSpriteLoader.js +295 -263
- package/index.cjs.js +1 -1
- package/index.js +1 -1
- package/native/index.cjs.js +1 -1
- package/native/index.js +1 -1
- package/package.json +1 -1
- package/web/index.cjs.js +1 -1
- package/web/index.js +1 -1
package/core/useSpriteLoader.js
CHANGED
|
@@ -4,18 +4,14 @@ import { useThree, useLoader } from '@react-three/fiber';
|
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { useState } from 'react';
|
|
6
6
|
|
|
7
|
+
/* eslint react-hooks/exhaustive-deps: 1 */
|
|
7
8
|
// utils
|
|
8
|
-
const
|
|
9
|
-
if (Array.isArray(
|
|
10
|
-
return
|
|
11
|
-
} else if (typeof param === 'object' && param !== null) {
|
|
12
|
-
const keys = Object.keys(param);
|
|
13
|
-
return param[keys[0]][0];
|
|
9
|
+
const getFirstFrame = (frames, frameName) => {
|
|
10
|
+
if (Array.isArray(frames)) {
|
|
11
|
+
return frames[0];
|
|
14
12
|
} else {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
h: 0
|
|
18
|
-
};
|
|
13
|
+
const k = frameName !== null && frameName !== void 0 ? frameName : Object.keys(frames)[0];
|
|
14
|
+
return frames[k][0];
|
|
19
15
|
}
|
|
20
16
|
};
|
|
21
17
|
const checkIfFrameIsEmpty = frameData => {
|
|
@@ -26,166 +22,42 @@ const checkIfFrameIsEmpty = frameData => {
|
|
|
26
22
|
}
|
|
27
23
|
return true;
|
|
28
24
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let finalMaxScaleH = Math.min(currentMaxScale, scaleY);
|
|
38
|
-
|
|
39
|
-
// Ensure that scaleX and scaleY do not exceed the max scale while maintaining aspect ratio
|
|
40
|
-
if (scaleX > currentMaxScale) {
|
|
41
|
-
finalMaxScaleW = currentMaxScale;
|
|
42
|
-
finalMaxScaleH = scaleY / scaleX * currentMaxScale;
|
|
43
|
-
}
|
|
44
|
-
return new THREE.Vector3(finalMaxScaleW, finalMaxScaleH, 1);
|
|
45
|
-
};
|
|
46
|
-
function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, canvasRenderingContext2DSettings) {
|
|
47
|
-
const v = useThree(state => state.viewport);
|
|
25
|
+
function useSpriteLoader(/** The URL of the sprite sheet. */
|
|
26
|
+
input, /** The JSON data of the sprite sheet. */
|
|
27
|
+
json, /** The names of the animations in the sprite sheet. */
|
|
28
|
+
animationNames, /** The number of frames in the sprite sheet. */
|
|
29
|
+
numberOfFrames, /** A callback that is called when the sprite sheet is loaded. */
|
|
30
|
+
onLoad, /** The settings to use when creating the 2D context. */
|
|
31
|
+
canvasRenderingContext2DSettings) {
|
|
32
|
+
const viewportRef = React.useRef(useThree(state => state.viewport));
|
|
48
33
|
const spriteDataRef = React.useRef(null);
|
|
49
34
|
const totalFrames = React.useRef(0);
|
|
50
35
|
const aspectFactor = 0.1;
|
|
36
|
+
const inputRef = React.useRef(input);
|
|
37
|
+
const jsonRef = React.useRef(json);
|
|
38
|
+
const animationFramesRef = React.useRef(animationNames);
|
|
51
39
|
const [spriteData, setSpriteData] = useState(null);
|
|
52
40
|
const [spriteTexture, setSpriteTexture] = React.useState(new THREE.Texture());
|
|
53
|
-
const textureLoader = new THREE.TextureLoader();
|
|
41
|
+
const textureLoader = React.useMemo(() => new THREE.TextureLoader(), []);
|
|
54
42
|
const [spriteObj, setSpriteObj] = useState(null);
|
|
55
|
-
React.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
useLoader.clear(TextureLoader, input);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}, []);
|
|
68
|
-
function loadJsonAndTexture(textureUrl, jsonUrl) {
|
|
69
|
-
if (jsonUrl && textureUrl) {
|
|
70
|
-
loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, parseSpriteData);
|
|
71
|
-
} else {
|
|
72
|
-
loadStandaloneSprite(textureUrl);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function loadStandaloneSprite(textureUrl) {
|
|
76
|
-
if (!textureUrl && !input) {
|
|
77
|
-
throw new Error('Either textureUrl or input must be provided');
|
|
78
|
-
}
|
|
79
|
-
const validUrl = textureUrl !== null && textureUrl !== void 0 ? textureUrl : input;
|
|
80
|
-
if (!validUrl) {
|
|
81
|
-
throw new Error('A valid texture URL must be provided');
|
|
82
|
-
}
|
|
83
|
-
new Promise(resolve => {
|
|
84
|
-
textureLoader.load(validUrl, resolve);
|
|
85
|
-
}).then(texture => {
|
|
86
|
-
parseSpriteData(null, texture);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
*
|
|
92
|
-
*/
|
|
93
|
-
function loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, callback) {
|
|
94
|
-
const jsonPromise = fetch(jsonUrl).then(response => response.json());
|
|
95
|
-
const texturePromise = new Promise(resolve => {
|
|
96
|
-
textureLoader.load(textureUrl, resolve);
|
|
97
|
-
});
|
|
98
|
-
Promise.all([jsonPromise, texturePromise]).then(response => {
|
|
99
|
-
callback(response[0], response[1]);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
const parseSpriteData = (json, _spriteTexture) => {
|
|
103
|
-
let aspect = new THREE.Vector3(1, 1, 1);
|
|
104
|
-
// sprite only case
|
|
105
|
-
if (json === null) {
|
|
106
|
-
if (_spriteTexture && numberOfFrames) {
|
|
107
|
-
//get size from texture
|
|
108
|
-
const width = _spriteTexture.image.width;
|
|
109
|
-
const height = _spriteTexture.image.height;
|
|
110
|
-
totalFrames.current = numberOfFrames;
|
|
111
|
-
const {
|
|
112
|
-
rows,
|
|
113
|
-
columns,
|
|
114
|
-
frameWidth,
|
|
115
|
-
frameHeight,
|
|
116
|
-
emptyFrames
|
|
117
|
-
} = getRowsAndColumns(_spriteTexture, numberOfFrames);
|
|
118
|
-
spriteDataRef.current = {
|
|
119
|
-
frames: [],
|
|
120
|
-
meta: {
|
|
121
|
-
version: '1.0',
|
|
122
|
-
size: {
|
|
123
|
-
w: width,
|
|
124
|
-
h: height
|
|
125
|
-
},
|
|
126
|
-
rows,
|
|
127
|
-
columns,
|
|
128
|
-
frameWidth,
|
|
129
|
-
frameHeight,
|
|
130
|
-
scale: '1'
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
for (let row = 0; row < rows; row++) {
|
|
134
|
-
for (let col = 0; col < columns; col++) {
|
|
135
|
-
const isExcluded = (emptyFrames !== null && emptyFrames !== void 0 ? emptyFrames : []).some(coord => coord.row === row && coord.col === col);
|
|
136
|
-
if (isExcluded) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
spriteDataRef.current.frames.push({
|
|
140
|
-
frame: {
|
|
141
|
-
x: col * frameWidth,
|
|
142
|
-
y: row * frameHeight,
|
|
143
|
-
w: frameWidth,
|
|
144
|
-
h: frameHeight
|
|
145
|
-
},
|
|
146
|
-
rotated: false,
|
|
147
|
-
trimmed: false,
|
|
148
|
-
spriteSourceSize: {
|
|
149
|
-
x: 0,
|
|
150
|
-
y: 0,
|
|
151
|
-
w: frameWidth,
|
|
152
|
-
h: frameHeight
|
|
153
|
-
},
|
|
154
|
-
sourceSize: {
|
|
155
|
-
w: frameWidth,
|
|
156
|
-
h: frameHeight
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
aspect = calculateAspectRatio(frameWidth, frameHeight, aspectFactor, v);
|
|
162
|
-
}
|
|
43
|
+
const calculateAspectRatio = React.useCallback((width, height, factor) => {
|
|
44
|
+
const adaptedHeight = height * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height);
|
|
45
|
+
const adaptedWidth = width * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height);
|
|
46
|
+
const scaleX = adaptedWidth * factor;
|
|
47
|
+
const scaleY = adaptedHeight * factor;
|
|
48
|
+
const currentMaxScale = 1;
|
|
49
|
+
// Calculate the maximum scale based on the aspect ratio and max scale limit
|
|
50
|
+
let finalMaxScaleW = Math.min(currentMaxScale, scaleX);
|
|
51
|
+
let finalMaxScaleH = Math.min(currentMaxScale, scaleY);
|
|
163
52
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
spriteDataRef.current.frames = parseFrames();
|
|
169
|
-
totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
|
|
170
|
-
const {
|
|
171
|
-
w,
|
|
172
|
-
h
|
|
173
|
-
} = getFirstItem(json.frames).sourceSize;
|
|
174
|
-
aspect = calculateAspectRatio(w, h, aspectFactor, v);
|
|
53
|
+
// Ensure that scaleX and scaleY do not exceed the max scale while maintaining aspect ratio
|
|
54
|
+
if (scaleX > currentMaxScale) {
|
|
55
|
+
finalMaxScaleW = currentMaxScale;
|
|
56
|
+
finalMaxScaleH = scaleY / scaleX * currentMaxScale;
|
|
175
57
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// @ts-ignore
|
|
180
|
-
else _spriteTexture.colorSpace = THREE.SRGBColorSpace;
|
|
181
|
-
setSpriteTexture(_spriteTexture);
|
|
182
|
-
setSpriteObj({
|
|
183
|
-
spriteTexture: _spriteTexture,
|
|
184
|
-
spriteData: spriteDataRef.current,
|
|
185
|
-
aspect: aspect
|
|
186
|
-
});
|
|
187
|
-
};
|
|
188
|
-
const getRowsAndColumns = (texture, totalFrames) => {
|
|
58
|
+
return new THREE.Vector3(finalMaxScaleW, finalMaxScaleH, 1);
|
|
59
|
+
}, []);
|
|
60
|
+
const getRowsAndColumns = React.useCallback((texture, totalFrames) => {
|
|
189
61
|
if (texture.image) {
|
|
190
62
|
const canvas = document.createElement('canvas');
|
|
191
63
|
const ctx = canvas.getContext('2d', canvasRenderingContext2DSettings);
|
|
@@ -240,125 +112,285 @@ function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, ca
|
|
|
240
112
|
emptyFrames: []
|
|
241
113
|
};
|
|
242
114
|
}
|
|
243
|
-
};
|
|
115
|
+
}, [canvasRenderingContext2DSettings]);
|
|
116
|
+
|
|
117
|
+
// calculate scale ratio for the frames
|
|
118
|
+
const calculateScaleRatio = React.useCallback(frames => {
|
|
119
|
+
// Helper function to calculate scale ratio for an array of frames
|
|
120
|
+
const processFrameArray = frameArray => {
|
|
121
|
+
// Find the largest frame
|
|
122
|
+
let largestFrame = null;
|
|
123
|
+
for (const frame of frameArray) {
|
|
124
|
+
const {
|
|
125
|
+
w,
|
|
126
|
+
h
|
|
127
|
+
} = frame.frame;
|
|
128
|
+
const area = w * h;
|
|
129
|
+
if (!largestFrame || area > largestFrame.area) {
|
|
130
|
+
largestFrame = {
|
|
131
|
+
w,
|
|
132
|
+
h,
|
|
133
|
+
area
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Set scaleRatio property on each frame
|
|
139
|
+
const frameArr = frameArray.map(frame => {
|
|
140
|
+
const {
|
|
141
|
+
w,
|
|
142
|
+
h
|
|
143
|
+
} = frame.frame;
|
|
144
|
+
const area = w * h;
|
|
145
|
+
const scaleRatio = largestFrame ? area === largestFrame.area ? 1 : Math.sqrt(area / largestFrame.area) : 1;
|
|
146
|
+
return {
|
|
147
|
+
...frame,
|
|
148
|
+
scaleRatio
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
return frameArr;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Handle both array and record cases
|
|
155
|
+
if (Array.isArray(frames)) {
|
|
156
|
+
return processFrameArray(frames);
|
|
157
|
+
} else {
|
|
158
|
+
const result = {};
|
|
159
|
+
for (const key in frames) {
|
|
160
|
+
result[key] = processFrameArray(frames[key]);
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
}, []);
|
|
244
165
|
|
|
245
166
|
// for frame based JSON Hash sprite data
|
|
246
|
-
const parseFrames = () => {
|
|
167
|
+
const parseFrames = React.useCallback(() => {
|
|
247
168
|
const sprites = {};
|
|
248
169
|
const data = spriteDataRef.current;
|
|
249
|
-
const delimiters =
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
sourceSize: {
|
|
270
|
-
w: sourceWidth,
|
|
271
|
-
h: sourceHeight
|
|
272
|
-
}
|
|
273
|
-
});
|
|
170
|
+
const delimiters = animationFramesRef.current;
|
|
171
|
+
if (data) {
|
|
172
|
+
if (delimiters && Array.isArray(data['frames'])) {
|
|
173
|
+
for (let i = 0; i < delimiters.length; i++) {
|
|
174
|
+
// we convert each named animation group into an array
|
|
175
|
+
sprites[delimiters[i]] = [];
|
|
176
|
+
for (const value of data['frames']) {
|
|
177
|
+
const frameData = value['frame'];
|
|
178
|
+
const sourceWidth = value['sourceSize']['w'];
|
|
179
|
+
const sourceHeight = value['sourceSize']['h'];
|
|
180
|
+
if (typeof value['filename'] === 'string' && value['filename'].toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
|
|
181
|
+
sprites[delimiters[i]].push({
|
|
182
|
+
...value,
|
|
183
|
+
frame: frameData,
|
|
184
|
+
sourceSize: {
|
|
185
|
+
w: sourceWidth,
|
|
186
|
+
h: sourceHeight
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
274
190
|
}
|
|
275
191
|
}
|
|
192
|
+
for (const frame in sprites) {
|
|
193
|
+
const scaleRatioData = calculateScaleRatio(sprites[frame]);
|
|
194
|
+
if (Array.isArray(scaleRatioData)) {
|
|
195
|
+
sprites[frame] = scaleRatioData;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return sprites;
|
|
199
|
+
} else if (delimiters && typeof data['frames'] === 'object') {
|
|
200
|
+
for (let i = 0; i < delimiters.length; i++) {
|
|
201
|
+
// we convert each named animation group into an array
|
|
202
|
+
sprites[delimiters[i]] = [];
|
|
203
|
+
for (const innerKey in data['frames']) {
|
|
204
|
+
const value = data['frames'][innerKey];
|
|
205
|
+
const frameData = value['frame'];
|
|
206
|
+
const sourceWidth = value['sourceSize']['w'];
|
|
207
|
+
const sourceHeight = value['sourceSize']['h'];
|
|
208
|
+
if (typeof innerKey === 'string' && innerKey.toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
|
|
209
|
+
sprites[delimiters[i]].push({
|
|
210
|
+
...value,
|
|
211
|
+
frame: frameData,
|
|
212
|
+
sourceSize: {
|
|
213
|
+
w: sourceWidth,
|
|
214
|
+
h: sourceHeight
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const frame in sprites) {
|
|
221
|
+
const scaleRatioData = calculateScaleRatio(sprites[frame]);
|
|
222
|
+
if (Array.isArray(scaleRatioData)) {
|
|
223
|
+
sprites[frame] = scaleRatioData;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return sprites;
|
|
227
|
+
} else {
|
|
228
|
+
let spritesArr = [];
|
|
229
|
+
if (data != null && data.frames) {
|
|
230
|
+
if (Array.isArray(data.frames)) {
|
|
231
|
+
spritesArr = data.frames.map(frame => ({
|
|
232
|
+
...frame,
|
|
233
|
+
x: frame.frame.x,
|
|
234
|
+
y: frame.frame.y,
|
|
235
|
+
w: frame.frame.w,
|
|
236
|
+
h: frame.frame.h
|
|
237
|
+
}));
|
|
238
|
+
} else {
|
|
239
|
+
spritesArr = Object.values(data.frames).flat().map(frame => ({
|
|
240
|
+
...frame,
|
|
241
|
+
x: frame.frame.x,
|
|
242
|
+
y: frame.frame.y,
|
|
243
|
+
w: frame.frame.w,
|
|
244
|
+
h: frame.frame.h
|
|
245
|
+
}));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return calculateScaleRatio(spritesArr);
|
|
276
249
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
250
|
+
}
|
|
251
|
+
return [];
|
|
252
|
+
}, [calculateScaleRatio, spriteDataRef]);
|
|
253
|
+
const parseSpriteData = React.useCallback((json, _spriteTexture) => {
|
|
254
|
+
let aspect = new THREE.Vector3(1, 1, 1);
|
|
255
|
+
// sprite only case
|
|
256
|
+
if (json === null) {
|
|
257
|
+
if (_spriteTexture && numberOfFrames) {
|
|
258
|
+
//get size from texture
|
|
259
|
+
const width = _spriteTexture.image.width;
|
|
260
|
+
const height = _spriteTexture.image.height;
|
|
261
|
+
totalFrames.current = numberOfFrames;
|
|
262
|
+
const {
|
|
263
|
+
rows,
|
|
264
|
+
columns,
|
|
265
|
+
frameWidth,
|
|
266
|
+
frameHeight,
|
|
267
|
+
emptyFrames
|
|
268
|
+
} = getRowsAndColumns(_spriteTexture, numberOfFrames);
|
|
269
|
+
const nonJsonFrames = {
|
|
270
|
+
frames: [],
|
|
271
|
+
meta: {
|
|
272
|
+
version: '1.0',
|
|
273
|
+
size: {
|
|
298
274
|
w: width,
|
|
299
|
-
h: height
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
275
|
+
h: height
|
|
276
|
+
},
|
|
277
|
+
rows,
|
|
278
|
+
columns,
|
|
279
|
+
frameWidth,
|
|
280
|
+
frameHeight,
|
|
281
|
+
scale: '1'
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
for (let row = 0; row < rows; row++) {
|
|
285
|
+
for (let col = 0; col < columns; col++) {
|
|
286
|
+
const isExcluded = (emptyFrames !== null && emptyFrames !== void 0 ? emptyFrames : []).some(coord => coord.row === row && coord.col === col);
|
|
287
|
+
if (isExcluded) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (Array.isArray(nonJsonFrames.frames)) {
|
|
291
|
+
nonJsonFrames.frames.push({
|
|
292
|
+
frame: {
|
|
293
|
+
x: col * frameWidth,
|
|
294
|
+
y: row * frameHeight,
|
|
295
|
+
w: frameWidth,
|
|
296
|
+
h: frameHeight
|
|
297
|
+
},
|
|
298
|
+
scaleRatio: 1,
|
|
299
|
+
rotated: false,
|
|
300
|
+
trimmed: false,
|
|
301
|
+
spriteSourceSize: {
|
|
302
|
+
x: 0,
|
|
303
|
+
y: 0,
|
|
304
|
+
w: frameWidth,
|
|
305
|
+
h: frameHeight
|
|
306
|
+
},
|
|
307
|
+
sourceSize: {
|
|
308
|
+
w: frameWidth,
|
|
309
|
+
h: frameHeight
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
306
313
|
}
|
|
307
314
|
}
|
|
315
|
+
aspect = calculateAspectRatio(frameWidth, frameHeight, aspectFactor);
|
|
316
|
+
spriteDataRef.current = nonJsonFrames;
|
|
308
317
|
}
|
|
309
|
-
for (const frame in sprites) {
|
|
310
|
-
sprites[frame].frame = calculateScaleRatio(sprites[frame]);
|
|
311
|
-
}
|
|
312
|
-
return sprites;
|
|
313
|
-
} else {
|
|
314
|
-
// we need to convert it into an array
|
|
315
|
-
let spritesArr = [];
|
|
316
|
-
for (const key in data.frames) {
|
|
317
|
-
spritesArr.push(data.frames[key]);
|
|
318
|
-
}
|
|
319
|
-
spritesArr = calculateScaleRatio(spritesArr);
|
|
320
|
-
return spritesArr;
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
318
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
319
|
+
//scale ratio for standalone sprite
|
|
320
|
+
if (spriteDataRef.current && spriteDataRef.current.frames) {
|
|
321
|
+
spriteDataRef.current.frames = calculateScaleRatio(spriteDataRef.current.frames);
|
|
322
|
+
}
|
|
323
|
+
} else if (_spriteTexture) {
|
|
324
|
+
spriteDataRef.current = json;
|
|
325
|
+
spriteDataRef.current.frames = parseFrames();
|
|
326
|
+
totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
|
|
329
327
|
const {
|
|
330
328
|
w,
|
|
331
329
|
h
|
|
332
|
-
} =
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
330
|
+
} = getFirstFrame(json.frames).sourceSize;
|
|
331
|
+
aspect = calculateAspectRatio(w, h, aspectFactor);
|
|
332
|
+
}
|
|
333
|
+
setSpriteData(spriteDataRef.current);
|
|
334
|
+
if ('encoding' in _spriteTexture) {
|
|
335
|
+
_spriteTexture.encoding = 3001; // sRGBEncoding
|
|
336
|
+
} else if ('colorSpace' in _spriteTexture) {
|
|
337
|
+
//@ts-ignore
|
|
338
|
+
_spriteTexture.colorSpace = THREE.SRGBColorSpace;
|
|
340
339
|
}
|
|
340
|
+
setSpriteTexture(_spriteTexture);
|
|
341
|
+
setSpriteObj({
|
|
342
|
+
spriteTexture: _spriteTexture,
|
|
343
|
+
spriteData: spriteDataRef.current,
|
|
344
|
+
aspect: aspect
|
|
345
|
+
});
|
|
346
|
+
}, [getRowsAndColumns, numberOfFrames, parseFrames, calculateAspectRatio, calculateScaleRatio]);
|
|
341
347
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
348
|
+
/**
|
|
349
|
+
*
|
|
350
|
+
*/
|
|
351
|
+
const loadJsonAndTextureAndExecuteCallback = React.useCallback((jsonUrl, textureUrl, callback) => {
|
|
352
|
+
const jsonPromise = fetch(jsonUrl).then(response => response.json());
|
|
353
|
+
const texturePromise = new Promise(resolve => {
|
|
354
|
+
textureLoader.load(textureUrl, resolve);
|
|
355
|
+
});
|
|
356
|
+
Promise.all([jsonPromise, texturePromise]).then(response => {
|
|
357
|
+
callback(response[0], response[1]);
|
|
358
|
+
});
|
|
359
|
+
}, [textureLoader]);
|
|
360
|
+
const loadStandaloneSprite = React.useCallback(textureUrl => {
|
|
361
|
+
if (!textureUrl && !inputRef.current) {
|
|
362
|
+
throw new Error('Either textureUrl or input must be provided');
|
|
356
363
|
}
|
|
357
|
-
|
|
358
|
-
|
|
364
|
+
const validUrl = textureUrl !== null && textureUrl !== void 0 ? textureUrl : inputRef.current;
|
|
365
|
+
if (!validUrl) {
|
|
366
|
+
throw new Error('A valid texture URL must be provided');
|
|
367
|
+
}
|
|
368
|
+
textureLoader.load(validUrl, texture => parseSpriteData(null, texture));
|
|
369
|
+
}, [textureLoader, parseSpriteData]);
|
|
370
|
+
const loadJsonAndTexture = React.useCallback((textureUrl, jsonUrl) => {
|
|
371
|
+
if (jsonUrl && textureUrl) {
|
|
372
|
+
loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, parseSpriteData);
|
|
373
|
+
} else {
|
|
374
|
+
loadStandaloneSprite(textureUrl);
|
|
375
|
+
}
|
|
376
|
+
}, [loadJsonAndTextureAndExecuteCallback, loadStandaloneSprite, parseSpriteData]);
|
|
377
|
+
React.useLayoutEffect(() => {
|
|
378
|
+
if (jsonRef.current && inputRef.current) {
|
|
379
|
+
loadJsonAndTextureAndExecuteCallback(jsonRef.current, inputRef.current, parseSpriteData);
|
|
380
|
+
} else if (inputRef.current) {
|
|
381
|
+
// only load the texture, this is an image sprite only
|
|
382
|
+
loadStandaloneSprite();
|
|
383
|
+
}
|
|
384
|
+
const _inputRef = inputRef.current;
|
|
385
|
+
return () => {
|
|
386
|
+
if (_inputRef) {
|
|
387
|
+
useLoader.clear(TextureLoader, _inputRef);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}, [loadJsonAndTextureAndExecuteCallback, loadStandaloneSprite, parseSpriteData]);
|
|
359
391
|
React.useLayoutEffect(() => {
|
|
360
|
-
onLoad == null || onLoad(spriteTexture, spriteData);
|
|
361
|
-
}, [spriteTexture, spriteData]);
|
|
392
|
+
onLoad == null || onLoad(spriteTexture, spriteData !== null && spriteData !== void 0 ? spriteData : null);
|
|
393
|
+
}, [spriteTexture, spriteData, onLoad]);
|
|
362
394
|
return {
|
|
363
395
|
spriteObj,
|
|
364
396
|
loadJsonAndTexture
|
|
@@ -367,4 +399,4 @@ function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, ca
|
|
|
367
399
|
useSpriteLoader.preload = url => useLoader.preload(TextureLoader, url);
|
|
368
400
|
useSpriteLoader.clear = input => useLoader.clear(TextureLoader, input);
|
|
369
401
|
|
|
370
|
-
export {
|
|
402
|
+
export { checkIfFrameIsEmpty, getFirstFrame, useSpriteLoader };
|