refactor: remove image context

This commit is contained in:
trafficlunar 2025-01-12 21:07:59 +00:00
parent aa58b31269
commit f4ca910d4c
5 changed files with 52 additions and 119 deletions

View file

@ -5,40 +5,20 @@ import * as PIXI from "pixi.js";
import { useApp } from "@pixi/react"; import { useApp } from "@pixi/react";
import { CompositeTilemap, settings } from "@pixi/tilemap"; import { CompositeTilemap, settings } from "@pixi/tilemap";
import { findBlockFromRgb } from "@/utils/findBlockFromRgb";
interface Props { interface Props {
blocks: Block[]; blocks: Block[];
setBlocks: React.Dispatch<React.SetStateAction<Block[]>>;
missingTexture: PIXI.Texture | undefined; missingTexture: PIXI.Texture | undefined;
textures: Record<string, PIXI.Texture>; textures: Record<string, PIXI.Texture>;
solidTextures: Record<string, PIXI.Texture>; solidTextures: Record<string, PIXI.Texture>;
image: HTMLImageElement | undefined;
imageDimensions: Dimension;
usableBlocks: string[];
coords: Position; coords: Position;
scale: number; scale: number;
version: number; version: number;
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
} }
// Lifts 16,000 tiles limit // Lifts 16,000 tiles limit
settings.use32bitIndex = true; settings.use32bitIndex = true;
function Blocks({ function Blocks({ blocks, missingTexture, textures, solidTextures, coords, scale, version }: Props) {
blocks,
setBlocks,
missingTexture,
textures,
solidTextures,
image,
imageDimensions,
usableBlocks,
coords,
scale,
version,
setLoading,
}: Props) {
const app = useApp(); const app = useApp();
const tilemapRef = useRef<CompositeTilemap>(); const tilemapRef = useRef<CompositeTilemap>();
@ -80,39 +60,6 @@ function Blocks({
tilemapRef.current.scale.set(scale, scale); tilemapRef.current.scale.set(scale, scale);
}, [coords, 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; return null;
} }

View file

@ -4,8 +4,6 @@ import * as PIXI from "pixi.js";
import { Container, Stage } from "@pixi/react"; import { Container, Stage } from "@pixi/react";
import { CanvasContext } from "@/context/Canvas"; import { CanvasContext } from "@/context/Canvas";
import { ImageContext } from "@/context/Image";
import { LoadingContext } from "@/context/Loading";
import { SettingsContext } from "@/context/Settings"; import { SettingsContext } from "@/context/Settings";
import { TexturesContext } from "@/context/Textures"; import { TexturesContext } from "@/context/Textures";
import { ThemeContext } from "@/context/Theme"; import { ThemeContext } from "@/context/Theme";
@ -28,8 +26,6 @@ PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
function Canvas() { function Canvas() {
const { stageSize, canvasSize, blocks, coords, scale, version, setStageSize, setBlocks, setCoords, setScale } = useContext(CanvasContext); 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 { settings } = useContext(SettingsContext);
const { missingTexture, solidTextures } = useContext(TexturesContext); const { missingTexture, solidTextures } = useContext(TexturesContext);
const { isDark } = useContext(ThemeContext); const { isDark } = useContext(ThemeContext);
@ -320,17 +316,12 @@ function Canvas() {
> >
<Blocks <Blocks
blocks={visibleBlocks} blocks={visibleBlocks}
setBlocks={setBlocks}
missingTexture={missingTexture} missingTexture={missingTexture}
textures={textures} textures={textures}
solidTextures={solidTextures} solidTextures={solidTextures}
image={image}
imageDimensions={imageDimensions}
usableBlocks={usableBlocks}
coords={coords} coords={coords}
scale={scale} scale={scale}
version={version} version={version}
setLoading={setLoading}
/> />
<Container x={coords.x} y={coords.y} scale={scale}> <Container x={coords.x} y={coords.y} scale={scale}>

View file

@ -4,7 +4,6 @@ import { useDropzone } from "react-dropzone";
import { CircleAlertIcon, LinkIcon, UploadIcon } from "lucide-react"; import { CircleAlertIcon, LinkIcon, UploadIcon } from "lucide-react";
import { CanvasContext } from "@/context/Canvas"; import { CanvasContext } from "@/context/Canvas";
import { ImageContext } from "@/context/Image";
import { LoadingContext } from "@/context/Loading"; import { LoadingContext } from "@/context/Loading";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -22,11 +21,11 @@ import { useBlockData } from "@/hooks/useBlockData";
import BlockSelector from "./open-image/BlockSelector"; import BlockSelector from "./open-image/BlockSelector";
import VersionCombobox from "../VersionCombobox"; import VersionCombobox from "../VersionCombobox";
import { findBlockFromRgb } from "@/utils/findBlockFromRgb";
function OpenImage({ close }: DialogProps) { function OpenImage({ close }: DialogProps) {
const { version, setVersion } = useContext(CanvasContext); const { version, setVersion, setBlocks } = useContext(CanvasContext);
const { setLoading } = useContext(LoadingContext); const { setLoading } = useContext(LoadingContext);
const { setImage: setContextImage, setImageDimensions: setContextImageDimensions, setUsableBlocks } = useContext(ImageContext);
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
accept: { accept: {
@ -95,17 +94,44 @@ function OpenImage({ close }: DialogProps) {
setSelectedBlocks(newValue); setSelectedBlocks(newValue);
}; };
const onSubmit = () => { const onSubmit = async () => {
if (image) { if (image) {
setLoading(true); setLoading(true);
setUsableBlocks(selectedBlocks);
// Wait for loading indicator to appear // Wait for loading indicator to appear
setTimeout(() => { await new Promise((resolve) => setTimeout(resolve, 100));
setContextImage(image);
setContextImageDimensions(imageDimensions); // 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(); close();
}, 100);
} }
}; };

View file

@ -1,28 +0,0 @@
import { createContext, ReactNode, useState } from "react";
interface Context {
image: HTMLImageElement | undefined;
imageDimensions: Dimension;
usableBlocks: string[];
setImage: React.Dispatch<React.SetStateAction<HTMLImageElement | undefined>>;
setImageDimensions: React.Dispatch<React.SetStateAction<Dimension>>;
setUsableBlocks: React.Dispatch<React.SetStateAction<string[]>>;
}
interface Props {
children: ReactNode;
}
export const ImageContext = createContext<Context>({} as Context);
export const ImageProvider = ({ children }: Props) => {
const [image, setImage] = useState<HTMLImageElement>();
const [imageDimensions, setImageDimensions] = useState<Dimension>({ width: 0, height: 0 });
const [usableBlocks, setUsableBlocks] = useState<string[]>([]);
return (
<ImageContext.Provider value={{ image, imageDimensions, usableBlocks, setImage, setImageDimensions, setUsableBlocks }}>
{children}
</ImageContext.Provider>
);
};

View file

@ -1,5 +1,4 @@
import { CanvasProvider } from "@/context/Canvas"; import { CanvasProvider } from "@/context/Canvas";
import { ImageProvider } from "@/context/Image";
import { LoadingProvider } from "@/context/Loading"; import { LoadingProvider } from "@/context/Loading";
import { SettingsProvider } from "@/context/Settings"; import { SettingsProvider } from "@/context/Settings";
import { TexturesProvider } from "@/context/Textures"; import { TexturesProvider } from "@/context/Textures";
@ -13,7 +12,6 @@ import ToolSettings from "@/components/tool-settings";
function AppPage() { function AppPage() {
return ( return (
<CanvasProvider> <CanvasProvider>
<ImageProvider>
<LoadingProvider> <LoadingProvider>
<SettingsProvider> <SettingsProvider>
<TexturesProvider> <TexturesProvider>
@ -28,7 +26,6 @@ function AppPage() {
</TexturesProvider> </TexturesProvider>
</SettingsProvider> </SettingsProvider>
</LoadingProvider> </LoadingProvider>
</ImageProvider>
</CanvasProvider> </CanvasProvider>
); );
} }