Plasma effect

From Rosetta Code
Task
Plasma effect
You are encouraged to solve this task according to the task description, using any language you may know.

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



C[edit]

ASCII version for Windows[edit]

If you don't want to bother with Graphics libraries, try out this nifty implementation on Windows :

 
/*Abhishek Ghosh, 4th October 2017*/
 
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
 
#define pi M_PI
 
int main()
{
CONSOLE_SCREEN_BUFFER_INFO info;
int cols, rows;
time_t t;
int i,j;
 
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
cols = info.srWindow.Right - info.srWindow.Left + 1;
rows = info.srWindow.Bottom - info.srWindow.Top + 1;
 
HANDLE console;
 
console = GetStdHandle(STD_OUTPUT_HANDLE);
 
system("@clear||cls");
 
srand((unsigned)time(&t));
 
for(i=0;i<rows;i++)
for(j=0;j<cols;j++){
SetConsoleTextAttribute(console,fabs(sin(pi*(rand()%254 + 1)/255.0))*254);
printf("%c",219);
}
 
getchar();
 
return 0;
}
 

Graphics version[edit]

And here's the Graphics version, requires the WinBGIm library. Prints out usage on incorrect invocation.

 
/*Abhishek Ghosh, 4th October 2017*/
 
#include<graphics.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
 
#define pi M_PI
 
void plasmaScreen(int width,int height){
 
int x,y,sec;
double dx,dy,dv;
time_t t;
 
initwindow(width,height,"WinBGIm Plasma");
 
while(1){
time(&t);
sec = (localtime(&t))->tm_sec;
 
for(x=0;x<width;x++)
for(y=0;y<height;y++){
dx = x + .5 * sin(sec/5.0);
dy = y + .5 * cos(sec/3.0);
 
dv = sin(x*10 + sec) + sin(10*(x*sin(sec/2.0) + y*cos(sec/3.0)) + sec) + sin(sqrt(100*(dx*dx + dy*dy)+1) + sec);
 
setcolor(COLOR(255*fabs(sin(dv*pi)),255*fabs(sin(dv*pi + 2*pi/3)),255*fabs(sin(dv*pi + 4*pi/3))));
 
putpixel(x,y,getcolor());
}
delay(1000);
}
}
 
int main(int argC,char* argV[])
{
if(argC != 3)
printf("Usage : %s <Two positive integers separated by a space specifying screen size>",argV[0]);
else{
plasmaScreen(atoi(argV[1]),atoi(argV[2]));
}
return 0;
}
 

C++[edit]

Plasma.png

Windows version.

 
#include <windows.h>
#include <math.h>
#include <string>
 
const int BMP_SIZE = 240, MY_TIMER = 987654;
 
