Decouple UI updates from WebGL renderer
This commit is contained in:
+4
-2
@@ -1,5 +1,5 @@
|
||||
import { Provider } from '@react-spectrum/s2';
|
||||
import { lazy, Suspense, useRef, useState } from 'react';
|
||||
import { lazy, Suspense, useDeferredValue, useRef, useState } from 'react';
|
||||
import type { EffectCanvasHandle } from './components/canvas/effect';
|
||||
import { Controls } from './components/controls';
|
||||
import { ImageLoader } from './components/image-loader';
|
||||
@@ -34,6 +34,8 @@ const App = () => {
|
||||
const [activeTab, setActiveTab] = useState<ActiveTab>('mask');
|
||||
const effectCanvasRef = useRef<EffectCanvasHandle>(null);
|
||||
|
||||
const deferredDrosteParams = useDeferredValue(drosteParams);
|
||||
|
||||
useZoomAnimation({
|
||||
isAnimating: drosteParams.zoomAnimating,
|
||||
isActive: activeTab === 'effect',
|
||||
@@ -77,7 +79,7 @@ const App = () => {
|
||||
ref={effectCanvasRef}
|
||||
image={image}
|
||||
curve={curve}
|
||||
drosteParams={drosteParams}
|
||||
drosteParams={deferredDrosteParams}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type RefObject, useEffect, useRef } from 'react';
|
||||
import { computeOptimalCenter, computeOptimalScale } from '../../math/bezier';
|
||||
import type { BezierCurve, DrosteParams } from '../../types';
|
||||
import type { BezierCurve, DrosteParams, Point } from '../../types';
|
||||
import { DrosteRenderer } from '../../webgl/droste-renderer';
|
||||
|
||||
type RendererConfig = {
|
||||
@@ -10,13 +10,23 @@ type RendererConfig = {
|
||||
drosteParams: DrosteParams;
|
||||
};
|
||||
|
||||
type RenderParams = {
|
||||
center: Point;
|
||||
scaleFactor: number;
|
||||
drosteParams: DrosteParams;
|
||||
};
|
||||
|
||||
export function useDrosteRenderer({ canvasRef, image, curve, drosteParams }: RendererConfig) {
|
||||
const rendererRef = useRef<DrosteRenderer | null>(null);
|
||||
const rafIdRef = useRef<number | null>(null);
|
||||
const renderParamsRef = useRef<RenderParams | null>(null);
|
||||
|
||||
const center = computeOptimalCenter(curve, image.width, image.height);
|
||||
const autoScale = computeOptimalScale(curve, center, image.width, image.height);
|
||||
const scaleFactor = drosteParams.scaleOverride ?? autoScale;
|
||||
|
||||
renderParamsRef.current = { center, scaleFactor, drosteParams };
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
@@ -56,14 +66,35 @@ export function useDrosteRenderer({ canvasRef, image, curve, drosteParams }: Ren
|
||||
}, [curve, center]);
|
||||
|
||||
useEffect(() => {
|
||||
const renderer = rendererRef.current;
|
||||
const canvas = canvasRef.current;
|
||||
if (!renderer || !canvas) return;
|
||||
if (!canvas) return;
|
||||
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
}, [image.width, image.height, canvasRef]);
|
||||
|
||||
renderer.render(center, scaleFactor, drosteParams);
|
||||
useEffect(() => {
|
||||
const renderer = rendererRef.current;
|
||||
if (!renderer) return;
|
||||
|
||||
if (rafIdRef.current !== null) {
|
||||
cancelAnimationFrame(rafIdRef.current);
|
||||
}
|
||||
|
||||
rafIdRef.current = requestAnimationFrame(() => {
|
||||
rafIdRef.current = null;
|
||||
const params = renderParamsRef.current;
|
||||
if (params) {
|
||||
renderer.render(params.center, params.scaleFactor, params.drosteParams);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (rafIdRef.current !== null) {
|
||||
cancelAnimationFrame(rafIdRef.current);
|
||||
rafIdRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [image, center, scaleFactor, curve, drosteParams, canvasRef]);
|
||||
|
||||
const download = () => {
|
||||
|
||||
Reference in New Issue
Block a user