CloudFlare suffered a massive security issue affecting all of its customers, including Rosetta Code. All passwords not changed since February 19th 2017 have been expired, and session cookie longevity will be reduced until late March.--Michael Mol (talk) 05:15, 25 February 2017 (UTC)

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]

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 );
}
 

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)

Gosu[edit]

 
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);
});
}
}

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')