class myBitmap {
public:
myBitmap() : pen( NULL ), brush( NULL ), clr( 0 ), wid( 1 ) {}
~myBitmap() {
DeleteObject( pen ); DeleteObject( brush );
DeleteDC( hdc ); DeleteObject( bmp );
}
bool create( int w, int h ) {
BITMAPINFO bi;
ZeroMemory( &bi, sizeof( bi ) );
bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = w;
bi.bmiHeader.biHeight = -h;
 
HDC dc = GetDC( GetConsoleWindow() );
bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
if( !bmp ) return false;
 
hdc = CreateCompatibleDC( dc );
SelectObject( hdc, bmp );
ReleaseDC( GetConsoleWindow(), dc );
 
width = w; height = h;
return true;
}
void clear( BYTE clr = 0 ) {
memset( pBits, clr, width * height * sizeof( DWORD ) );
}
void setBrushColor( DWORD bClr ) {
if( brush ) DeleteObject( brush );
brush = CreateSolidBrush( bClr );
SelectObject( hdc, brush );
}
void setPenColor( DWORD c ) {
clr = c; createPen();
}
void setPenWidth( int w ) {
wid = w; createPen();
}
void saveBitmap( std::string path ) {
BITMAPFILEHEADER fileheader;
BITMAPINFO infoheader;
BITMAP bitmap;
DWORD wb;
 
GetObject( bmp, sizeof( bitmap ), &bitmap );
DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
 
ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
 
infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
infoheader.bmiHeader.biCompression = BI_RGB;
infoheader.bmiHeader.biPlanes = 1;
infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
infoheader.bmiHeader.biHeight = bitmap.bmHeight;
infoheader.bmiHeader.biWidth = bitmap.bmWidth;
infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
 
fileheader.bfType = 0x4D42;
fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
 
GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
 
HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
CloseHandle( file );
 
delete [] dwpBits;
}
HDC getDC() const { return hdc; }
DWORD* bits() { return ( DWORD* )pBits; }
private:
void createPen() {
if( pen ) DeleteObject( pen );
pen = CreatePen( PS_SOLID, wid, clr );
SelectObject( hdc, pen );
}
HBITMAP bmp; HDC hdc;
HPEN pen; HBRUSH brush;
void *pBits; int width, height, wid;
DWORD clr;
};
class plasma
{
public:
plasma() {
currentTime = 0; _WD = BMP_SIZE >> 1; _WV = BMP_SIZE << 1;
_bmp.create( BMP_SIZE, BMP_SIZE ); _bmp.clear();
plasma1 = new BYTE[BMP_SIZE * BMP_SIZE * 4];
plasma2 = new BYTE[BMP_SIZE * BMP_SIZE * 4];
int i, j, dst = 0;
double temp;
for( j = 0; j < BMP_SIZE * 2; j++ ) {
for( i = 0; i < BMP_SIZE * 2; i++ ) {
plasma1[dst] = ( BYTE )( 128.0 + 127.0 * ( cos( ( double )hypot( BMP_SIZE - j, BMP_SIZE - i ) / 64.0 ) ) );
plasma2[dst] = ( BYTE )( ( sin( ( sqrt( 128.0 + ( BMP_SIZE - i ) * ( BMP_SIZE - i ) +
( BMP_SIZE - j ) * ( BMP_SIZE - j ) ) - 4.0 ) / 32.0 ) + 1 ) * 90.0 );
dst++;
}
}
}
void update() {
DWORD dst;
BYTE a, c1,c2, c3;
currentTime += ( double )( rand() % 2 + 1 );
 
int x1 = _WD + ( int )( ( _WD - 1 ) * sin( currentTime / 137 ) ),
x2 = _WD + ( int )( ( _WD - 1 ) * sin( -currentTime / 75 ) ),
x3 = _WD + ( int )( ( _WD - 1 ) * sin( -currentTime / 125 ) ),
y1 = _WD + ( int )( ( _WD - 1 ) * cos( currentTime / 123 ) ),
y2 = _WD + ( int )( ( _WD - 1 ) * cos( -currentTime / 85 ) ),
y3 = _WD + ( int )( ( _WD - 1 ) * cos( -currentTime / 108 ) );
 
int src1 = y1 * _WV + x1, src2 = y2 * _WV + x2, src3 = y3 * _WV + x3;
 
DWORD* bits = _bmp.bits();
for( int j = 0; j < BMP_SIZE; j++ ) {
dst = j * BMP_SIZE;
for( int i= 0; i < BMP_SIZE; i++ ) {
a = plasma2[src1] + plasma1[src2] + plasma2[src3];
c1 = a << 1; c2 = a << 2; c3 = a << 3;
bits[dst + i] = RGB( c1, c2, c3 );
src1++; src2++; src3++;
}
src1 += BMP_SIZE; src2 += BMP_SIZE; src3 += BMP_SIZE;
}
draw();
}
void setHWND( HWND hwnd ) { _hwnd = hwnd; }
private:
void draw() {
HDC dc = _bmp.getDC(), wdc = GetDC( _hwnd );
BitBlt( wdc, 0, 0, BMP_SIZE, BMP_SIZE, dc, 0, 0, SRCCOPY );
ReleaseDC( _hwnd, wdc );
}
myBitmap _bmp; HWND _hwnd; float _ang;
BYTE *plasma1, *plasma2;
double currentTime; int _WD, _WV;
};
class wnd
{
public:
wnd() { _inst = this; }
int wnd::Run( HINSTANCE hInst ) {
_hInst = hInst; _hwnd = InitAll();
SetTimer( _hwnd, MY_TIMER, 15, NULL );
_plasma.setHWND( _hwnd );
ShowWindow( _hwnd, SW_SHOW );
UpdateWindow( _hwnd );
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while( msg.message != WM_QUIT ) {
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return UnregisterClass( "_MY_PLASMA_", _hInst );
}
private:
void wnd::doPaint( HDC dc ) { _plasma.update(); }
void wnd::doTimer() { _plasma.update(); }
static int WINAPI wnd::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
switch( msg ) {
case WM_PAINT: {
PAINTSTRUCT ps;
_inst->doPaint( BeginPaint( hWnd, &ps ) );
EndPaint( hWnd, &ps );
return 0;
}
case WM_DESTROY: PostQuitMessage( 0 ); break;
case WM_TIMER: _inst->doTimer(); break;
default: return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
HWND InitAll() {
WNDCLASSEX wcex;
ZeroMemory( &wcex, sizeof( wcex ) );
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = ( WNDPROC )WndProc;
wcex.hInstance = _hInst;
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszClassName = "_MY_PLASMA_";
 
RegisterClassEx( &wcex );
 
RECT rc = { 0, 0, BMP_SIZE, BMP_SIZE };
AdjustWindowRect( &rc, WS_SYSMENU | WS_CAPTION, FALSE );
int w = rc.right - rc.left, h = rc.bottom - rc.top;
return CreateWindow( "_MY_PLASMA_", ".: Plasma -- PJorente :.", WS_SYSMENU, CW_USEDEFAULT, 0, w, h, NULL, NULL, _hInst, NULL );
}
static wnd* _inst; HINSTANCE _hInst; HWND _hwnd; plasma _plasma;
};
wnd* wnd::_inst = 0;
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) {
wnd myWnd;
return myWnd.Run( hInstance );
}
 

Ceylon[edit]

Be sure to import javafx.base, javafx.graphics and ceylon.numeric in your module file.

Translation of: Java
 
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();
}
 
}

