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 { 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 { 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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue