mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Color render working
This commit is contained in:
parent
2bee6142be
commit
ce1873147c
@ -22,11 +22,11 @@ export function* chaosGameFinal({width, height, transforms, final, quality, step
|
||||
[x, y] = transform(x, y);
|
||||
|
||||
// highlight-start
|
||||
[x, y] = final(x, y);
|
||||
const [finalX, finalY] = final(x, y);
|
||||
// highlight-end
|
||||
|
||||
if (i > 20)
|
||||
plot(x, y, image);
|
||||
plot(finalX, finalY, image);
|
||||
|
||||
if (i % step === 0)
|
||||
yield image;
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
@ -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);
|
||||
}
|
@ -8,7 +8,7 @@ export type ChaosGameHistogramProps = ChaosGameFinalProps & {
|
||||
painter: (width: number, histogram: Uint32Array) => ImageData;
|
||||
}
|
||||
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;
|
||||
|
||||
const histogram = new Uint32Array(width * height);
|
||||
|
29
blog/2024-11-15-playing-with-fire/3-log-density/color.ts
Normal file
29
blog/2024-11-15-playing-with-fire/3-log-density/color.ts
Normal 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;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
authors: [bspeice]
|
||||
tags: []
|
||||
@ -32,10 +32,16 @@ import Canvas from "../src/Canvas";
|
||||
import FlameHistogram from "./FlameHistogram";
|
||||
import {paintLinear} from "./paintLinear";
|
||||
|
||||
<Canvas><FlameHistogram quality={5} paintFn={paintLinear}/></Canvas>
|
||||
<!-- <Canvas><FlameHistogram quality={0.5} paintFn={paintLinear}/></Canvas> -->
|
||||
|
||||
## Log display
|
||||
|
||||
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>
|
@ -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: []
|
||||
---
|
@ -76,7 +76,7 @@ export const xforms: [number, Transform][] = [
|
||||
|
||||
export const xformFinal: Transform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, xformFinalVariations));
|
||||
|
||||
export const palette =
|
||||
export const paletteString =
|
||||
"7E3037762C45722B496E2A4E6A2950672853652754632656" +
|
||||
"5C265C5724595322574D2155482153462050451F4E441E4D" +
|
||||
"431E4C3F1E473F1E453F1E433F1E3F3F1E3B3E1E393E1E37" +
|
||||
@ -109,3 +109,13 @@ export const palette =
|
||||
"E9A411E5A313E1A113DD9F13D99D14D49C15D09815CC9518" +
|
||||
"C79318C38F1ABE8B1AB9871DB4811FB07D1FAB7621A67123" +
|
||||
"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);
|
Loading…
Reference in New Issue
Block a user