From f4ca910d4ca2b3133141e46adfd86a3db54ef47c Mon Sep 17 00:00:00 2001 From: trafficlunar Date: Sun, 12 Jan 2025 21:07:59 +0000 Subject: [PATCH] refactor: remove image context --- src/components/canvas/Blocks.tsx | 55 +--------------------------- src/components/canvas/Canvas.tsx | 9 ----- src/components/dialogs/OpenImage.tsx | 48 ++++++++++++++++++------ src/context/Image.tsx | 28 -------------- src/pages/AppPage.tsx | 31 +++++++--------- 5 files changed, 52 insertions(+), 119 deletions(-) delete mode 100644 src/context/Image.tsx diff --git a/src/components/canvas/Blocks.tsx b/src/components/canvas/Blocks.tsx index c400ab0..47d294a 100644 --- a/src/components/canvas/Blocks.tsx +++ b/src/components/canvas/Blocks.tsx @@ -5,40 +5,20 @@ import * as PIXI from "pixi.js"; import { useApp } from "@pixi/react"; import { CompositeTilemap, settings } from "@pixi/tilemap"; -import { findBlockFromRgb } from "@/utils/findBlockFromRgb"; - interface Props { blocks: Block[]; - setBlocks: React.Dispatch>; missingTexture: PIXI.Texture | undefined; textures: Record; solidTextures: Record; - image: HTMLImageElement | undefined; - imageDimensions: Dimension; - usableBlocks: string[]; coords: Position; scale: number; version: number; - setLoading: React.Dispatch>; } // Lifts 16,000 tiles limit settings.use32bitIndex = true; -function Blocks({ - blocks, - setBlocks, - missingTexture, - textures, - solidTextures, - image, - imageDimensions, - usableBlocks, - coords, - scale, - version, - setLoading, -}: Props) { +function Blocks({ blocks, missingTexture, textures, solidTextures, coords, scale, version }: Props) { const app = useApp(); const tilemapRef = useRef(); @@ -80,39 +60,6 @@ function Blocks({ tilemapRef.current.scale.set(scale, scale); }, [coords, scale]); - useEffect(() => { - if (!image) return; - - const canvas = document.createElement("canvas"); - const ctx = canvas.getContext("2d"); - - if (ctx) { - canvas.width = imageDimensions.width; - canvas.height = imageDimensions.height; - ctx.drawImage(image, 0, 0, imageDimensions.width, imageDimensions.height); - - const imageData = ctx.getImageData(0, 0, imageDimensions.width, imageDimensions.height); - const newBlocks: Block[] = []; - - for (let i = 0; i < imageData.data.length; i += 4) { - const block = findBlockFromRgb(usableBlocks, imageData.data[i], imageData.data[i + 1], imageData.data[i + 2], imageData.data[i + 3]); - if (block == "air") continue; - - const x = Math.floor((i / 4) % imageData.width); - const y = Math.floor(i / 4 / imageData.width); - - newBlocks.push({ - name: block, - x, - y, - }); - } - - setBlocks(newBlocks); - setLoading(false); - } - }, [image, imageDimensions]); - return null; } diff --git a/src/components/canvas/Canvas.tsx b/src/components/canvas/Canvas.tsx index 4cd8680..da25e91 100644 --- a/src/components/canvas/Canvas.tsx +++ b/src/components/canvas/Canvas.tsx @@ -4,8 +4,6 @@ import * as PIXI from "pixi.js"; import { Container, Stage } from "@pixi/react"; import { CanvasContext } from "@/context/Canvas"; -import { ImageContext } from "@/context/Image"; -import { LoadingContext } from "@/context/Loading"; import { SettingsContext } from "@/context/Settings"; import { TexturesContext } from "@/context/Textures"; import { ThemeContext } from "@/context/Theme"; @@ -28,8 +26,6 @@ PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; function Canvas() { const { stageSize, canvasSize, blocks, coords, scale, version, setStageSize, setBlocks, setCoords, setScale } = useContext(CanvasContext); - const { image, imageDimensions, usableBlocks } = useContext(ImageContext); - const { setLoading } = useContext(LoadingContext); const { settings } = useContext(SettingsContext); const { missingTexture, solidTextures } = useContext(TexturesContext); const { isDark } = useContext(ThemeContext); @@ -320,17 +316,12 @@ function Canvas() { > diff --git a/src/components/dialogs/OpenImage.tsx b/src/components/dialogs/OpenImage.tsx index 0a08b23..bad3c06 100644 --- a/src/components/dialogs/OpenImage.tsx +++ b/src/components/dialogs/OpenImage.tsx @@ -4,7 +4,6 @@ import { useDropzone } from "react-dropzone"; import { CircleAlertIcon, LinkIcon, UploadIcon } from "lucide-react"; import { CanvasContext } from "@/context/Canvas"; -import { ImageContext } from "@/context/Image"; import { LoadingContext } from "@/context/Loading"; import { Button } from "@/components/ui/button"; @@ -22,11 +21,11 @@ import { useBlockData } from "@/hooks/useBlockData"; import BlockSelector from "./open-image/BlockSelector"; import VersionCombobox from "../VersionCombobox"; +import { findBlockFromRgb } from "@/utils/findBlockFromRgb"; function OpenImage({ close }: DialogProps) { - const { version, setVersion } = useContext(CanvasContext); + const { version, setVersion, setBlocks } = useContext(CanvasContext); const { setLoading } = useContext(LoadingContext); - const { setImage: setContextImage, setImageDimensions: setContextImageDimensions, setUsableBlocks } = useContext(ImageContext); const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ accept: { @@ -95,17 +94,44 @@ function OpenImage({ close }: DialogProps) { setSelectedBlocks(newValue); }; - const onSubmit = () => { + const onSubmit = async () => { if (image) { setLoading(true); - setUsableBlocks(selectedBlocks); - // Wait for loading indicator to appear - setTimeout(() => { - setContextImage(image); - setContextImageDimensions(imageDimensions); - close(); - }, 100); + await new Promise((resolve) => setTimeout(resolve, 100)); + + // Load image through JS canvas + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + + if (ctx) { + canvas.width = imageDimensions.width; + canvas.height = imageDimensions.height; + ctx.drawImage(image, 0, 0, imageDimensions.width, imageDimensions.height); + + const imageData = ctx.getImageData(0, 0, imageDimensions.width, imageDimensions.height); + const newBlocks: Block[] = []; + + // Go through each pixel in the image and find block by checking closest RGB to the average color of the texture + for (let i = 0; i < imageData.data.length; i += 4) { + const block = findBlockFromRgb(selectedBlocks, imageData.data[i], imageData.data[i + 1], imageData.data[i + 2], imageData.data[i + 3]); + if (block == "air") continue; + + const x = Math.floor((i / 4) % imageData.width); + const y = Math.floor(i / 4 / imageData.width); + + newBlocks.push({ + name: block, + x, + y, + }); + } + + setBlocks(newBlocks); + } + + setLoading(false); + close(); } }; diff --git a/src/context/Image.tsx b/src/context/Image.tsx deleted file mode 100644 index 33af7f6..0000000 --- a/src/context/Image.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { createContext, ReactNode, useState } from "react"; - -interface Context { - image: HTMLImageElement | undefined; - imageDimensions: Dimension; - usableBlocks: string[]; - setImage: React.Dispatch>; - setImageDimensions: React.Dispatch>; - setUsableBlocks: React.Dispatch>; -} - -interface Props { - children: ReactNode; -} - -export const ImageContext = createContext({} as Context); - -export const ImageProvider = ({ children }: Props) => { - const [image, setImage] = useState(); - const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0 }); - const [usableBlocks, setUsableBlocks] = useState([]); - - return ( - - {children} - - ); -}; diff --git a/src/pages/AppPage.tsx b/src/pages/AppPage.tsx index 09c6f76..a4b58a8 100644 --- a/src/pages/AppPage.tsx +++ b/src/pages/AppPage.tsx @@ -1,5 +1,4 @@ import { CanvasProvider } from "@/context/Canvas"; -import { ImageProvider } from "@/context/Image"; import { LoadingProvider } from "@/context/Loading"; import { SettingsProvider } from "@/context/Settings"; import { TexturesProvider } from "@/context/Textures"; @@ -13,22 +12,20 @@ import ToolSettings from "@/components/tool-settings"; function AppPage() { return ( - - - - - -
- - - - -
-
-
-
-
-
+ + + + +
+ + + + +
+
+
+
+
); }