-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathResize.tsx
More file actions
140 lines (127 loc) · 4.07 KB
/
Resize.tsx
File metadata and controls
140 lines (127 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import { useEffect } from "react";
import { Dimensions, PixelRatio, View } from "react-native";
import { Canvas } from "react-native-webgpu";
import Animated, {
cancelAnimation,
Easing,
useAnimatedStyle,
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const AnimatedView = Animated.View as any;
import { redFragWGSL, triangleVertWGSL } from "../Triangle/triangle";
import { useWebGPU } from "../components/useWebGPU";
const win = Dimensions.get("window");
export const useLoop = ({ duration }: { duration: number }) => {
const progress = useSharedValue(0);
useEffect(() => {
progress.value = withRepeat(
withTiming(1, { duration, easing: Easing.inOut(Easing.ease) }),
-1,
true,
);
return () => {
cancelAnimation(progress);
};
}, [duration, progress]);
return progress;
};
export const Resize = () => {
const progress = useLoop({ duration: 4000 });
const width = useDerivedValue(() => {
return 20 + progress.value * (win.width - 20);
});
const ref = useWebGPU(({ context, device, presentationFormat, canvas }) => {
const sampleCount = 4;
const pipeline = device.createRenderPipeline({
layout: "auto",
vertex: {
module: device.createShaderModule({
code: triangleVertWGSL,
}),
},
fragment: {
module: device.createShaderModule({
code: redFragWGSL,
}),
targets: [
{
format: presentationFormat,
},
],
},
primitive: {
topology: "triangle-list",
},
multisample: {
count: sampleCount,
},
});
let renderTarget: GPUTexture | undefined;
let renderTargetView: GPUTextureView;
return () => {
const currentWidth = canvas.clientWidth * PixelRatio.get();
const currentHeight = canvas.clientHeight * PixelRatio.get();
// The canvas size is animating via CSS.
// When the size changes, we need to reallocate the render target.
// We also need to set the physical size of the canvas to match the computed CSS size.
if (
(currentWidth !== canvas.width ||
currentHeight !== canvas.height ||
!renderTargetView) &&
currentWidth &&
currentHeight
) {
if (renderTarget !== undefined) {
// Destroy the previous render target
renderTarget.destroy();
}
// Setting the canvas width and height will automatically resize the textures returned
// when calling getCurrentTexture() on the context.
canvas.width = currentWidth;
canvas.height = currentHeight;
// Resize the multisampled render target to match the new canvas size.
renderTarget = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount,
format: presentationFormat,
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
renderTargetView = renderTarget.createView();
}
if (renderTargetView) {
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: renderTargetView,
resolveTarget: context.getCurrentTexture().createView(),
clearValue: [0.5, 0.5, 0.5, 0.5],
loadOp: "clear",
storeOp: "store",
},
],
};
const passEncoder =
commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.draw(3);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
}
};
});
const style = useAnimatedStyle(() => {
return { width: width.value, flex: 1, backgroundColor: "cyan" };
});
return (
<View style={{ flex: 1, alignItems: "center" }}>
<AnimatedView style={style}>
<Canvas ref={ref} style={{ flex: 1 }} transparent />
</AnimatedView>
</View>
);
};