mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Convert baseline renderer to animation
This commit is contained in:
parent
782b00320b
commit
7f44243cd0
@ -35,14 +35,16 @@ export type CanvasParams = {
|
|||||||
size: number;
|
size: number;
|
||||||
qualityMax: number;
|
qualityMax: number;
|
||||||
qualityStep: number;
|
qualityStep: number;
|
||||||
renderer: Renderer;
|
renderer: (size: number) => Renderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CanvasRenderer: React.FC<{ params: CanvasParams }> = ({
|
export const CanvasRenderer: React.FC<{ params: CanvasParams }> = ({
|
||||||
params,
|
params,
|
||||||
}) => {
|
}) => {
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
var qualityCurrent: number = 0;
|
var qualityCurrent: number = 0;
|
||||||
|
var rendererCurrent: Renderer = params.renderer(params.size);
|
||||||
|
|
||||||
const animate = () => {
|
const animate = () => {
|
||||||
const ctx = canvasRef.current?.getContext("2d");
|
const ctx = canvasRef.current?.getContext("2d");
|
||||||
@ -51,21 +53,34 @@ export const CanvasRenderer: React.FC<{ params: CanvasParams }> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const image = ctx.createImageData(params.size, params.size);
|
const image = ctx.createImageData(params.size, params.size);
|
||||||
params.renderer.run(params.qualityStep);
|
rendererCurrent.run(params.qualityStep);
|
||||||
params.renderer.render(image);
|
rendererCurrent.render(image);
|
||||||
ctx.putImageData(image, 0, 0);
|
ctx.putImageData(image, 0, 0);
|
||||||
|
|
||||||
qualityCurrent += params.qualityStep;
|
|
||||||
if (qualityCurrent < params.qualityMax) {
|
if (qualityCurrent < params.qualityMax) {
|
||||||
|
qualityCurrent += params.qualityStep;
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
qualityCurrent = 0;
|
||||||
|
rendererCurrent = params.renderer(params.size);
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvasRef.current) {
|
if (canvasRef.current) {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <canvas ref={canvasRef} width={params.size} height={params.size} />;
|
return (
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef}
|
||||||
|
width={params.size}
|
||||||
|
height={params.size}
|
||||||
|
onClick={reset}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { CanvasParams } from "./0-canvas";
|
||||||
import {
|
import {
|
||||||
randomBiUnit,
|
randomBiUnit,
|
||||||
randomInteger,
|
randomInteger,
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
import { randomBiUnit, weightedChoice } from "./0-utility";
|
import {
|
||||||
|
Renderer,
|
||||||
|
histIndex,
|
||||||
|
imageIndex,
|
||||||
|
randomBiUnit,
|
||||||
|
weightedChoice,
|
||||||
|
} from "./0-utility";
|
||||||
|
|
||||||
export type Variation = (
|
export type Variation = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
transformCoefs: Coefs
|
transformCoefs: Coefs
|
||||||
) => [number, number];
|
) => [number, number];
|
||||||
|
|
||||||
export type Coefs = {
|
export type Coefs = {
|
||||||
a: number;
|
a: number;
|
||||||
b: number;
|
b: number;
|
||||||
@ -83,6 +90,66 @@ export class Transform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RendererFlame extends Renderer {
|
||||||
|
private values = new Uint8Array(this.size * this.size);
|
||||||
|
|
||||||
|
constructor(size: number, public readonly transforms: [number, Transform][]) {
|
||||||
|
super(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
plot(x: number, y: number) {
|
||||||
|
// By default, Apophysis uses a camera that covers the range [-2, 2]
|
||||||
|
// (specifically, the `scale` parameter becomes `pixels_per_unit` in flam3)
|
||||||
|
// Shift the coordinate system to [0, 4], then scale to pixel coordinates
|
||||||
|
const pixelX = Math.floor(((x + 2) * this.size) / 4);
|
||||||
|
const pixelY = Math.floor(((y + 2) * this.size) / 4);
|
||||||
|
|
||||||
|
if (
|
||||||
|
pixelX < 0 ||
|
||||||
|
pixelX >= this.size ||
|
||||||
|
pixelY < 0 ||
|
||||||
|
pixelY >= this.size
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hIndex = histIndex(pixelX, pixelY, this.size);
|
||||||
|
this.values[hIndex] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
run(quality: number): void {
|
||||||
|
var x = randomBiUnit();
|
||||||
|
var y = randomBiUnit();
|
||||||
|
|
||||||
|
const iterations = quality * this.size * this.size;
|
||||||
|
for (var i = 0; i < iterations; i++) {
|
||||||
|
const [_, transform] = weightedChoice(this.transforms);
|
||||||
|
[x, y] = transform.apply(x, y);
|
||||||
|
|
||||||
|
if (i > 20) {
|
||||||
|
this.plot(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(image: ImageData): void {
|
||||||
|
for (var x = 0; x < this.size; x++) {
|
||||||
|
for (var y = 0; y < this.size; y++) {
|
||||||
|
const hIndex = histIndex(x, y, this.size);
|
||||||
|
if (!this.values[hIndex]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iIndex = imageIndex(x, y, this.size);
|
||||||
|
image.data[iIndex + 0] = 0;
|
||||||
|
image.data[iIndex + 1] = 0;
|
||||||
|
image.data[iIndex + 2] = 0;
|
||||||
|
image.data[iIndex + 3] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Flame {
|
export class Flame {
|
||||||
protected x: number = randomBiUnit();
|
protected x: number = randomBiUnit();
|
||||||
protected y: number = randomBiUnit();
|
protected y: number = randomBiUnit();
|
||||||
@ -186,12 +253,10 @@ export const transform3 = new Transform(
|
|||||||
[[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]]
|
[[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]]
|
||||||
);
|
);
|
||||||
|
|
||||||
export function renderBaseline(image: ImageData) {
|
export function rendererBaseline(size: number) {
|
||||||
const flame = new Flame([
|
return new RendererFlame(size, [
|
||||||
[transform1Weight, transform1],
|
[transform1Weight, transform1],
|
||||||
[transform2Weight, transform2],
|
[transform2Weight, transform2],
|
||||||
[transform3Weight, transform3],
|
[transform3Weight, transform3],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
render(flame, 1, image);
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Blog from "../../../LayoutBlog";
|
|||||||
|
|
||||||
import { Canvas, CanvasRenderer } from "./0-canvas";
|
import { Canvas, CanvasRenderer } from "./0-canvas";
|
||||||
import { RendererGasket } from "./1-gasket";
|
import { RendererGasket } from "./1-gasket";
|
||||||
import { renderBaseline } from "./2a-variations";
|
import { rendererBaseline } from "./2a-variations";
|
||||||
import { renderPost } from "./2b-post";
|
import { renderPost } from "./2b-post";
|
||||||
import { renderFinal } from "./2c-final";
|
import { renderFinal } from "./2c-final";
|
||||||
import { renderBinary } from "./3a-binary";
|
import { renderBinary } from "./3a-binary";
|
||||||
@ -23,13 +23,22 @@ export default function () {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<CanvasRenderer
|
{/* <CanvasRenderer
|
||||||
params={{
|
params={{
|
||||||
defaultUrl: "",
|
defaultUrl: "",
|
||||||
size: 400,
|
size: 400,
|
||||||
renderer: new RendererGasket(400),
|
renderer: new RendererGasket(400),
|
||||||
qualityMax: 0.25,
|
qualityMax: 0.3,
|
||||||
qualityStep: 0.25,
|
qualityStep: 0.1,
|
||||||
|
}}
|
||||||
|
/> */}
|
||||||
|
<CanvasRenderer
|
||||||
|
params={{
|
||||||
|
defaultUrl: "",
|
||||||
|
size: 400,
|
||||||
|
renderer: (size) => rendererBaseline(size),
|
||||||
|
qualityMax: 1,
|
||||||
|
qualityStep: 0.1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <div>
|
{/* <div>
|
||||||
|
Loading…
Reference in New Issue
Block a user