mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Incremental rendering
This commit is contained in:
parent
22a4ffff7c
commit
4c3f4246a4
@ -1,24 +1,40 @@
|
|||||||
// Hint: try increasing the iteration count
|
function Gasket() {
|
||||||
const iterations = 10000;
|
// Hint: try increasing the iteration count
|
||||||
|
const iterations = 10000;
|
||||||
|
|
||||||
// Hint: negating `x` and `y` creates some interesting images
|
// Hint: negating `x` and `y` creates some interesting images
|
||||||
const functions = [
|
const functions = [
|
||||||
(x, y) => [x / 2, y / 2],
|
(x, y) => [x / 2, y / 2],
|
||||||
(x, y) => [(x + 1) / 2, y / 2],
|
(x, y) => [(x + 1) / 2, y / 2],
|
||||||
(x, y) => [x / 2, (y + 1) / 2]
|
(x, y) => [x / 2, (y + 1) / 2]
|
||||||
]
|
]
|
||||||
|
|
||||||
function chaosGame(image) {
|
const image = new ImageData(600, 600);
|
||||||
var [x, y] = [randomBiUnit(), randomBiUnit()];
|
function* chaosGame() {
|
||||||
|
var [x, y] = [randomBiUnit(), randomBiUnit()];
|
||||||
|
|
||||||
for (var count = 0; count < iterations; count++) {
|
for (var count = 0; count < iterations; count++) {
|
||||||
const i = randomInteger(0, functions.length);
|
const i = randomInteger(0, functions.length);
|
||||||
[x, y] = functions[i](x, y);
|
[x, y] = functions[i](x, y);
|
||||||
|
|
||||||
if (count > 20) {
|
if (count > 20) {
|
||||||
plot(x, y, image);
|
plot(x, y, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count % 1000 === 0) {
|
||||||
|
yield image;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Canvas
|
||||||
|
width={image.width}
|
||||||
|
height={image.height}
|
||||||
|
painter={chaosGame()}/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render(<Gasket renderFn={chaosGame}/>)
|
render(<Gasket/>)
|
||||||
|
@ -1,30 +1,12 @@
|
|||||||
import React, {useContext, useEffect} from "react";
|
|
||||||
import randomBiUnit from './biunit';
|
import randomBiUnit from './biunit';
|
||||||
import plot from './plot';
|
import plot from './plot';
|
||||||
import randomInteger from './randint';
|
import randomInteger from './randint';
|
||||||
import Canvas, {ImageContext} from "../src/Canvas";
|
import Canvas from "../src/Canvas";
|
||||||
|
|
||||||
interface Props {
|
|
||||||
renderFn: (image: ImageData) => void;
|
|
||||||
}
|
|
||||||
function Render({renderFn}: Props) {
|
|
||||||
const {width, height, setImage} = useContext(ImageContext);
|
|
||||||
const image = new ImageData(width, height);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
renderFn(image);
|
|
||||||
setImage(image);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Scope = {
|
const Scope = {
|
||||||
plot,
|
plot,
|
||||||
randomBiUnit,
|
randomBiUnit,
|
||||||
randomInteger,
|
randomInteger,
|
||||||
Canvas,
|
Canvas
|
||||||
Gasket: ({renderFn}: Props) =>
|
|
||||||
<Canvas width={600} height={600}><Render renderFn={renderFn}/></Canvas>
|
|
||||||
}
|
}
|
||||||
export default Scope;
|
export default Scope;
|
@ -1,49 +1,54 @@
|
|||||||
import React, {createContext, useCallback, useContext, useEffect, useRef, useState} from "react";
|
import React, {useCallback, useEffect, useState} from "react";
|
||||||
import {useColorMode} from "@docusaurus/theme-common";
|
import {useColorMode} from "@docusaurus/theme-common";
|
||||||
|
|
||||||
interface IImageContext {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
setImage: (image: ImageData) => void;
|
|
||||||
}
|
|
||||||
export const ImageContext = createContext<IImageContext>(null);
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
painter: Iterator<ImageData>;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
export default function Canvas({width, height, children}) {
|
export default function Canvas({width, height, painter, children}: Props) {
|
||||||
const [canvasCtx, setCanvasCtx] = useState<CanvasRenderingContext2D | null>(null);
|
const {colorMode} = useColorMode();
|
||||||
|
const [image, setImage] = useState<[ImageData]>(null);
|
||||||
|
|
||||||
|
const [canvasCtx, setCanvasCtx] = useState<CanvasRenderingContext2D>(null);
|
||||||
const canvasRef = useCallback(node => {
|
const canvasRef = useCallback(node => {
|
||||||
if (node !== null) {
|
if (node !== null) {
|
||||||
setCanvasCtx(node.getContext("2d"));
|
setCanvasCtx(node.getContext("2d"));
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const {colorMode} = useColorMode();
|
|
||||||
const [image, setImage] = useState<ImageData>(new ImageData(width, height));
|
|
||||||
const paintImage = new ImageData(width, height);
|
const paintImage = new ImageData(width, height);
|
||||||
|
const paint = () => {
|
||||||
useEffect(() => {
|
if (!canvasCtx || !image) {
|
||||||
if (!canvasCtx) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [index, value] of image.data.entries()) {
|
for (const [index, value] of image[0].data.entries()) {
|
||||||
// If dark mode is active, invert the color scheme
|
if (index % 4 === 3) {
|
||||||
const adjustValue = colorMode === 'light' ? value : 255 - value;
|
// Alpha values are copied as-is
|
||||||
|
paintImage.data[index] = value;
|
||||||
// Alpha values never change
|
} else {
|
||||||
paintImage.data[index] = index % 4 === 3 ? value : adjustValue;
|
// If dark mode is active, invert the color
|
||||||
|
paintImage.data[index] = colorMode === 'light' ? value : 255 - value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Painting image");
|
|
||||||
canvasCtx.putImageData(paintImage, 0, 0);
|
canvasCtx.putImageData(paintImage, 0, 0);
|
||||||
}, [canvasCtx, colorMode, image]);
|
}
|
||||||
|
useEffect(paint, [colorMode, image]);
|
||||||
|
|
||||||
|
const animate = () => {
|
||||||
|
const nextImage = painter.next().value;
|
||||||
|
if (nextImage) {
|
||||||
|
setImage([nextImage])
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
useEffect(animate, [canvasCtx]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageContext.Provider value={{width, height, setImage}}>
|
<>
|
||||||
<canvas
|
<canvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
width={width}
|
width={width}
|
||||||
@ -54,6 +59,6 @@ export default function Canvas({width, height, children}) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</ImageContext.Provider>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user