refactor: remove image context
This commit is contained in:
parent
aa58b31269
commit
f4ca910d4c
5 changed files with 52 additions and 119 deletions
|
|
@ -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<React.SetStateAction<Block[]>>;
|
||||
missingTexture: PIXI.Texture | undefined;
|
||||
textures: Record<string, PIXI.Texture>;
|
||||
solidTextures: Record<string, PIXI.Texture>;
|
||||
image: HTMLImageElement | undefined;
|
||||
imageDimensions: Dimension;
|
||||
usableBlocks: string[];
|
||||
coords: Position;
|
||||
scale: number;
|
||||
version: number;
|
||||
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
// 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<CompositeTilemap>();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
|||
>
|
||||
<Blocks
|
||||
blocks={visibleBlocks}
|
||||
setBlocks={setBlocks}
|
||||
missingTexture={missingTexture}
|
||||
textures={textures}
|
||||
solidTextures={solidTextures}
|
||||
image={image}
|
||||
imageDimensions={imageDimensions}
|
||||
usableBlocks={usableBlocks}
|
||||
coords={coords}
|
||||
scale={scale}
|
||||
version={version}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
|
||||
<Container x={coords.x} y={coords.y} scale={scale}>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
@ -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 (
|
||||
<CanvasProvider>
|
||||
<ImageProvider>
|
||||
<LoadingProvider>
|
||||
<SettingsProvider>
|
||||
<TexturesProvider>
|
||||
<ToolProvider>
|
||||
<main className="h-screen grid grid-rows-[2.5rem_minmax(0,1fr)] grid-cols-[2.5rem_minmax(0,1fr)_auto]">
|
||||
<Menubar />
|
||||
<Toolbar />
|
||||
<Canvas />
|
||||
<ToolSettings />
|
||||
</main>
|
||||
</ToolProvider>
|
||||
</TexturesProvider>
|
||||
</SettingsProvider>
|
||||
</LoadingProvider>
|
||||
</ImageProvider>
|
||||
<LoadingProvider>
|
||||
<SettingsProvider>
|
||||
<TexturesProvider>
|
||||
<ToolProvider>
|
||||
<main className="h-screen grid grid-rows-[2.5rem_minmax(0,1fr)] grid-cols-[2.5rem_minmax(0,1fr)_auto]">
|
||||
<Menubar />
|
||||
<Toolbar />
|
||||
<Canvas />
|
||||
<ToolSettings />
|
||||
</main>
|
||||
</ToolProvider>
|
||||
</TexturesProvider>
|
||||
</SettingsProvider>
|
||||
</LoadingProvider>
|
||||
</CanvasProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue