react-native-shine 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -6
- package/lib/module/components/Content.js +232 -0
- package/lib/module/components/Content.js.map +1 -0
- package/lib/module/components/Shine.js +18 -254
- package/lib/module/components/Shine.js.map +1 -1
- package/lib/module/components/ShineGroup.js +11 -23
- package/lib/module/components/ShineGroup.js.map +1 -1
- package/lib/module/hooks/useAnimationFrame.js +17 -0
- package/lib/module/hooks/useAnimationFrame.js.map +1 -0
- package/lib/module/hooks/useOrientation.js +2 -8
- package/lib/module/hooks/useOrientation.js.map +1 -1
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/shaders/bindGroupLayouts.js +8 -8
- package/lib/module/shaders/bindGroupLayouts.js.map +1 -1
- package/lib/module/shaders/bindGroupUtils.js +18 -40
- package/lib/module/shaders/bindGroupUtils.js.map +1 -1
- package/lib/module/shaders/fragmentShaders/glareFragment.js +8 -7
- package/lib/module/shaders/fragmentShaders/glareFragment.js.map +1 -1
- package/lib/module/shaders/fragmentShaders/holoFragment.js +5 -10
- package/lib/module/shaders/fragmentShaders/holoFragment.js.map +1 -1
- package/lib/module/shaders/fragmentShaders/reverseHoloFragment.js +3 -3
- package/lib/module/shaders/fragmentShaders/reverseHoloFragment.js.map +1 -1
- package/lib/module/shaders/pipelineSetups.js +29 -43
- package/lib/module/shaders/pipelineSetups.js.map +1 -1
- package/lib/module/shaders/resourceManagement/textures.js +7 -0
- package/lib/module/shaders/resourceManagement/textures.js.map +1 -1
- package/lib/module/shaders/utils.js +8 -22
- package/lib/module/shaders/utils.js.map +1 -1
- package/lib/module/shaders/vertexShaders/mainRotationEffectVertex.js +2 -2
- package/lib/module/shaders/vertexShaders/mainRotationEffectVertex.js.map +1 -1
- package/lib/module/types/size.js +2 -0
- package/lib/module/types/size.js.map +1 -0
- package/lib/module/types/typeUtils.js +0 -14
- package/lib/module/types/typeUtils.js.map +1 -1
- package/lib/module/types/vector.js +2 -0
- package/lib/module/types/vector.js.map +1 -0
- package/lib/module/utils/size.js +25 -0
- package/lib/module/utils/size.js.map +1 -0
- package/lib/module/utils/vector.js +168 -0
- package/lib/module/utils/vector.js.map +1 -0
- package/lib/typescript/src/components/Content.d.ts +23 -0
- package/lib/typescript/src/components/Content.d.ts.map +1 -0
- package/lib/typescript/src/components/Shine.d.ts +3 -13
- package/lib/typescript/src/components/Shine.d.ts.map +1 -1
- package/lib/typescript/src/components/ShineGroup.d.ts +3 -5
- package/lib/typescript/src/components/ShineGroup.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useAnimationFrame.d.ts +2 -0
- package/lib/typescript/src/hooks/useAnimationFrame.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useOrientation.d.ts +3 -1
- package/lib/typescript/src/hooks/useOrientation.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/shaders/bindGroupLayouts.d.ts +9 -9
- package/lib/typescript/src/shaders/bindGroupLayouts.d.ts.map +1 -1
- package/lib/typescript/src/shaders/bindGroupUtils.d.ts +3 -3
- package/lib/typescript/src/shaders/bindGroupUtils.d.ts.map +1 -1
- package/lib/typescript/src/shaders/fragmentShaders/glareFragment.d.ts.map +1 -1
- package/lib/typescript/src/shaders/fragmentShaders/holoFragment.d.ts.map +1 -1
- package/lib/typescript/src/shaders/pipelineSetups.d.ts +7 -7
- package/lib/typescript/src/shaders/pipelineSetups.d.ts.map +1 -1
- package/lib/typescript/src/shaders/resourceManagement/textures.d.ts +2 -1
- package/lib/typescript/src/shaders/resourceManagement/textures.d.ts.map +1 -1
- package/lib/typescript/src/shaders/utils.d.ts +3 -4
- package/lib/typescript/src/shaders/utils.d.ts.map +1 -1
- package/lib/typescript/src/types/size.d.ts +5 -0
- package/lib/typescript/src/types/size.d.ts.map +1 -0
- package/lib/typescript/src/types/typeUtils.d.ts +1 -4
- package/lib/typescript/src/types/typeUtils.d.ts.map +1 -1
- package/lib/typescript/src/types/types.d.ts +3 -1
- package/lib/typescript/src/types/types.d.ts.map +1 -1
- package/lib/typescript/src/types/vector.d.ts +11 -0
- package/lib/typescript/src/types/vector.d.ts.map +1 -0
- package/lib/typescript/src/utils/size.d.ts +5 -0
- package/lib/typescript/src/utils/size.d.ts.map +1 -0
- package/lib/typescript/src/utils/vector.d.ts +33 -0
- package/lib/typescript/src/utils/vector.d.ts.map +1 -0
- package/package.json +8 -7
- package/src/components/Content.tsx +403 -0
- package/src/components/Shine.tsx +24 -466
- package/src/components/ShineGroup.tsx +17 -24
- package/src/hooks/useAnimationFrame.ts +21 -0
- package/src/hooks/useOrientation.ts +11 -13
- package/src/index.tsx +9 -1
- package/src/shaders/bindGroupLayouts.ts +11 -11
- package/src/shaders/bindGroupUtils.ts +31 -61
- package/src/shaders/fragmentShaders/glareFragment.ts +8 -7
- package/src/shaders/fragmentShaders/holoFragment.ts +5 -13
- package/src/shaders/fragmentShaders/reverseHoloFragment.ts +4 -4
- package/src/shaders/pipelineSetups.ts +54 -69
- package/src/shaders/resourceManagement/textures.ts +13 -1
- package/src/shaders/utils.ts +13 -27
- package/src/shaders/vertexShaders/mainRotationEffectVertex.ts +2 -2
- package/src/types/size.ts +4 -0
- package/src/types/typeUtils.ts +0 -28
- package/src/types/types.ts +11 -1
- package/src/types/vector.ts +13 -0
- package/src/utils/size.ts +12 -0
- package/src/utils/vector.ts +132 -0
package/src/components/Shine.tsx
CHANGED
|
@@ -1,480 +1,38 @@
|
|
|
1
|
-
import { useEffect,
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useDevice } from 'react-native-wgpu';
|
|
3
|
+
import type { TgpuTexture } from 'typegpu';
|
|
3
4
|
import { getOrInitRoot } from '../roots';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
clamp,
|
|
8
|
-
rotate2D,
|
|
9
|
-
subscribeToOrientationChange,
|
|
10
|
-
getAngleFromDimensions,
|
|
11
|
-
} from '../shaders/utils';
|
|
12
|
-
import type { TgpuRenderPipeline, TgpuTexture } from 'typegpu';
|
|
13
|
-
import {
|
|
14
|
-
glareOptionsBindGroupLayout,
|
|
15
|
-
colorMaskBindGroupLayout,
|
|
16
|
-
rotationValuesBindGroupLayout,
|
|
17
|
-
textureBindGroupLayout,
|
|
18
|
-
type BufferDataMap,
|
|
19
|
-
bufferData,
|
|
20
|
-
} from '../shaders/bindGroupLayouts';
|
|
21
|
-
import Animated, {
|
|
22
|
-
SensorType,
|
|
23
|
-
useAnimatedSensor,
|
|
24
|
-
useAnimatedStyle,
|
|
25
|
-
useDerivedValue,
|
|
26
|
-
useSharedValue,
|
|
27
|
-
type SharedValue,
|
|
28
|
-
} from 'react-native-reanimated';
|
|
29
|
-
import * as d from 'typegpu/data';
|
|
30
|
-
import { PixelRatio, Platform, View } from 'react-native';
|
|
31
|
-
import {
|
|
32
|
-
createGlareOptionsBindGroup,
|
|
33
|
-
createColorMaskBindGroup,
|
|
34
|
-
createRotationValuesBindGroup,
|
|
35
|
-
} from '../shaders/bindGroupUtils';
|
|
36
|
-
import {
|
|
37
|
-
createBindGroupPairs,
|
|
38
|
-
createGlareOptions,
|
|
39
|
-
createColorMask,
|
|
40
|
-
colorMaskToTyped,
|
|
41
|
-
} from '../types/typeUtils';
|
|
42
|
-
import type {
|
|
43
|
-
BindGroupPair,
|
|
44
|
-
GlareOptions,
|
|
45
|
-
ColorMask,
|
|
46
|
-
DeepPartiallyOptional,
|
|
47
|
-
} from '../types/types';
|
|
48
|
-
import {
|
|
49
|
-
attachBindGroups,
|
|
50
|
-
blend,
|
|
51
|
-
createReverseHoloPipeline,
|
|
52
|
-
createMaskPipeline,
|
|
53
|
-
getDefaultTarget,
|
|
54
|
-
pipelineRenderFunction,
|
|
55
|
-
createRainbowHoloPipeline as createHoloPipeline,
|
|
56
|
-
} from '../shaders/pipelineSetups';
|
|
57
|
-
import colorMaskFragment from '../shaders/fragmentShaders/colorMaskFragment';
|
|
58
|
-
import {
|
|
59
|
-
createTexture,
|
|
60
|
-
loadTexture,
|
|
61
|
-
} from '../shaders/resourceManagement/textures';
|
|
62
|
-
import { newGlareFragment } from '../shaders/fragmentShaders/glareFragment';
|
|
63
|
-
import { TypedBufferMap } from '../shaders/resourceManagement/bufferManager';
|
|
5
|
+
import { loadBitmap } from '../shaders/resourceManagement/textures';
|
|
6
|
+
import Content, { type SharedProps } from './Content';
|
|
64
7
|
|
|
65
|
-
export interface ShineProps {
|
|
66
|
-
width: number;
|
|
67
|
-
height: number;
|
|
8
|
+
export interface ShineProps extends SharedProps {
|
|
68
9
|
imageURI: string;
|
|
69
|
-
glareOptions?: Partial<GlareOptions>;
|
|
70
|
-
colorMaskOptions?: DeepPartiallyOptional<ColorMask, 'baseColor'>;
|
|
71
10
|
maskURI?: string;
|
|
72
|
-
useTouchControl?: boolean;
|
|
73
|
-
touchPosition?: SharedValue<[number, number]>;
|
|
74
|
-
addTextureMask?: boolean;
|
|
75
|
-
addReverseHolo?: boolean;
|
|
76
|
-
addHolo?: boolean;
|
|
77
11
|
}
|
|
78
12
|
|
|
79
|
-
export function Shine({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
colorMaskOptions,
|
|
85
|
-
maskURI,
|
|
86
|
-
touchPosition,
|
|
87
|
-
useTouchControl = false,
|
|
88
|
-
addTextureMask = false,
|
|
89
|
-
addHolo = false,
|
|
90
|
-
addReverseHolo = false,
|
|
91
|
-
}: ShineProps) {
|
|
92
|
-
const { device = null } = useDevice();
|
|
93
|
-
const root = device ? getOrInitRoot(device) : null;
|
|
94
|
-
const { ref, context } = useGPUContext();
|
|
95
|
-
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
96
|
-
const frameRef = useRef<number | null>(null);
|
|
13
|
+
export function Shine({ imageURI, maskURI, ...props }: ShineProps) {
|
|
14
|
+
const { device } = useDevice();
|
|
15
|
+
const root = device && getOrInitRoot(device);
|
|
16
|
+
const [imageTexture, setImageTexture] = useState<TgpuTexture>();
|
|
17
|
+
const [maskTexture, setMaskTexture] = useState<TgpuTexture>();
|
|
97
18
|
|
|
98
|
-
//changing canvas size to prevent blur
|
|
99
|
-
const dpr = PixelRatio.get();
|
|
100
|
-
const logicalWidth = width;
|
|
101
|
-
const logicalHeight = height;
|
|
102
|
-
const pixelWidth = Math.max(1, Math.round(logicalWidth * dpr));
|
|
103
|
-
const pixelHeight = Math.max(1, Math.round(logicalHeight * dpr));
|
|
104
|
-
|
|
105
|
-
const [imageTexture, setImageTexture] = useState<TgpuTexture | null>(null);
|
|
106
|
-
const [maskTexture, setMaskTexture] = useState<TgpuTexture | null>(null);
|
|
107
|
-
|
|
108
|
-
const orientationAngle = useSharedValue<number>(0); // degrees
|
|
109
|
-
const rotationShared = useSharedValue<[number, number, number]>([0, 0, 0]); // final GPU offsets
|
|
110
|
-
|
|
111
|
-
// Calibration shared values (UI thread)
|
|
112
|
-
const initialGravity = useSharedValue<[number, number, number]>([0, 0, 0]);
|
|
113
|
-
const calibSum = useSharedValue<[number, number, number]>([0, 0, 0]);
|
|
114
|
-
const calibCount = useSharedValue<number>(0);
|
|
115
|
-
const calibrated = useSharedValue<boolean>(false);
|
|
116
|
-
const gravitySensor = useAnimatedSensor(SensorType.GRAVITY, { interval: 20 });
|
|
117
|
-
|
|
118
|
-
const bufferManager = useMemo(
|
|
119
|
-
() => new TypedBufferMap(bufferData as BufferDataMap),
|
|
120
|
-
[]
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
//TODO: add once again, when the wgpu issues are fixed :3
|
|
124
|
-
|
|
125
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
126
|
-
// const rotX = rotationShared.value[0] * 10;
|
|
127
|
-
// const rotY = rotationShared.value[1] * 10;
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
transform: [
|
|
131
|
-
{ perspective: 300 },
|
|
132
|
-
// { rotateX: `${-rotX}deg` },
|
|
133
|
-
// { rotateY: `${rotY}deg` },
|
|
134
|
-
// { rotateZ: `${rotX * 5}deg` },
|
|
135
|
-
],
|
|
136
|
-
};
|
|
137
|
-
});
|
|
138
|
-
// Subscribe to orientation changes and reset calibration on change
|
|
139
19
|
useEffect(() => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
orientationAngle.value = angleDeg;
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
return () => unsubscribe();
|
|
146
|
-
}, [orientationAngle]);
|
|
147
|
-
|
|
148
|
-
// Calibration & mapping logic
|
|
149
|
-
useDerivedValue(() => {
|
|
150
|
-
'worklet';
|
|
151
|
-
|
|
152
|
-
if (useTouchControl) {
|
|
153
|
-
rotationShared.value = touchPosition
|
|
154
|
-
? [...touchPosition.value, 0]
|
|
155
|
-
: [0, 0, 0];
|
|
156
|
-
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// console.log(orientationAngle.value);
|
|
161
|
-
const v: { x: number; y: number; z: number } = gravitySensor.sensor
|
|
162
|
-
?.value ??
|
|
163
|
-
gravitySensor.sensor.value ?? { x: 0, y: 0, z: 0 };
|
|
164
|
-
|
|
165
|
-
const gx = v.x ?? 0;
|
|
166
|
-
const gy = v.y ?? 0;
|
|
167
|
-
const gz = v.z ?? 0;
|
|
168
|
-
|
|
169
|
-
const CALIBRATION_SAMPLES = 40;
|
|
170
|
-
const alpha = 0.15; // smoothing
|
|
171
|
-
const scale = 0.6;
|
|
172
|
-
|
|
173
|
-
if (!calibrated.value) {
|
|
174
|
-
// accumulate baseline in device coordinates
|
|
175
|
-
const s = calibSum.value;
|
|
176
|
-
const c = calibCount.value + 1;
|
|
177
|
-
calibSum.value = [s[0] + gx, s[1] + gy, s[2] + gz];
|
|
178
|
-
calibCount.value = c;
|
|
179
|
-
|
|
180
|
-
if (c >= CALIBRATION_SAMPLES) {
|
|
181
|
-
const avg = calibSum.value;
|
|
182
|
-
initialGravity.value = [avg[0] / c, avg[1] / c, avg[2] / c];
|
|
183
|
-
calibrated.value = true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
rotationShared.value = [0, 0, 0];
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const init = initialGravity.value;
|
|
191
|
-
const dx = gx - init[0];
|
|
192
|
-
const dy = gy - init[1];
|
|
193
|
-
const dz = gz - init[2];
|
|
194
|
-
|
|
195
|
-
// Rotate into screen coordinates so offsets auto-swap with orientation
|
|
196
|
-
const [mx, my] = rotate2D([dx, dy], -orientationAngle.value);
|
|
197
|
-
const screenX = mx;
|
|
198
|
-
const screenY = -my;
|
|
199
|
-
|
|
200
|
-
const prev = rotationShared.value;
|
|
201
|
-
const smoothX = prev[0] * (1 - alpha) + screenX * alpha;
|
|
202
|
-
const smoothY = prev[1] * (1 - alpha) + screenY * alpha;
|
|
203
|
-
const smoothZ = prev[2] * (1 - alpha) + dz * alpha;
|
|
204
|
-
|
|
205
|
-
if (orientationAngle.value === 90) {
|
|
206
|
-
rotationShared.value = [
|
|
207
|
-
clamp(smoothY * scale, -1, 1),
|
|
208
|
-
clamp(-smoothX * scale, -1, 1),
|
|
209
|
-
clamp(smoothZ * scale, -1, 1),
|
|
210
|
-
];
|
|
211
|
-
} else {
|
|
212
|
-
rotationShared.value = [
|
|
213
|
-
clamp(smoothX * scale, -1, 1),
|
|
214
|
-
clamp(smoothY * scale, -1, 1),
|
|
215
|
-
clamp(smoothZ * scale, -1, 1),
|
|
216
|
-
];
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Resource setup
|
|
221
|
-
useEffect(() => {
|
|
222
|
-
if (!root || !device || !context) return;
|
|
223
|
-
|
|
224
|
-
(async () => {
|
|
225
|
-
const bitmap = await getBitmapFromURI(imageURI);
|
|
226
|
-
const texture = await createTexture(root, bitmap);
|
|
227
|
-
setImageTexture(texture);
|
|
228
|
-
await loadTexture(root, bitmap, texture);
|
|
20
|
+
if (root) loadBitmap(root, imageURI, setImageTexture);
|
|
21
|
+
}, [root, imageURI]);
|
|
229
22
|
|
|
230
|
-
if (!maskURI) return;
|
|
231
|
-
const maskBitmap = await getBitmapFromURI(maskURI);
|
|
232
|
-
const maskTex = await createTexture(root, maskBitmap);
|
|
233
|
-
setMaskTexture(maskTex);
|
|
234
|
-
await loadTexture(root, maskBitmap, maskTex);
|
|
235
|
-
})();
|
|
236
|
-
}, [root, device, context, imageURI, maskURI]);
|
|
237
|
-
|
|
238
|
-
// Render loop
|
|
239
23
|
useEffect(() => {
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
//this sets the underlying resolution of the canvas to prevent blurriness
|
|
243
|
-
const canvasElement = context.canvas;
|
|
244
|
-
if (
|
|
245
|
-
canvasElement &&
|
|
246
|
-
canvasElement.width !== pixelWidth &&
|
|
247
|
-
canvasElement.height !== pixelHeight
|
|
248
|
-
) {
|
|
249
|
-
canvasElement.width = pixelWidth;
|
|
250
|
-
canvasElement.height = pixelHeight;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
context.configure({
|
|
254
|
-
device,
|
|
255
|
-
format: presentationFormat,
|
|
256
|
-
alphaMode: 'premultiplied',
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const sampler = device.createSampler({
|
|
260
|
-
magFilter: 'linear',
|
|
261
|
-
minFilter: 'linear',
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
const imageTextureBindGroup = root.createBindGroup(textureBindGroupLayout, {
|
|
265
|
-
texture: root.unwrap(imageTexture).createView(),
|
|
266
|
-
sampler: sampler,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
const rotationBuffer = bufferManager.addBuffer(
|
|
270
|
-
root,
|
|
271
|
-
'rotationBuffer',
|
|
272
|
-
d.vec3f(0.0)
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
const rotationBindGroup = createRotationValuesBindGroup(
|
|
276
|
-
root,
|
|
277
|
-
rotationBuffer
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
const glareOptionsBuffer = bufferManager.addBuffer(
|
|
281
|
-
root,
|
|
282
|
-
'glareBuffer',
|
|
283
|
-
createGlareOptions(glareOptions ?? {})
|
|
284
|
-
);
|
|
285
|
-
const glareOptionsBindGroup = createGlareOptionsBindGroup(
|
|
286
|
-
root,
|
|
287
|
-
glareOptionsBuffer
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
const colorMaskBuffer = bufferManager.addBuffer(
|
|
291
|
-
root,
|
|
292
|
-
'colorMaskBuffer',
|
|
293
|
-
colorMaskToTyped(
|
|
294
|
-
createColorMask(colorMaskOptions ?? { baseColor: [-20, -20, -20] })
|
|
295
|
-
)
|
|
296
|
-
);
|
|
297
|
-
const colorMaskBindGroup = createColorMaskBindGroup(root, colorMaskBuffer);
|
|
298
|
-
|
|
299
|
-
const glareBGP: BindGroupPair[] = createBindGroupPairs(
|
|
300
|
-
[
|
|
301
|
-
textureBindGroupLayout,
|
|
302
|
-
rotationValuesBindGroupLayout,
|
|
303
|
-
glareOptionsBindGroupLayout,
|
|
304
|
-
colorMaskBindGroupLayout,
|
|
305
|
-
],
|
|
306
|
-
[
|
|
307
|
-
imageTextureBindGroup,
|
|
308
|
-
rotationBindGroup,
|
|
309
|
-
glareOptionsBindGroup,
|
|
310
|
-
colorMaskBindGroup,
|
|
311
|
-
]
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
const colorMaskBGP: BindGroupPair[] = createBindGroupPairs(
|
|
315
|
-
[
|
|
316
|
-
textureBindGroupLayout,
|
|
317
|
-
colorMaskBindGroupLayout,
|
|
318
|
-
rotationValuesBindGroupLayout,
|
|
319
|
-
],
|
|
320
|
-
[imageTextureBindGroup, colorMaskBindGroup, rotationBindGroup]
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
let glarePipeline = root['~unstable']
|
|
324
|
-
.withVertex(mainVertex, {})
|
|
325
|
-
.withFragment(newGlareFragment, getDefaultTarget(presentationFormat))
|
|
326
|
-
.createPipeline();
|
|
327
|
-
glarePipeline = attachBindGroups(glarePipeline, glareBGP);
|
|
328
|
-
|
|
329
|
-
let colorMaskPipeline = root['~unstable']
|
|
330
|
-
.withVertex(mainVertex, {})
|
|
331
|
-
.withFragment(
|
|
332
|
-
colorMaskFragment,
|
|
333
|
-
getDefaultTarget(presentationFormat, blend)
|
|
334
|
-
)
|
|
335
|
-
.createPipeline();
|
|
336
|
-
colorMaskPipeline = attachBindGroups(colorMaskPipeline, colorMaskBGP);
|
|
337
|
-
|
|
338
|
-
//optional pipeline - mask
|
|
339
|
-
const maskPipeline = createMaskPipeline(
|
|
340
|
-
root,
|
|
341
|
-
maskTexture,
|
|
342
|
-
createBindGroupPairs(
|
|
343
|
-
[textureBindGroupLayout, rotationValuesBindGroupLayout],
|
|
344
|
-
[imageTextureBindGroup, rotationBindGroup]
|
|
345
|
-
),
|
|
346
|
-
sampler,
|
|
347
|
-
presentationFormat
|
|
348
|
-
);
|
|
349
|
-
|
|
350
|
-
const reverseHoloBGP: BindGroupPair[] = createBindGroupPairs(
|
|
351
|
-
[
|
|
352
|
-
textureBindGroupLayout,
|
|
353
|
-
rotationValuesBindGroupLayout,
|
|
354
|
-
glareOptionsBindGroupLayout,
|
|
355
|
-
],
|
|
356
|
-
[imageTextureBindGroup, rotationBindGroup, glareOptionsBindGroup]
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
const reverseHoloPipeline = createReverseHoloPipeline(
|
|
360
|
-
root,
|
|
361
|
-
maskTexture,
|
|
362
|
-
reverseHoloBGP,
|
|
363
|
-
sampler,
|
|
364
|
-
presentationFormat
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
const holoBGP: BindGroupPair[] = createBindGroupPairs(
|
|
368
|
-
[rotationValuesBindGroupLayout],
|
|
369
|
-
[rotationBindGroup]
|
|
370
|
-
);
|
|
371
|
-
|
|
372
|
-
const holoPipeline = createHoloPipeline(
|
|
373
|
-
root,
|
|
374
|
-
imageTexture,
|
|
375
|
-
holoBGP,
|
|
376
|
-
sampler,
|
|
377
|
-
presentationFormat
|
|
378
|
-
);
|
|
379
|
-
|
|
380
|
-
const pipelines: TgpuRenderPipeline[] = [glarePipeline];
|
|
381
|
-
if (addTextureMask && maskPipeline) pipelines.push(maskPipeline);
|
|
382
|
-
if (addReverseHolo && reverseHoloPipeline)
|
|
383
|
-
pipelines.push(reverseHoloPipeline);
|
|
384
|
-
if (addHolo && holoPipeline) pipelines.push(holoPipeline);
|
|
385
|
-
if (colorMaskOptions) pipelines.push(colorMaskPipeline);
|
|
386
|
-
|
|
387
|
-
const rot = d.vec3f(0.0);
|
|
388
|
-
let view: GPUTextureView;
|
|
389
|
-
let initialAttachment;
|
|
390
|
-
let loadingAttachment;
|
|
391
|
-
const isInSinglePass = false;
|
|
392
|
-
const render = () => {
|
|
393
|
-
rot[0] = rotationShared.value[0];
|
|
394
|
-
rot[1] = rotationShared.value[1];
|
|
395
|
-
rot[2] = rotationShared.value[2];
|
|
396
|
-
rotationBuffer.write(rot);
|
|
397
|
-
|
|
398
|
-
view = context.getCurrentTexture().createView();
|
|
399
|
-
initialAttachment = {
|
|
400
|
-
view: view,
|
|
401
|
-
clearValue: [0, 0, 0, 0],
|
|
402
|
-
loadOp: 'clear' as GPULoadOp,
|
|
403
|
-
storeOp: 'store' as GPUStoreOp,
|
|
404
|
-
};
|
|
405
|
-
loadingAttachment = {
|
|
406
|
-
view: view,
|
|
407
|
-
clearValue: [0, 0, 0, 0],
|
|
408
|
-
loadOp: 'load' as GPULoadOp,
|
|
409
|
-
storeOp: 'store' as GPUStoreOp,
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
pipelineRenderFunction(
|
|
413
|
-
root,
|
|
414
|
-
pipelines,
|
|
415
|
-
[
|
|
416
|
-
initialAttachment,
|
|
417
|
-
loadingAttachment,
|
|
418
|
-
loadingAttachment,
|
|
419
|
-
loadingAttachment,
|
|
420
|
-
loadingAttachment,
|
|
421
|
-
],
|
|
422
|
-
view,
|
|
423
|
-
isInSinglePass
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
context.present();
|
|
427
|
-
frameRef.current = requestAnimationFrame(render);
|
|
428
|
-
};
|
|
429
|
-
frameRef.current = requestAnimationFrame(render);
|
|
430
|
-
|
|
431
|
-
return () => {
|
|
432
|
-
if (frameRef.current) cancelAnimationFrame(frameRef.current);
|
|
433
|
-
};
|
|
434
|
-
}, [
|
|
435
|
-
device,
|
|
436
|
-
context,
|
|
437
|
-
root,
|
|
438
|
-
presentationFormat,
|
|
439
|
-
imageTexture,
|
|
440
|
-
maskTexture,
|
|
441
|
-
rotationShared,
|
|
442
|
-
bufferManager,
|
|
443
|
-
glareOptions,
|
|
444
|
-
colorMaskOptions,
|
|
445
|
-
maskURI,
|
|
446
|
-
addHolo,
|
|
447
|
-
addReverseHolo,
|
|
448
|
-
addTextureMask,
|
|
449
|
-
pixelWidth,
|
|
450
|
-
pixelHeight,
|
|
451
|
-
]);
|
|
24
|
+
if (root && maskURI) loadBitmap(root, maskURI, setMaskTexture);
|
|
25
|
+
}, [root, imageURI, maskURI]);
|
|
452
26
|
|
|
453
27
|
return (
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
<Canvas
|
|
464
|
-
ref={ref}
|
|
465
|
-
style={[
|
|
466
|
-
{ width: logicalWidth, height: logicalHeight },
|
|
467
|
-
// aspectRatio: pixelWidth / pixelHeight,
|
|
468
|
-
// { transform: [{ scaleX: 1 / dpr }, { scaleY: 1 / dpr }] },
|
|
469
|
-
]}
|
|
470
|
-
transparent={Platform.OS === 'ios'}
|
|
471
|
-
// transparent={true}
|
|
472
|
-
/>
|
|
473
|
-
</View>
|
|
474
|
-
</Animated.View>
|
|
28
|
+
root &&
|
|
29
|
+
imageTexture && (
|
|
30
|
+
<Content
|
|
31
|
+
{...props}
|
|
32
|
+
root={root}
|
|
33
|
+
imageTexture={imageTexture}
|
|
34
|
+
maskTexture={maskTexture}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
475
37
|
);
|
|
476
38
|
}
|
|
477
|
-
|
|
478
|
-
// const styles = StyleSheet.create({
|
|
479
|
-
// container: { overflow: 'hidden' },
|
|
480
|
-
// });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type PropsWithChildren, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
StyleSheet,
|
|
@@ -7,11 +7,12 @@ import {
|
|
|
7
7
|
PixelRatio,
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import ViewShot, { captureRef } from 'react-native-view-shot';
|
|
10
|
+
import type { V2d } from '../types/vector';
|
|
11
|
+
import { sizeFromV2d, sizeToV2d } from '../utils/size';
|
|
12
|
+
import { areV2dEqual, multiplyV2d, round2D } from '../utils/vector';
|
|
10
13
|
import { Shine, type ShineProps } from './Shine';
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
children: React.ReactNode;
|
|
14
|
-
}
|
|
15
|
+
type ShineGroupProps = PropsWithChildren<Partial<ShineProps>>;
|
|
15
16
|
|
|
16
17
|
export function ShineGroup({
|
|
17
18
|
children,
|
|
@@ -23,21 +24,17 @@ export function ShineGroup({
|
|
|
23
24
|
addTextureMask = false,
|
|
24
25
|
addHolo = false,
|
|
25
26
|
addReverseHolo = false,
|
|
26
|
-
}: ShineGroupProps
|
|
27
|
-
const viewShotRef = useRef<
|
|
27
|
+
}: ShineGroupProps) {
|
|
28
|
+
const viewShotRef = useRef<ViewShot>(null);
|
|
28
29
|
const [capturedURI, setCapturedURI] = useState<string | null>(null);
|
|
29
|
-
const [size, setSize] = useState<
|
|
30
|
-
null
|
|
31
|
-
);
|
|
30
|
+
const [size, setSize] = useState<V2d | null>(null);
|
|
32
31
|
|
|
33
32
|
const onInnerLayout = (e: LayoutChangeEvent) => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
33
|
+
const layoutV2d = sizeToV2d(e.nativeEvent.layout);
|
|
34
|
+
|
|
35
|
+
if (!size || !areV2dEqual(size, layoutV2d)) {
|
|
36
|
+
setSize(layoutV2d);
|
|
39
37
|
}
|
|
40
|
-
console.log('onInnerLayout', width, height);
|
|
41
38
|
};
|
|
42
39
|
|
|
43
40
|
// When we have a valid measured size, take a snapshot (after a short tick)
|
|
@@ -48,15 +45,12 @@ export function ShineGroup({
|
|
|
48
45
|
let mounted = true;
|
|
49
46
|
const t = setTimeout(async () => {
|
|
50
47
|
try {
|
|
51
|
-
const
|
|
52
|
-
const pixelW = Math.round(size.width * dpr);
|
|
53
|
-
const pixelH = Math.round(size.height * dpr);
|
|
48
|
+
const pixel = round2D(multiplyV2d(size, PixelRatio.get()));
|
|
54
49
|
|
|
55
|
-
const uri = await captureRef(viewShotRef
|
|
50
|
+
const uri = await captureRef(viewShotRef, {
|
|
56
51
|
format: 'png',
|
|
57
52
|
quality: 1,
|
|
58
|
-
|
|
59
|
-
height: pixelH,
|
|
53
|
+
...sizeFromV2d(pixel),
|
|
60
54
|
});
|
|
61
55
|
if (mounted) setCapturedURI(uri);
|
|
62
56
|
} catch (err) {
|
|
@@ -79,13 +73,12 @@ export function ShineGroup({
|
|
|
79
73
|
</ViewShot>
|
|
80
74
|
|
|
81
75
|
{capturedURI && size && (
|
|
82
|
-
<Image src={capturedURI}
|
|
76
|
+
<Image src={capturedURI} {...sizeFromV2d(size)} />
|
|
83
77
|
)}
|
|
84
78
|
|
|
85
79
|
{capturedURI && size && (
|
|
86
80
|
<Shine
|
|
87
|
-
|
|
88
|
-
height={size.height}
|
|
81
|
+
{...sizeFromV2d(size)}
|
|
89
82
|
imageURI={capturedURI}
|
|
90
83
|
glareOptions={glareOptions}
|
|
91
84
|
colorMaskOptions={colorMaskOptions}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function useAnimationFrame(cb: () => void) {
|
|
4
|
+
const requestId = useRef<number>(null);
|
|
5
|
+
|
|
6
|
+
const onFrame = useCallback(
|
|
7
|
+
function () {
|
|
8
|
+
cb();
|
|
9
|
+
requestId.current = requestAnimationFrame(onFrame);
|
|
10
|
+
},
|
|
11
|
+
[cb]
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
requestId.current = requestAnimationFrame(onFrame);
|
|
16
|
+
|
|
17
|
+
return () => {
|
|
18
|
+
requestId.current === null || cancelAnimationFrame(requestId.current);
|
|
19
|
+
};
|
|
20
|
+
}, [onFrame]);
|
|
21
|
+
}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
getAngleFromDimensions,
|
|
4
|
-
subscribeToOrientationChange,
|
|
5
|
-
} from '../shaders/utils';
|
|
2
|
+
import { subscribeToOrientationChange } from '../shaders/utils';
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
const [orientation, setOrientation] = useState<string>();
|
|
4
|
+
type Orientation = 'LANDSCAPE' | 'PORTRAIT';
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const unsubscribe = subscribeToOrientationChange((angleDeg) => {
|
|
13
|
-
setOrientation(angleDeg === 0 ? 'PORTRAIT' : 'LANDSCAPE');
|
|
14
|
-
});
|
|
6
|
+
export const useOrientation = () => {
|
|
7
|
+
const [orientation, setOrientation] = useState<Orientation>();
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
useEffect(
|
|
10
|
+
() =>
|
|
11
|
+
subscribeToOrientationChange((isLandscape) =>
|
|
12
|
+
setOrientation(isLandscape ? 'LANDSCAPE' : 'PORTRAIT')
|
|
13
|
+
),
|
|
14
|
+
[]
|
|
15
|
+
);
|
|
18
16
|
|
|
19
17
|
return orientation;
|
|
20
18
|
};
|
package/src/index.tsx
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { useOrientation } from './hooks/useOrientation';
|
|
2
2
|
import {
|
|
3
3
|
getAngleFromDimensions,
|
|
4
|
+
isLandscapeMode,
|
|
4
5
|
subscribeToOrientationChange,
|
|
5
6
|
} from './shaders/utils';
|
|
6
7
|
|
|
7
|
-
export {
|
|
8
|
+
export {
|
|
9
|
+
subscribeToOrientationChange,
|
|
10
|
+
getAngleFromDimensions,
|
|
11
|
+
isLandscapeMode,
|
|
12
|
+
useOrientation,
|
|
13
|
+
};
|
|
8
14
|
export { Shine } from './components/Shine';
|
|
9
15
|
export { ShineGroup } from './components/ShineGroup';
|
|
10
16
|
export type { ShineProps } from './components/Shine';
|
|
17
|
+
export * from './utils/vector';
|
|
18
|
+
export type { V2d, V3d } from './types/vector';
|