Plasma effect: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 12: Line 12:
=={{header|C++}}==
=={{header|C++}}==
Windows version.
Windows version.
[[File:plasma.png]]
<lang cpp>
<lang cpp>
#include <windows.h>
#include <windows.h>

Revision as of 16:58, 13 March 2016

Plasma effect is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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.

The task: create a plasma effect.

See also


C++

Windows version. <lang cpp>

  1. include <windows.h>
  2. include <math.h>
  3. 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>

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

Works with: Java version 8

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