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
ASCII version for Windows
If you don't want to bother with Graphics libraries, try out this nifty implementation on Windows : <lang C>
- 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; } </lang>
Graphics version
And here's the Graphics version, requires the WinBGIm library. Prints out usage on incorrect invocation. <lang C> /*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; } </lang>
C++
Windows version. <lang cpp>
- 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 );
} </lang>
Ceylon
Be sure to import javafx.base, javafx.graphics and ceylon.numeric in your module file.
<lang ceylon> 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(); }
}</lang>
Common Lisp
plasma_demo.lisp: <lang 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)</lang>
FreeBASIC
<lang freebasic>' 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</lang>
Gosu
<lang gosu> 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) }
} </lang>
J
<lang j>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
)</lang>
<lang j> viewmat plasma 256 256</lang>
Java
<lang java>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); }); }
}</lang>
JavaScript
<lang javascript><!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></lang>
Kotlin
<lang scala>// 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 }
}</lang>
Lua
Needs LÖVE 2D Engine
<lang lua> _ = 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 </lang>
Racket
Uses `return-color-by-pos` from #Lisp, because it was almost lift and shift
<lang racket>#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)))</lang>
Perl 6
<lang perl6>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;
}</lang>
Phix
<lang Phix>-- -- demo\rosetta\plasma.exw -- include pGUI.e
Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas
sequence plasma integer pw = 0, ph = 0
procedure createPlasma(integer w, h)
plasma = repeat(repeat(0,w),h) for y=1 to h do for x=1 to w do atom v = sin(x/16) v += sin(y/8) v += sin((x+y)/16) v += sin(sqrt(x*x + y*y)/8) v += 4 -- shift range from -4 .. 4 to 0 .. 8 v /= 8 -- bring range down to 0 .. 1 plasma[y][x] = v end for end for pw = w ph = h
end procedure
atom hueShift = 0
procedure drawPlasma(integer w, h)
hueShift = remainder(hueShift + 0.02,1) sequence rgb3 = repeat(repeat(0,w*h),3) integer cx = 1 for y=1 to h do for x=1 to w do atom hue = hueShift + remainder(plasma[y][x],1) integer i = floor(hue * 6) atom t = 255, f = (hue * 6 - i)*t, q = t - f, r, g, b switch mod(i,6) do case 0: r = t; g = f; b = 0 case 1: r = q; g = t; b = 0 case 2: r = 0; g = t; b = f case 3: r = 0; g = q; b = t case 4: r = f; g = 0; b = t case 5: r = t; g = 0; b = q end switch rgb3[1][cx] = r rgb3[2][cx] = g rgb3[3][cx] = b cx += 1 end for end for cdCanvasPutImageRectRGB(cddbuffer, w, h, rgb3, 0, 0, 0, 0, 0, 0, 0, 0)
end procedure
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
atom {w,h} = IupGetIntInt(canvas, "DRAWSIZE") if pw!=w or ph!=h then createPlasma(w,h) end if cdCanvasActivate(cddbuffer) drawPlasma(w,h) cdCanvasFlush(cddbuffer) return IUP_DEFAULT
end function
function timer_cb(Ihandle /*ih*/)
IupUpdate(canvas) return IUP_IGNORE
end function
function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih) cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) cdCanvasSetBackground(cddbuffer, CD_WHITE) cdCanvasSetForeground(cddbuffer, CD_GRAY) return IUP_DEFAULT
end function
procedure main()
IupOpen()
canvas = IupCanvas(NULL) IupSetAttribute(canvas, "RASTERSIZE", "450x300") IupSetCallback(canvas, "MAP_CB", Icallback("map_cb")) IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
dlg = IupDialog(canvas) IupSetAttribute(dlg, "TITLE", "Plasma") IupCloseOnEscape(dlg)
IupShow(dlg) IupSetAttribute(canvas, "RASTERSIZE", NULL) Ihandle timer = IupTimer(Icallback("timer_cb"), 50) IupMainLoop() IupClose()
end procedure
main()</lang> And here's a simple console ditty, similar I think to C's ASCII version for Windows, though this also works on Linux: <lang Phix>sequence s = video_config() for i=1 to s[VC_SCRNLINES]*s[VC_SCRNCOLS]-1 do
bk_color(rand(16)-1) text_color(rand(16)-1) puts(1,"\xDF")
end for {} = wait_key()</lang>
Python
<lang python>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()</lang>
Ring
<lang ring>
- Project : Plasma effect
load "guilib.ring"
paint = null
new qapp
{ win1 = new qwidget() { setwindowtitle("Plasma effect") setgeometry(100,100,500,600)
label1 = new qlabel(win1) { setgeometry(10,10,400,400) settext("") }
new qpushbutton(win1) { setgeometry(150,500,100,30) settext("Draw") setclickevent("Draw()") } show() } exec() }
func draw
p1 = new qpicture() color = new qcolor() { setrgb(0,0,255,255) } ### <<< BLUE pen = new qpen() { setcolor(color) setwidth(1) }
paint = new qpainter() { begin(p1) setpen(pen)
w = 256 h = 256 time = 0
for x = 0 to w -1 for y = 0 to h -1 time = time + 0.99 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 = floor(value * 32) r = c g = (c*2)%255 b = 255-c color2 = new qcolor() color2.setrgb(r,g,b,255) pen.setcolor(color2) setpen(pen) drawpoint(x,y) next next endpaint() } label1 { setpicture(p1) show() } return
func dist(a, b, c, d)
d = sqrt(((a - c) * (a - c) + (b - d) * (b - d))) return d
</lang> Output:
Scala
Java Swing Interoperability
<lang Scala>import java.awt._ import java.awt.event.ActionEvent import java.awt.image.BufferedImage
import javax.swing._
import scala.math.{sin, sqrt}
object PlasmaEffect extends App {
SwingUtilities.invokeLater(() => new JFrame("Plasma Effect") {
class PlasmaEffect extends JPanel { private val (w, h) = (640, 640) private var hueShift = 0.0f
override def paintComponent(gg: Graphics): Unit = { val g = gg.asInstanceOf[Graphics2D]
def drawPlasma(g: Graphics2D) = { val img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB)
for (y <- 0 until h; x <- 0 until w) {
def design = (sin(x / 16f) + sin(y / 8f) + sin((x + y) / 16f) + sin(sqrt(x * x + y * y) / 8f) + 4).toFloat / 8
img.setRGB(x, y, Color.HSBtoRGB(hueShift + design % 1, 1, 1)) } g.drawImage(img, 0, 0, null) }
super.paintComponent(gg) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) drawPlasma(g) }
// animate about 24 fps and shift hue value with every frame new Timer(42, (_: ActionEvent) => { hueShift = (hueShift + 0.02f) % 1 repaint() }).start()
setBackground(Color.white) setPreferredSize(new Dimension(h, w)) }
add(new PlasmaEffect, BorderLayout.CENTER) pack() setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) setLocationRelativeTo(null) setResizable(false) setVisible(true) })
}</lang>
Sidef
<lang ruby>require('Imager')
class Plasma(width=400, height=400) {
has img = nil
method init { img = %O|Imager|.new(xsize => width, ysize => height) }
method generate { for y=(^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')</lang> Output image: Plasma effect