Skip to content

Commit bffa8bf

Browse files
committed
🔧
1 parent 1227660 commit bffa8bf

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { useCallback, useEffect, useRef, useState } from "react";
2+
import { Canvas, useCanvasEffect } from "react-native-wgpu";
3+
import { PixelRatio, useWindowDimensions } from "react-native";
4+
5+
import { ComputeEngine } from "./engine";
6+
7+
export interface ComputeToy {
8+
shader: string;
9+
uniforms: Record<string, number>;
10+
}
11+
12+
export const useComputeToy = (toyId: number) => {
13+
const [props, setProps] = useState<ComputeToy | null>(null);
14+
15+
useEffect(() => {
16+
(async () => {
17+
const shaderURL = `https://compute.toys/view/${toyId}/wgsl`;
18+
const uniformsURL = `https://compute.toys/view/${toyId}/json`;
19+
20+
// Execute both fetch requests in parallel
21+
const [shaderResponse, uniformsResponse] = await Promise.all([
22+
fetch(shaderURL),
23+
fetch(uniformsURL),
24+
]);
25+
26+
// Process the responses in parallel
27+
const [shader, uniformsJSON] = await Promise.all([
28+
shaderResponse.text(),
29+
uniformsResponse.json(),
30+
]);
31+
const uniforms: Record<string, number> = {};
32+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33+
uniformsJSON.body.uniforms.forEach((uniform: any) => {
34+
uniforms[uniform.name] = uniform.value;
35+
});
36+
setProps({ shader, uniforms });
37+
})();
38+
}, [toyId]);
39+
return props;
40+
};
41+
42+
export interface ComputeToyProps {
43+
toy: ComputeToy;
44+
}
45+
46+
export const ComputeToy = ({ toy: { shader, uniforms } }: ComputeToyProps) => {
47+
const { width, height } = useWindowDimensions();
48+
const [engine, setEngine] = useState<ComputeEngine | null>(null);
49+
const animationRef = useRef<number | null>(null);
50+
const lastTimeRef = useRef<number>(0);
51+
52+
// Initialize WebGPU and the compute engine
53+
const canvasRef = useCanvasEffect(() => {
54+
const initWebGPU = async () => {
55+
try {
56+
// Create the compute engine
57+
await ComputeEngine.create();
58+
const eng = ComputeEngine.getInstance();
59+
60+
// Set the canvas surface
61+
if (canvasRef.current) {
62+
eng.setSurface(canvasRef.current!);
63+
64+
// Set the canvas size based on your CANVAS constants
65+
// TODO: use PixelRatio.get()
66+
eng.resize(width, height, PixelRatio.get());
67+
68+
// Initialize render state
69+
eng.reset();
70+
71+
// Set callbacks for shader compilation
72+
eng.onSuccess((entryPoints) => {
73+
console.log(
74+
"Shader compiled successfully with entry points:",
75+
entryPoints,
76+
);
77+
});
78+
79+
eng.onError((message, row, col) => {
80+
console.error(`Shader error at ${row}:${col} - ${message}`);
81+
});
82+
eng.setCustomFloats(
83+
Object.keys(uniforms),
84+
new Float32Array(Object.values(uniforms)),
85+
);
86+
// Process and compile the shader
87+
const preprocessed = await eng.preprocess(shader);
88+
if (preprocessed) {
89+
await eng.compile(preprocessed);
90+
}
91+
92+
setEngine(eng);
93+
}
94+
} catch (error) {
95+
console.error("Failed to initialize WebGPU:", error);
96+
}
97+
};
98+
99+
initWebGPU();
100+
101+
return () => {
102+
if (animationRef.current !== null) {
103+
cancelAnimationFrame(animationRef.current);
104+
}
105+
};
106+
});
107+
108+
// Animation/render loop
109+
const renderLoop = useCallback(
110+
(timestamp: number) => {
111+
if (!engine) {
112+
return;
113+
}
114+
115+
// Calculate time delta
116+
const delta = lastTimeRef.current
117+
? (timestamp - lastTimeRef.current) / 1000
118+
: 0;
119+
lastTimeRef.current = timestamp;
120+
121+
// Update time uniforms
122+
engine.setTimeElapsed(timestamp / 1000);
123+
engine.setTimeDelta(delta);
124+
// Render frame
125+
126+
engine.render();
127+
// Schedule next frame
128+
animationRef.current = requestAnimationFrame(renderLoop);
129+
},
130+
[engine],
131+
);
132+
133+
useEffect(() => {
134+
renderLoop(new Date().getTime());
135+
}, [renderLoop]);
136+
137+
return <Canvas ref={canvasRef} style={{ width, height }} />;
138+
};

0 commit comments

Comments
 (0)