From 712424e03029c5f81c99fd0836069ef45502c45d Mon Sep 17 00:00:00 2001 From: Yehor Date: Tue, 14 Nov 2023 23:46:30 +0200 Subject: [PATCH] Single canvas (v0.0.1-alpha.3) (#16) --- package.json | 2 +- .../Generator/CanvasSection/CanvasSection.tsx | 78 +++++++++++++------ .../Generator/CanvasSection/utils/draw.ts | 58 -------------- .../CanvasSection/utils/drawNormal.ts | 55 +++++++++++++ src/components/pages/Generator/Generator.tsx | 6 +- .../Generator/SettingsSection/Group/Group.tsx | 2 +- 6 files changed, 113 insertions(+), 88 deletions(-) create mode 100644 src/components/pages/Generator/CanvasSection/utils/drawNormal.ts diff --git a/package.json b/package.json index 2217b95..f80121b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "displacementx", - "version": "0.0.1-alpha.2", + "version": "0.0.1-alpha.3", "scripts": { "dev": "next dev", "build": "next build", diff --git a/src/components/pages/Generator/CanvasSection/CanvasSection.tsx b/src/components/pages/Generator/CanvasSection/CanvasSection.tsx index ad4d8f2..043153a 100644 --- a/src/components/pages/Generator/CanvasSection/CanvasSection.tsx +++ b/src/components/pages/Generator/CanvasSection/CanvasSection.tsx @@ -8,6 +8,8 @@ import {saveImage} from './utils/saveImage'; import {draw} from './utils/draw'; import {Switch} from '@/components/ui/Switch'; import {clearCanvas} from './utils/clearCanvas'; +import {drawNormal} from './utils/drawNormal'; +import {getCanvasDimensions} from './utils/getCanvasDimensions'; export function CanvasSection() { const [is8k, setIs8k] = useState(false); @@ -16,17 +18,18 @@ export function CanvasSection() { const [isPristine, setIsPristine] = useState(true); const [isRendering, setIsRendering] = useState(false); + const [isNormalPreview, setIsNormalPreview] = useState(false); const [renderTimeMs, setRenderTimeMs] = useState(); const canvasRef = useRef(null); - const canvasNormalRef = useRef(null); + const canvasOriginalPreviewDataUrl = useRef(undefined); const render = () => { setIsPristine(false); setIsRendering(true); + setIsNormalPreview(false); const ctx2d = getCtx2d(canvasRef); - const ctx2dNormal = getCtx2d(canvasNormalRef); const { iterations, @@ -61,7 +64,6 @@ export function CanvasSection() { draw({ ctx2d, - ctx2dNormal, props: { iterations, backgroundBrightness, @@ -116,41 +118,65 @@ export function CanvasSection() { saveImage({canvas, fileName: 'displacementx-gen'}); }; - const downloadNormal = () => { - const canvas = canvasNormalRef.current; - if (!canvas) return; - - saveImage({canvas, fileName: 'displacementx-gen-normal'}); - }; - const onIs8kChange = (is8k: boolean) => { const ctx2d = getCtx2d(canvasRef); - const ctx2dNormal = getCtx2d(canvasNormalRef); clearCanvas(ctx2d); - clearCanvas(ctx2dNormal); setIsPristine(true); + setIsNormalPreview(false); setRenderTimeMs(undefined); setIs8k(is8k); }; + const toggleNormalPreview = () => { + const isNormalPreviewNew = !isNormalPreview; + const renderTimeStartMs: number = performance.now(); + setIsRendering(true); + + const updateCanvas = () => { + const ctx2d = getCtx2d(canvasRef); + + if (isNormalPreviewNew) { + // Draw normal preview + canvasOriginalPreviewDataUrl.current = ctx2d.canvas.toDataURL(); + drawNormal({ctx2d, ctx2dNormal: ctx2d}); + } else { + // Restore original preview + const dataUrl = canvasOriginalPreviewDataUrl.current; + if (dataUrl) { + const {w, h} = getCanvasDimensions(ctx2d); + const img = new Image(); + img.src = dataUrl; + img.onload = () => { + ctx2d.clearRect(0, 0, w, h); + ctx2d.drawImage(img, 0, 0, w, h); + canvasOriginalPreviewDataUrl.current = undefined; + }; + } + } + }; + + // Put a small timeout to allow the UI to update before canvas takes the main thread over + setTimeout(() => { + updateCanvas(); + setIsNormalPreview(isNormalPreviewNew); + setIsRendering(false); + setRenderTimeMs(performance.now() - renderTimeStartMs); + }, 20); + }; + return (
Output -
+ +
-
@@ -162,18 +188,20 @@ export function CanvasSection() {
-
- -
-
+
-
+
+
diff --git a/src/components/pages/Generator/CanvasSection/utils/draw.ts b/src/components/pages/Generator/CanvasSection/utils/draw.ts index dabd753..02d8bd4 100644 --- a/src/components/pages/Generator/CanvasSection/utils/draw.ts +++ b/src/components/pages/Generator/CanvasSection/utils/draw.ts @@ -7,7 +7,6 @@ import {clearCanvas} from './clearCanvas'; export const draw = ({ ctx2d, - ctx2dNormal, onEnd, props: { iterations, @@ -41,7 +40,6 @@ export const draw = ({ }, }: { ctx2d: CanvasRenderingContext2D; - ctx2dNormal: CanvasRenderingContext2D; onEnd: (renderTimeMs: number) => void; props: { iterations: number; @@ -77,7 +75,6 @@ export const draw = ({ const renderStartTimeMs = performance.now(); clearCanvas(ctx2d); - clearCanvas(ctx2dNormal); drawBackground({ctx2d, backgroundBrightness}); @@ -142,7 +139,6 @@ export const draw = ({ } }, onEnd() { - drawNormal({ctx2d, ctx2dNormal}); const renderTimeMs = performance.now() - renderStartTimeMs; onEnd(renderTimeMs); }, @@ -336,57 +332,3 @@ const drawLines = ({ ctx2d.fillRect(x, 0, thickness, h); } }; - -/** - * Draws the normal map. - * - "ctx2d" is the canvas context to read from. - * - "ctx2dNormal" is the canvas context to write to. - */ -const drawNormal = ({ - ctx2d, - ctx2dNormal, -}: { - ctx2d: CanvasRenderingContext2D; - ctx2dNormal: CanvasRenderingContext2D; -}): void => { - const {w, h} = getCanvasDimensions(ctx2d); - - const source = ctx2d.getImageData(0, 0, w, h); - const destination = ctx2dNormal.createImageData(w, h); - - for (let i = 0, l = w * h * 4; i < l; i += 4) { - let x1; - let x2; - let y1; - let y2; - - if (i % (w * 4) === 0) { - x1 = source.data[i]; - x2 = source.data[i + 4]; - } else if (i % (w * 4) === (w - 1) * 4) { - x1 = source.data[i - 4]; - x2 = source.data[i]; - } else { - x1 = source.data[i - 4]; - x2 = source.data[i + 4]; - } - - if (i < h * 4) { - y1 = source.data[i]; - y2 = source.data[i + h * 4]; - } else if (i > h * (h - 1) * 4) { - y1 = source.data[i - h * 4]; - y2 = source.data[i]; - } else { - y1 = source.data[i - h * 4]; - y2 = source.data[i + h * 4]; - } - - destination.data[i] = x1 - x2 + 127; - destination.data[i + 1] = y1 - y2 + 127; - destination.data[i + 2] = 255; - destination.data[i + 3] = 255; - } - - ctx2dNormal.putImageData(destination, 0, 0); -}; diff --git a/src/components/pages/Generator/CanvasSection/utils/drawNormal.ts b/src/components/pages/Generator/CanvasSection/utils/drawNormal.ts new file mode 100644 index 0000000..62a5073 --- /dev/null +++ b/src/components/pages/Generator/CanvasSection/utils/drawNormal.ts @@ -0,0 +1,55 @@ +import {getCanvasDimensions} from './getCanvasDimensions'; + +/** + * Draws the normal map. + * - "ctx2d" is the canvas context to read from. + * - "ctx2dNormal" is the canvas context to write to. + */ +export const drawNormal = ({ + ctx2d, + ctx2dNormal, +}: { + ctx2d: CanvasRenderingContext2D; + ctx2dNormal: CanvasRenderingContext2D; +}): void => { + const {w, h} = getCanvasDimensions(ctx2d); + + const source = ctx2d.getImageData(0, 0, w, h); + const destination = ctx2dNormal.createImageData(w, h); + + for (let i = 0, l = w * h * 4; i < l; i += 4) { + let x1; + let x2; + let y1; + let y2; + + if (i % (w * 4) === 0) { + x1 = source.data[i]; + x2 = source.data[i + 4]; + } else if (i % (w * 4) === (w - 1) * 4) { + x1 = source.data[i - 4]; + x2 = source.data[i]; + } else { + x1 = source.data[i - 4]; + x2 = source.data[i + 4]; + } + + if (i < h * 4) { + y1 = source.data[i]; + y2 = source.data[i + h * 4]; + } else if (i > h * (h - 1) * 4) { + y1 = source.data[i - h * 4]; + y2 = source.data[i]; + } else { + y1 = source.data[i - h * 4]; + y2 = source.data[i + h * 4]; + } + + destination.data[i] = x1 - x2 + 127; + destination.data[i + 1] = y1 - y2 + 127; + destination.data[i + 2] = 255; + destination.data[i + 3] = 255; + } + + ctx2dNormal.putImageData(destination, 0, 0); +}; diff --git a/src/components/pages/Generator/Generator.tsx b/src/components/pages/Generator/Generator.tsx index 947c244..2b15814 100644 --- a/src/components/pages/Generator/Generator.tsx +++ b/src/components/pages/Generator/Generator.tsx @@ -26,11 +26,11 @@ export function Generator() { /> -
-
+
+
-
+
diff --git a/src/components/pages/Generator/SettingsSection/Group/Group.tsx b/src/components/pages/Generator/SettingsSection/Group/Group.tsx index ce6b247..86925c7 100644 --- a/src/components/pages/Generator/SettingsSection/Group/Group.tsx +++ b/src/components/pages/Generator/SettingsSection/Group/Group.tsx @@ -36,7 +36,7 @@ export function Group(props: GroupProps) {