Common Lisp[edit]

Library: simple-rgb

plasma_demo.lisp:

(require :lispbuilder-sdl)
(require :simple-rgb)
 
(defparameter *palette*
(let ((palette-aux (make-array 256 :element-type 'fixnum)))
(dotimes (i 256)
(let ((color_i (simple-rgb:hsv->rgb (simple-rgb:hsv (/ i 255.0) 1.0 1.0))))
(setf (aref palette-aux i) (loop :for component :across color_i
:for i :from 0
:sum (ash component (* 8 i))))))
palette-aux)
"palette")
 
(defun value->color (palette palette-shift index)
(aref palette (mod (+ index palette-shift) (length palette))))
 
(defun return-color-by-pos (x y &optional w h)
"returns a color index"
(floor
(/ (+ (+ 128.0 (* 128.0 (sin (/ x 16.0))))
(+ 128.0 (* 128.0 (sin (/ y 8.0))))
(+ 128.0 (* 128.0 (sin (/ (+ x y) 16.0))))
(+ 128.0 (* 128.0 (sin (/ (sqrt (+ (* x x) (* y y))) 8.0)))))
4.0)))
 
(defun return-color-by-pos-another (x y &optional w h)
"a different function that returns a color index"
(floor
(/ (+ (+ 128.0 (* 128.0 (sin (/ x 16.0))))
(+ 128.0 (* 128.0 (sin (/ y 32.0))))
(+ 128.0 (* 128.0 (sin (/ (sqrt (+ (expt (/ (- x w) 2.0) 2) (expt (/ (- y h) 2.0) 2))) 8.0))))
(+ 128.0 (* 128.0 (sin (/ (sqrt (+ (* x x) (* y y))) 8.0)))))
4.0)))
 
(defun plasma-render (surface palette-shift)
"render plasma"
(let ((width (sdl:width surface))
(height (sdl:height surface)))
(sdl-base::with-pixel (s (sdl:fp surface))
(dotimes (h height)
(dotimes (w width)
(sdl-base::write-pixel s w h (value->color *palette* palette-shift (funcall #'return-color-by-pos-another w h width height)))))))
surface)
 
(defun demo/plasma ()
"main function: shows a window rendering a plasma efect"
(sdl:with-init ()
(let ((win (sdl:window 320 240
:bpp 24
:resizable nil
:title-caption "demo/plasma"
:icon-caption "demo/plasma")))
(let ((palette-shift 0))
(sdl:update-display win)
(sdl:with-events ()
(:idle
(plasma-render win palette-shift)
(sdl:update-display win)
(incf palette-shift))
(:video-expose-event () (sdl:update-display win))
(:key-down-event (:key key)
(when (or
(sdl:key= key :sdl-key-escape)
(sdl:key= key :sdl-key-q))
(sdl:push-quit-event)))
(:quit-event () t))))))
 
(demo/plasma)

FreeBASIC[edit]

' version 12-04-2017
' compile with: fbc -s gui
' Computer Graphics Tutorial (lodev.org), last example
 
#Define dist(a, b, c, d) Sqr(((a - c) * (a - c) + (b - d) * (b - d)))
 
Const As ULong w = 256
Const As ULong h = 256
ScreenRes w, h, 24
WindowTitle ("Plasma effect")
 
Dim As ULong x, y
Dim As UByte c
Dim As Double time_, value
 
Do
time_ += .99
ScreenLock
For x = 0 To w -1
For y = 0 To h -1
value = Sin(dist(x + time_, y, 128, 128) / 8) _
+ Sin(dist(x, y, 64, 64) / 8) _
+ Sin(dist(x, y + time_ / 7, 192, 64) / 7) _
+ Sin(dist(x, y, 192, 100) / 8) + 4
' c = Int(value) * 32
c = int(value * 32)
PSet(x, y), RGB(c, c * 2, 255 - c)
Next
Next
ScreenUnLock
Sleep 1
 
If Inkey <> "" Or Inkey = Chr(255) + "k" Then
End
End If
 
Loop

Gosu[edit]

Translation of: Java
 
uses javax.swing.*
uses java.awt.*
uses java.awt.image.*
uses java.awt.event.ActionEvent
uses java.awt.image.BufferedImage#*
uses java.lang.Math#*
 
var size = 400
EventQueue.invokeLater(\ -> showPlasma())
 
function showPlasma() {
var frame = new JFrame("Plasma") {:Resizable = false, :DefaultCloseOperation = JFrame.EXIT_ON_CLOSE}
frame.add(new Plasma(), BorderLayout.CENTER)
frame.pack()
frame.setLocationRelativeTo(null)
frame.Visible = true
}
 
class Plasma extends JPanel {
var hueShift: float
property get plasma: float[][] = createPlasma(size, size)
property get img: BufferedImage = new BufferedImage(size, size, TYPE_INT_RGB)
 
construct() {
PreferredSize = new Dimension(size, size)
new Timer(50, \ e -> {hueShift+=0.02 repaint()}).start()
}
 
private function createPlasma(w: int, h: int): float[][] {
var buffer = new float[h][w]
for(y in 0..|h)
for(x in 0..|w) {
var value = (sin(x / 16) + sin(y / 8) + sin((x + y) / 16) + sin(sqrt(x * x + y * y) / 8) + 4) / 8
buffer[y][x] = value as float
}
return buffer
}
 
override function paintComponent(g: Graphics) {
for(y in 0..|plasma.length)
for(x in 0..|plasma[0].length)
img.setRGB(x, y, Color.HSBtoRGB(hueShift + plasma[y][x], 1, 1))
g.drawImage(img, 0, 0, null)
}
}
 

J[edit]

J-viewmat-plasma.png
require 'trig viewmat'
plasma=: 3 :0
'w h'=. y
X=. (i. % <:) w
Y=. (i. % <:) h
x1=. sin X*16
y1=. sin Y*32
xy1=. sin (Y+/X)*16
xy2=. sin (Y +&.*:/ X)*32
xy1+xy2+y1+/x1
)
   viewmat plasma 256 256

Java[edit]

Plasma effect java.png
Works with: Java version 8
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import static java.awt.image.BufferedImage.*;
import static java.lang.Math.*;
import javax.swing.*;
 
public class PlasmaEffect extends JPanel {
float[][] plasma;
float hueShift = 0;
BufferedImage img;
 
public PlasmaEffect() {
Dimension dim = new Dimension(640, 640);
setPreferredSize(dim);
setBackground(Color.white);
 
img = new BufferedImage(dim.width, dim.height, TYPE_INT_RGB);
plasma = createPlasma(dim.height, dim.width);
 
// animate about 24 fps and shift hue value with every frame
new Timer(42, (ActionEvent e) -> {
hueShift = (hueShift + 0.02f) % 1;
repaint();
}).start();
}
 
float[][] createPlasma(int w, int h) {
float[][] buffer = new float[h][w];
 
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
 
double value = sin(x / 16.0);
value += sin(y / 8.0);
value += sin((x + y) / 16.0);
value += sin(sqrt(x * x + y * y) / 8.0);
value += 4; // shift range from -4 .. 4 to 0 .. 8
value /= 8; // bring range down to 0 .. 1
 
// requires VM option -ea
assert (value >= 0.0 && value <= 1.0) : "Hue value out of bounds";
 
buffer[y][x] = (float) value;
}
return buffer;
}
 
void drawPlasma(Graphics2D g) {
int h = plasma.length;
int w = plasma[0].length;
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
float hue = hueShift + plasma[y][x] % 1;
img.setRGB(x, y, Color.HSBtoRGB(hue, 1, 1));
}
g.drawImage(img, 0, 0, null);
}
 
@Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
 
drawPlasma(g);
}
 
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Plasma Effect");
f.setResizable(false);
f.add(new PlasmaEffect(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

JavaScript[edit]

Translation of: Java
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<style>
canvas {
position: absolute;
top: 50%;
left: 50%;
width: 700px;
height: 500px;
margin: -250px 0 0 -350px;
}
body {
background-color: navy;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
'use strict';
var canvas = document.querySelector('canvas');
canvas.width = 700;
canvas.height = 500;
 
var g = canvas.getContext('2d');
 
var plasma = createPlasma(canvas.width, canvas.height);
var hueShift = 0;
 
function createPlasma(w, h) {
var buffer = new Array(h);
 
for (var y = 0; y < h; y++) {
buffer[y] = new Array(w);
 
for (var x = 0; x < w; x++) {
 
var value = Math.sin(x / 16.0);
value += Math.sin(y / 8.0);
value += Math.sin((x + y) / 16.0);
value += Math.sin(Math.sqrt(x * x + y * y) / 8.0);
value += 4; // shift range from -4 .. 4 to 0 .. 8
value /= 8; // bring range down to 0 .. 1
 
buffer[y][x] = value;
}
}
return buffer;
}
 
function drawPlasma(w, h) {
var img = g.getImageData(0, 0, w, h);
 
for (var y = 0; y < h; y++) {
 
for (var x = 0; x < w; x++) {
 
var hue = hueShift + plasma[y][x] % 1;
var rgb = HSVtoRGB(hue, 1, 1);
var pos = (y * w + x) * 4;
img.data[pos] = rgb.r;
img.data[pos + 1] = rgb.g;
img.data[pos + 2] = rgb.b;
}
}
g.putImageData(img, 0, 0);
}
 
/* copied from stackoverflow */
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
 
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
 
function drawBorder() {
g.strokeStyle = "white";
g.lineWidth = 10;
g.strokeRect(0, 0, canvas.width, canvas.height);
}
 
function animate(lastFrameTime) {
var time = new Date().getTime();
var delay = 42;
 
if (lastFrameTime + delay < time) {
hueShift = (hueShift + 0.02) % 1;
drawPlasma(canvas.width, canvas.height);
drawBorder();
lastFrameTime = time;
}
 
requestAnimationFrame(function () {
animate(lastFrameTime);
});
}
 
g.fillRect(0, 0, canvas.width, canvas.height);
animate(0);
</script>
 
</body>
</html>

Kotlin[edit]

Translation of: Java
// version 1.1.2
 
import java.awt.*
import java.awt.image.BufferedImage
import javax.swing.*
 
class PlasmaEffect : JPanel() {
private val plasma: Array<FloatArray>
private var hueShift = 0.0f
private val img: BufferedImage
 
init {
val dim = Dimension(640, 640)
preferredSize = dim
background = Color.white
img = BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB)
plasma = createPlasma(dim.height, dim.width)
// animate about 24 fps and shift hue value with every frame
Timer(42) {
hueShift = (hueShift + 0.02f) % 1
repaint()
}.start()
}
 
private fun createPlasma(w: Int, h: Int): Array<FloatArray> {
val buffer = Array(h) { FloatArray(w) }
for (y in 0 until h)
for (x in 0 until w) {
var value = Math.sin(x / 16.0)
value += Math.sin(y / 8.0)
value += Math.sin((x + y) / 16.0)
value += Math.sin(Math.sqrt((x * x + y * y).toDouble()) / 8.0)
value += 4.0 // shift range from -4 .. 4 to 0 .. 8
value /= 8.0 // bring range down to 0 .. 1
if (value < 0.0 || value > 1.0) throw RuntimeException("Hue value out of bounds")
buffer[y][x] = value.toFloat()
}
return buffer
}
 
private fun drawPlasma(g: Graphics2D) {
val h = plasma.size
val w = plasma[0].size
for (y in 0 until h)
for (x in 0 until w) {
val hue = hueShift + plasma[y][x] % 1
img.setRGB(x, y, Color.HSBtoRGB(hue, 1.0f, 1.0f))
}
g.drawImage(img, 0, 0, null)
}
 
override fun paintComponent(gg: Graphics) {
super.paintComponent(gg)
val g = gg as Graphics2D
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
drawPlasma(g);
}
}
 
fun main(args: Array<String>) {
SwingUtilities.invokeLater {
val f = JFrame()
f.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
f.title = "Plasma Effect"
f.isResizable = false
f.add(PlasmaEffect(), BorderLayout.CENTER)
f.pack()
f.setLocationRelativeTo(null)
f.isVisible = true
}
}

Lua[edit]

Needs LÖVE 2D Engine

Translation of: C++
 
_ = love.graphics
p1, p2, points = {}, {}, {}
 
function hypotenuse( a, b )
return a * a + b * b
end
function love.load()
size = _.getWidth()
currentTime, doub, half = 0, size * 2, size / 2
local b1, b2
 
for j = 0, size * 2 do
for i = 0, size * 2 do
b1 = math.floor( 128 + 127 * ( math.cos( math.sqrt( hypotenuse( size - j , size - i ) ) / 64 ) ) )
b2 = math.floor( ( math.sin( ( math.sqrt( 128.0 + hypotenuse( size - i, size - j ) ) - 4.0 ) / 32.0 ) + 1 ) * 90 )
table.insert( p1, b1 ); table.insert( p2, b2 )
end
end
end
function love.draw()
local a, c1, c2, c3, s1, s2, s3
currentTime = currentTime + math.random( 2 ) * 3
local x1 = math.floor( half + ( half - 2 ) * math.sin( currentTime / 47 ) )
local x2 = math.floor( half + ( half / 7 ) * math.sin( -currentTime / 149 ) )
local x3 = math.floor( half + ( half - 3 ) * math.sin( -currentTime / 157 ) )
local y1 = math.floor( half + ( half / 11 ) * math.cos( currentTime / 71 ) )
local y2 = math.floor( half + ( half - 5 ) * math.cos( -currentTime / 181 ) )
local y3 = math.floor( half + ( half / 23 ) * math.cos( -currentTime / 137 ) )
s1 = y1 * doub + x1; s2 = y2 * doub + x2; s3 = y3 * doub + x3
for j = 0, size do
for i = 0, size do
a = p2[s1] + p1[s2] + p2[s3]
c1 = a * 2; c2 = a * 4; c3 = a * 8
table.insert( points, { i, j, c1, c2, c3, 255 } )
s1 = s1 + 1; s2 = s2 + 1; s3 = s3 + 1;
end
s1 = s1 + size; s2 = s2 + size; s3 = s3 + size
end
_.points( points )
end
 

Racket[edit]

Uses `return-color-by-pos` from #Lisp, because it was almost lift and shift

#lang racket
;; from lisp (cos I could just lift the code)
(require images/flomap
2htdp/universe
racket/flonum)
 
;; copied from pythagoras-triangle#racket
(define (real-remainder x q) (- x (* (floor (/ x q)) q)))
 
(define (HSV->RGB H S V)
(define C (* V S)) ; chroma
(define H′ (/ H 60))
(define X (* C (- 1 (abs (- (real-remainder H′ 2) 1)))))
(define-values (R1 G1 B1)
(cond
[(< H′ 1) (values C X 0.)]
[(< H′ 2) (values X C 0.)]
[(< H′ 3) (values 0. C X)]
[(< H′ 4) (values 0. X C)]
[(< H′ 5) (values X 0. C)]
[(< H′ 6) (values C 0. X)]
[else (values 0. 0. 0.)]))
(define m (- V C))
(values (+ R1 m) (+ G1 m) (+ B1 m)))
 
 
(define ((colour-component-by-pos ϕ) k x y)
(let ((rv
(/ (+ (+ 1/2 (* 1/2 (sin (+ ϕ (/ x 16.0)))))
(+ 1/2 (* 1/2 (sin (+ ϕ (/ y 8.0)))))
(+ 1/2 (* 1/2 (sin (+ ϕ (/ (+ x y) 16.0)))))
(+ 1/2 (* 1/2 (sin (+ ϕ (/ (sqrt (+ (sqr x) (sqr y))) 8.0))))))
4.0)))
rv))
 
(define ((plasma-flomap (ϕ 0)) w h)
(build-flomap 1 w h (colour-component-by-pos ϕ)))
 
(define ((plasma-image (ϕ 0)) w h)
(flomap->bitmap ((plasma-flomap ϕ) w h)))
 
(define ((colour-plasma plsm) t)
(let ((w (flomap-width plsm))
(h (flomap-height plsm)))
(flomap->bitmap
(build-flomap* 3 w h
(λ (x y)
(define-values (r g b)
(HSV->RGB (real-remainder
(+ (* t 5.)
(* 360 (flomap-ref plsm 0 x y)))
360.) 1. 1.))
(flvector r g b))))))
 
;((plasma-image) 200 200)
 
;((plasma-image (/ pi 32)) 200 200)
 
(define plsm ((plasma-flomap) 300 300))
(animate (λ (t)
((colour-plasma plsm) t)))

Perl 6[edit]

Plasma-perl6.png
Works with: Rakudo version 2016.03
use Image::PNG::Portable;
 
my ($w, $h) = 400, 400;
my $out = Image::PNG::Portable.new: :width($w), :height($h);
 
plasma($out);
 
$out.write: 'Plasma-perl6.png';
 
sub plasma ($png) {
for ^$w -> $x {
for ^$h -> $y {
my $hue = 4 + sin($x / 19) + sin($y / 9) + sin(($x + $y) / 25) + sin(sqrt($x² + $y²) / 8);
$png.set: $x, $y, |hsv2rgb($hue/8, 1, 1);
}
}
}
 
sub hsv2rgb ( $h, $s, $v ){
my $c = $v * $s;
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) );
my $m = $v - $c;
my ($r, $g, $b) = do given $h {
when 0..^1/6 { $c, $x, 0 }
when 1/6..^1/3 { $x, $c, 0 }
when 1/3..^1/2 { 0, $c, $x }
when 1/2..^2/3 { 0, $x, $c }
when 2/3..^5/6 { $x, 0, $c }
when 5/6..1 { $c, 0, $x }
}
( $r, $g, $b ) = map { (($_+$m) * 255).Int }, $r, $g, $b;
}

Python[edit]

Translation of: Perl 6
import math
import colorsys
from PIL import Image
 
def plasma (w, h):
out = Image.new("RGB", (w, h))
pix = out.load()
for x in range (w):
for y in range(h):
hue = 4.0 + math.sin(x / 19.0) + math.sin(y / 9.0) \
+ math.sin((x + y) / 25.0) + math.sin(math.sqrt(x**2.0 + y**2.0) / 8.0)
hsv = colorsys.hsv_to_rgb(hue/8.0, 1, 1)
pix[x, y] = tuple([int(round(c * 255.0)) for c in hsv])
return out
 
if __name__=="__main__":
im = plasma(400, 400)
im.show()

Sidef[edit]

Translation of: Perl 6
require('Imager')
 
class Plasma(width=400, height=400) {
 
has img = nil
 
method init {
img = %s|Imager|.new(xsize => width, ysize => height)
}
 
method generate {
for y,x in (^height ~X ^width) {
var hue = (4 + sin(x/19) + sin(y/9) + sin((x+y)/25) + sin(hypot(x, y)/8))
img.setpixel(x => x, y => y, color => Hash(hsv => [360 * hue / 8, 1, 1]))
}
}
 
method save_as(filename) {
img.write(file => filename)
}
}
 
var plasma = Plasma(256, 256)
plasma.generate
plasma.save_as('plasma.png')