The plasma effect is a visual effect created by applying various functions, notably sine and cosine, to the color values of screen pixels. When animated (not a task requirement) the effect may give the impression of a colorful flowing liquid.



Task
Create a plasma effect.




See also
 Computer Graphics Tutorial (lodev.org)
 Plasma (bidouille.org)


 
import javafx.application {
    Application
}
import javafx.stage {
    Stage
}
import javafx.scene {
    Scene
}
import javafx.scene.layout {
    BorderPane
}
import javafx.scene.image {
    WritableImage,
    ImageView
}
import ceylon.numeric.float {
    sin,
    sqrt,
    remainder
}
import javafx.scene.paint {
    Color
}
import javafx.animation {
    AnimationTimer
}
 
shared void run() {
    Application.launch(`Plasma`);
}
 
shared class Plasma() extends Application() {
 
    function createPlasma(Integer width, Integer height) => [
        for (j in 0:height) [
            for (i in 0:width)
            let (x = i.float, y = j.float)
            ( sin(x / 16.0)
            + sin(y / 8.0)
            + sin((x + y) / 16.0)
            + sin(sqrt(x ^ 2.0 + y ^ 2.0) / 8.0)
            + 4.0 )
            / 8.0
        ]
    ];
 
    void writeImage(Float[][] plasma, WritableImage img, Float hueShift = 0.0) {
        value writer = img.pixelWriter;
        for(j->row in plasma.indexed) {
            for(i->percent in row.indexed) {
                value hue = remainder(hueShift + percent, 1.0)  * 360.0;
                writer.setColor(i, j, Color.hsb(hue, 1.0, 1.0));
            }
        }
    }
 
    shared actual void start(Stage primaryStage) {
 
        value w = 500;
        value h = 500;
        value plasma = createPlasma(w, h);
        value img = WritableImage(w, h);
        writeImage(plasma, img);
 
        value root = BorderPane();
        root.center = ImageView(img);
 
        variable value hueShift = 0.0;
        value timer = object extends AnimationTimer() {
            shared actual void handle(Integer now) {
                hueShift = remainder(hueShift + 0.02, 1.0);
                writeImage(plasma, img, hueShift);
            }
        };
        timer.start();
 
        value scene = Scene(root);
        primaryStage.title = "Plasma";
        primaryStage.setScene(scene);
        primaryStage.sizeToScene();
        primaryStage.show();
    }
 
}