Attempt to generalize

This commit is contained in:
2024-11-23 15:26:48 -05:00
parent aba3c9f988
commit e2a0ee1d72
11 changed files with 177 additions and 44 deletions

View File

@ -0,0 +1,99 @@
import {createContext, useEffect, useRef, useState} from "react";
import {Transform} from "./transform";
import {randomBiUnit} from "./randomBiunit";
import {useColorMode} from "@docusaurus/theme-common";
import {randomChoice} from "./randomChoice";
export interface Flame {
transforms: [number, Transform][];
final: Transform;
palette: Uint8Array;
}
interface IFlameContext {
setQuality?: (quality: number) => void;
setFlame?: (flame: Flame) => void;
}
export const FlameContext = createContext<IFlameContext>({});
abstract class Renderer {
protected readonly _size: number;
protected _x: number = randomBiUnit();
protected _y: number = randomBiUnit();
protected _iterations: number = 0;
protected _flame?: Flame;
protected constructor(size: number) {
this._size = size;
}
abstract plot(x: number, y: number, c: number): void;
abstract run(iterations: number): void;
abstract paint(image: ImageData): void;
public get size(): number {
return this._size;
}
public get iterations(): number {
return this._iterations;
}
public set flame(value: Flame) {
[this._x, this._y] = [randomBiUnit(), randomBiUnit()];
this._iterations = 0;
}
}
export interface Props {
renderer: Renderer;
children?: React.ReactNode;
}
export const FlameCanvas: React.FC<Props> = ({renderer, children}) => {
const ITER_STEP = 10000;
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const colorMode = useColorMode();
const [quality, setQuality] = useState<number>();
const [flame, setFlame] = useState<Flame>(null);
var image: ImageData = null;
function animate() {
renderer.run(ITER_STEP);
paint();
if (renderer.iterations < quality * renderer.size * renderer.size) {
requestAnimationFrame(this);
}
}
function paint() {
}
useEffect(() => {
renderer.flame = flame;
requestAnimationFrame(animate);
}, [quality, flame]);
useEffect(() => { paint(); }, [colorMode]);
return (
<FlameContext.Provider value={{setFlame, setQuality}}>
<canvas
ref={canvasRef}
width={renderer.size}
height={renderer.size}
style={{
aspectRatio: '1 / 1',
width: '100%',
}}
/>
{children}
</FlameContext.Provider>
)
}

View File

@ -0,0 +1,3 @@
export function randomBiUnit() {
return Math.random() * 2 - 1;
}

View File

@ -0,0 +1,22 @@
/**
* @param choices array of [weight, value] pairs
* @returns pair of [index, value]
*/
export function randomChoice<T>(choices: [number, T][]): [number, T] {
const weightSum = choices.reduce(
(current, [weight, _]) => current + weight,
0
);
var choice = Math.random() * weightSum;
for (var i = 0; i < choices.length; i++) {
const [weight, t] = choices[i];
if (choice < weight) {
return [i, t];
}
choice -= weight;
}
throw "unreachable";
}

View File

@ -0,0 +1,3 @@
export function randomInteger(min: number, max: number) {
return Math.floor(Math.random() * (max - min)) + min;
}

View File

@ -4,6 +4,7 @@ import { Variation } from './variations'
export interface Transform {
coefs: Coefs,
variations: [number, Variation][],
coefsPost: Coefs,
color: number
enabled: boolean,
coefsPost?: Coefs,
color?: number
}