Color render working

This commit is contained in:
Bradlee Speice 2024-12-02 22:36:25 -05:00
parent 2bee6142be
commit ce1873147c
8 changed files with 138 additions and 14 deletions

View File

@ -22,11 +22,11 @@ export function* chaosGameFinal({width, height, transforms, final, quality, step
[x, y] = transform(x, y); [x, y] = transform(x, y);
// highlight-start // highlight-start
[x, y] = final(x, y); const [finalX, finalY] = final(x, y);
// highlight-end // highlight-end
if (i > 20) if (i > 20)
plot(x, y, image); plot(finalX, finalY, image);
if (i % step === 0) if (i % step === 0)
yield image; yield image;

View File

@ -0,0 +1,37 @@
import React, {useContext, useEffect, useState} from "react";
import * as params from "../src/params";
import {PainterContext} from "../src/Canvas";
import {chaosGameColor} from "./chaosGameColor";
type Props = {
quality?: number;
children?: React.ReactElement;
}
export default function FlameHistogram({quality, children}: Props) {
const {width, height, setPainter} = useContext(PainterContext);
const [counter, setCount] = useState(0);
const [xform1Color, setXform1Color] = useState(params.xform1Color);
const [xform2Color, setXform2Color] = useState(params.xform2Color);
const [xform3Color, setXform3Color] = useState(params.xform3Color);
useEffect(() => {
const gameParams = {
width,
height,
transforms: params.xforms,
final: params.xformFinal,
quality,
palette: params.palette,
colors: [xform1Color, xform2Color, xform3Color]
}
setPainter(chaosGameColor(gameParams));
}, [counter, xform1Color, xform2Color, xform3Color]);
return (
<>
{children}
<button onClick={() => setCount(counter + 1)}>Re-render {counter}</button>
</>
);
}

View File

@ -0,0 +1,49 @@
import {ChaosGameFinalProps} from "../2-transforms/chaosGameFinal";
import {randomBiUnit} from "../src/randomBiUnit";
import {randomChoice} from "../src/randomChoice";
import {camera, histIndex} from "../src/camera";
import {colorFromPalette, paintColor} from "./color";
type ChaosGameHistogramProps = ChaosGameFinalProps & {
palette: number[];
colors: number[];
}
export function* chaosGameColor({width, height, transforms, final, palette, colors, quality, step}: ChaosGameHistogramProps) {
let iterations = (quality ?? 1) * width * height;
step = step ?? 100_000;
let currentColor = Math.random();
const red = Array(width * height).fill(0);
const green = Array(width * height).fill(0);
const blue = Array(width * height).fill(0);
const alpha = Array(width * height).fill(0);
let [x, y] = [randomBiUnit(), randomBiUnit()];
for (let i = 0; i < iterations; i++) {
const [transformIndex, transform] = randomChoice(transforms);
[x, y] = transform(x, y);
const [finalX, finalY] = final(x, y);
if (i > 20) {
const [pixelX, pixelY] = camera(finalX, finalY, width);
const pixelIndex = histIndex(pixelX, pixelY, width, 1);
if (pixelIndex < 0 || pixelIndex >= alpha.length)
continue;
currentColor = (currentColor + colors[transformIndex]) / 2;
const [r, g, b] = colorFromPalette(palette, currentColor);
red[pixelIndex] += r;
green[pixelIndex] += g;
blue[pixelIndex] += b;
alpha[pixelIndex] += 1;
}
if (i % step === 0)
yield paintColor(width, height, red, green, blue, alpha);
}
yield paintColor(width, height, red, green, blue, alpha);
}

View File

@ -8,7 +8,7 @@ export type ChaosGameHistogramProps = ChaosGameFinalProps & {
painter: (width: number, histogram: Uint32Array) => ImageData; painter: (width: number, histogram: Uint32Array) => ImageData;
} }
export function* chaosGameHistogram({width, height, transforms, final, quality, step, painter}: ChaosGameHistogramProps) { export function* chaosGameHistogram({width, height, transforms, final, quality, step, painter}: ChaosGameHistogramProps) {
let iterations = (quality ?? 10) * width * height; let iterations = (quality ?? 1) * width * height;
step = step ?? 100_000; step = step ?? 100_000;
const histogram = new Uint32Array(width * height); const histogram = new Uint32Array(width * height);

View File

@ -0,0 +1,29 @@
import {histIndex} from "../src/camera";
export function colorFromPalette(palette: number[], colorIndex: number): [number, number, number] {
const paletteIndex = Math.floor(colorIndex * (palette.length / 3)) * 3;
return [palette[paletteIndex], palette[paletteIndex + 1], palette[paletteIndex + 2]];
}
export function paintColor(
width: number,
height: number,
red: number[],
green: number[],
blue: number[],
alpha: number[]
): ImageData {
const image = new ImageData(width, height);
for (let i = 0; i < width * height; i++) {
const alphaScale = Math.log10(alpha[i]) / (alpha[i] * 1.5);
const pixelIndex = i * 4;
image.data[pixelIndex] = red[i] * alphaScale * 0xff;
image.data[pixelIndex + 1] = green[i] * alphaScale * 0xff;
image.data[pixelIndex + 2] = blue[i] * alphaScale * 0xff;
image.data[pixelIndex + 3] = alpha[i] * alphaScale * 0xff;
}
return image;
}

View File

@ -1,6 +1,6 @@
--- ---
slug: 2024/11/playing-with-fire-log-density slug: 2024/11/playing-with-fire-log-density
title: "Playing with fire: Log-density display" title: "Playing with fire: Log-density and color"
date: 2024-11-15 14:00:00 date: 2024-11-15 14:00:00
authors: [bspeice] authors: [bspeice]
tags: [] tags: []
@ -32,10 +32,16 @@ import Canvas from "../src/Canvas";
import FlameHistogram from "./FlameHistogram"; import FlameHistogram from "./FlameHistogram";
import {paintLinear} from "./paintLinear"; import {paintLinear} from "./paintLinear";
<Canvas><FlameHistogram quality={5} paintFn={paintLinear}/></Canvas> <!-- <Canvas><FlameHistogram quality={0.5} paintFn={paintLinear}/></Canvas> -->
## Log display ## Log display
import {paintLogarithmic} from './paintLogarithmic' import {paintLogarithmic} from './paintLogarithmic'
<Canvas><FlameHistogram quality={10} paintFn={paintLogarithmic}/></Canvas> <!-- <Canvas><FlameHistogram quality={0.5} paintFn={paintLogarithmic}/></Canvas> -->
## Color
import FlameColor from "./FlameColor";
<Canvas><FlameColor quality={10}/></Canvas>

View File

@ -1,7 +0,0 @@
---
slug: 2024/11/playing-with-fire-color
title: "Playing with fire: Color"
date: 2024-11-15 15:00:00
authors: [bspeice]
tags: []
---

View File

@ -76,7 +76,7 @@ export const xforms: [number, Transform][] = [
export const xformFinal: Transform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, xformFinalVariations)); export const xformFinal: Transform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, xformFinalVariations));
export const palette = export const paletteString =
"7E3037762C45722B496E2A4E6A2950672853652754632656" + "7E3037762C45722B496E2A4E6A2950672853652754632656" +
"5C265C5724595322574D2155482153462050451F4E441E4D" + "5C265C5724595322574D2155482153462050451F4E441E4D" +
"431E4C3F1E473F1E453F1E433F1E3F3F1E3B3E1E393E1E37" + "431E4C3F1E473F1E453F1E433F1E3F3F1E3B3E1E393E1E37" +
@ -109,3 +109,13 @@ export const palette =
"E9A411E5A313E1A113DD9F13D99D14D49C15D09815CC9518" + "E9A411E5A313E1A113DD9F13D99D14D49C15D09815CC9518" +
"C79318C38F1ABE8B1AB9871DB4811FB07D1FAB7621A67123" + "C79318C38F1ABE8B1AB9871DB4811FB07D1FAB7621A67123" +
"A16A249C6227975E289256298E502A89482C853F2D803A2E" "A16A249C6227975E289256298E502A89482C853F2D803A2E"
function hexToBytes(hex: string) {
let bytes: number[] = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substring(i, i + 2), 16));
}
return bytes;
}
export const palette = hexToBytes(paletteString).map(value => value / 0xff);