mirror of
https://github.com/bspeice/speice.io
synced 2025-07-29 03:25:03 -04:00
Flame blending example
This commit is contained in:
44
blog/2024-11-15-playing-with-fire/src/camera.ts
Normal file
44
blog/2024-11-15-playing-with-fire/src/camera.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Translate values in the flame coordinate system to pixel coordinates
|
||||
*
|
||||
* The way `flam3` actually calculates the "camera" for mapping a point
|
||||
* to its pixel coordinate is fairly involved - it also needs to calculate
|
||||
* zoom and rotation (see the bucket accumulator code in rect.c).
|
||||
* We'll make some simplifying assumptions:
|
||||
* - The final image is square
|
||||
* - We want to plot the range [-2, 2]
|
||||
*
|
||||
* The reference parameters were designed in Apophysis, which uses the
|
||||
* range [-2, 2] by default (the `scale` parameter in XML defines the
|
||||
* "pixels per unit", and with the default zoom, is chosen to give a
|
||||
* range of [-2, 2]).
|
||||
*
|
||||
* @param x point in the range [-2, 2]
|
||||
* @param y point in the range [-2, 2]
|
||||
* @param size image size
|
||||
* @returns pair of pixel coordinates
|
||||
*/
|
||||
export function camera(x: number, y: number, size: number): [number, number] {
|
||||
return [Math.floor(((x + 2) * size) / 4), Math.floor(((y + 2) * size) / 4)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate values in pixel coordinates to a 1-dimensional array index
|
||||
*
|
||||
* Unlike the camera function, this mapping doesn't assume a square image,
|
||||
* and only requires knowing the image width.
|
||||
*
|
||||
* The stride parameter is used to calculate indices that take into account
|
||||
* how many "values" each pixel has. For example, in an ImageData, each pixel
|
||||
* has a red, green, blue, and alpha component per pixel, so a stride of 4
|
||||
* is appropriate. For situations where there are separate red/green/blue/alpha
|
||||
* arrays per pixel, a stride of 1 is appropriate
|
||||
*
|
||||
* @param x point in the range [0, size)
|
||||
* @param y point in the range [0, size)
|
||||
* @param width width of image in pixel units
|
||||
* @param stride values per pixel coordinate
|
||||
*/
|
||||
export function histIndex(x: number, y: number, width: number, stride: number): number {
|
||||
return y * (width * stride) + x * stride;
|
||||
}
|
@ -1,4 +1,11 @@
|
||||
export interface Coefs {
|
||||
a: number, b: number, c: number,
|
||||
d: number, e: number, f: number
|
||||
}
|
||||
|
||||
export function applyCoefs(x: number, y: number, coefs: Coefs) {
|
||||
return [
|
||||
(x * coefs.a + y * coefs.b + coefs.c),
|
||||
(x * coefs.d + y * coefs.e + coefs.f)
|
||||
]
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
.inputDiv {
|
||||
padding-left: .5em;
|
||||
padding-right: 1em;
|
||||
}
|
@ -7,13 +7,18 @@ import { Coefs } from './coefs';
|
||||
import { linear } from './linear'
|
||||
import { julia } from './julia'
|
||||
import { popcorn } from './popcorn'
|
||||
import { pdj } from './pdj'
|
||||
import {pdj, PdjParams} from './pdj'
|
||||
import {Variation} from "./variation"
|
||||
|
||||
export const identityCoefs: Coefs = {
|
||||
a: 1, b: 0, c: 0,
|
||||
d: 0, e: 1, f: 0,
|
||||
}
|
||||
|
||||
export const pdjParams: PdjParams = {
|
||||
a: 1.09358, b: 2.13048, c: 2.54127, d: 2.37267
|
||||
}
|
||||
|
||||
export const xform1Weight = 0.56453495;
|
||||
export const xform1Coefs = {
|
||||
a: -1.381068, b: -1.381068, c: 0,
|
||||
@ -47,7 +52,7 @@ export const xform3Coefs = {
|
||||
}
|
||||
export const xform3CoefsPost = identityCoefs;
|
||||
export const xform3Variations = [
|
||||
[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]
|
||||
[1, pdj(pdjParams)]
|
||||
];
|
||||
export const xform3Color = 0.349;
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
// hidden-start
|
||||
import { Variation } from './variation'
|
||||
//hidden-end
|
||||
export function pdj(a: number, b: number, c: number, d: number): Variation {
|
||||
export type PdjParams = {a: number, b: number, c: number, d: number};
|
||||
export function pdj({a, b, c, d}: PdjParams): Variation {
|
||||
return (x, y) => [
|
||||
Math.sin(a * y) - Math.cos(b * x),
|
||||
Math.sin(c * x) - Math.cos(d * y)
|
||||
|
17
blog/2024-11-15-playing-with-fire/src/plotBinary.ts
Normal file
17
blog/2024-11-15-playing-with-fire/src/plotBinary.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { camera, histIndex } from "./camera"
|
||||
|
||||
export function plotBinary(x: number, y: number, image: ImageData) {
|
||||
const [pixelX, pixelY] = camera(x, y, image.width);
|
||||
if (
|
||||
pixelX < 0 || pixelX >= image.width || pixelY < 0 || pixelY > image.height
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pixelIndex = histIndex(pixelX, pixelY, image.width, 4);
|
||||
|
||||
image.data[pixelIndex] = 0;
|
||||
image.data[pixelIndex + 1] = 0;
|
||||
image.data[pixelIndex + 2] = 0;
|
||||
image.data[pixelIndex + 3] = 0xff;
|
||||
}
|
@ -1,9 +1 @@
|
||||
import { Coefs } from './coefs'
|
||||
import { Variation } from './variation'
|
||||
|
||||
export interface Transform {
|
||||
coefs: Coefs,
|
||||
variations: [number, Variation][],
|
||||
coefsPost: Coefs,
|
||||
color: number
|
||||
}
|
||||
export type Transform = (x: number, y: number) => [number, number];
|
Reference in New Issue
Block a user