import java.awt.*; import java.awt.image.MemoryImageSource; import java.awt.event.*; import java.applet.Applet; import java.util.Vector; public class Particles extends Applet implements Runnable { Vector active_particles = new Vector(); Vector inactive_particles = new Vector(); Image offScrImage = null; Graphics offScrGr = null; MemoryImageSource imageSource = null; int[] pixels = null; Image image = null; int width, height; private double theta = Math.PI*0.75; private final int x = 0, y = 1, z = 2, vx = 3, vy = 4, vz = 5, red = 6, green = 7, blue = 8; public void processMouseMotionEvent( MouseEvent me ) { if ( me.getID() == me.MOUSE_DRAGGED ) { int y = me.getY(); theta = Math.PI*((y/(double)height) - 0.5); } } private volatile boolean running = true; public void start(){ running = true; (new Thread(this)).start(); } public void run(){ Dimension size = getSize(); offScrImage = createImage( size.width, size.height ); offScrGr = offScrImage.getGraphics(); width = size.width; height = size.height; for ( int i = 0; i < 2000; i++ ){ float[] particle = new float[ 9 ]; if ( i > 100 ) { inactive_particles.addElement( particle ); } else { particle[ red ] = particle[ green ] = particle[ blue ] = 0.5f; double px = Math.random()-0.5; double py = Math.random()-0.5; double pz = Math.random()-0.5; double dist = Math.sqrt( py*py + pz*pz ); particle[ x ] = (float)(width*px); particle[ y ] = (float)(width*py/dist); particle[ z ] = (float)(width*pz/dist); active_particles.addElement( particle ); } } pixels = new int[ size.width*size.height ]; imageSource = new MemoryImageSource( size.width, size.height, pixels, 0, width ); imageSource.setAnimated( true ); imageSource.setFullBufferUpdates( true ); image = createImage( imageSource ); enableEvents( AWTEvent.MOUSE_MOTION_EVENT_MASK ); Thread.currentThread().setPriority( Thread.MIN_PRIORITY ); while( running ){ long start = System.currentTimeMillis(); int num_inactive_particles = inactive_particles.size(); while( num_inactive_particles > 0 && Math.random() < 0.7 ){ num_inactive_particles--; float[] particle = (float[])inactive_particles.elementAt( num_inactive_particles ); inactive_particles.removeElementAt( num_inactive_particles ); particle[ y ] = (float)((0.5-Math.random())*3); particle[ z ] = (float)((0.5-Math.random())*3); particle[ vx ] = (float)((0.5-Math.random())*3); particle[ vz ] = (float)((0.5-Math.random())*3); double ran = Math.random(); if ( ran < 0.5 ){ particle[ x ] = (float)((0.5-Math.random()) + (3*width/8)); particle[ vy ] = (float)((0.5-Math.random()) + 10); } else { particle[ x ] = (float)((0.5-Math.random()) - (3*width/8)); particle[ vy ] = (float)((0.5-Math.random()) - 10); } for ( int i = red; i <= blue; i++ ) { particle[ i ] = 0.2f + (float)(0.1f*Math.random()); } if ( Math.random() < 0.7 ) particle[ blue ] += 0.15; else { particle[ red ] += 0.3; particle[ green ] += 0.2; } active_particles.addElement( particle ); } for ( int i = 0; i < pixels.length; i++ ){ pixels[ i ] = 0xFF000000; } float sin_theta = (float)Math.sin( theta ), cos_theta = (float)Math.cos( theta ); double dt = 0.1f; for ( int i = active_particles.size()-1; i >= 0; i-- ){ float[] particle = (float[])active_particles.elementAt( i ); if ( i > 100 ) { double distSq = 0.0; for ( int j = 0; j < 3; j++ ) { float v = particle[ j + 3 ]; particle[ j ] += dt*v; distSq += particle[ j ]*particle[ j ]; } double dist = Math.sqrt( distSq ); double force = -10000.0/distSq; double speedSq = 0.0; for ( int j = 0; j < 3; j++ ) { float v = particle[ j+3 ]; particle[ j+3 ] = (float)(v + dt*force*particle[ j ]/dist)*0.999f; speedSq += v*v; } if ( distSq < 100 || distSq > 1000000 || speedSq > 2500 ) { active_particles.removeElementAt( i ); inactive_particles.addElement( particle ); } } float py = particle[ this.y ]*cos_theta + particle[ this.z ]*sin_theta; float px = particle[ this.x ]; px += 0.5f*width; py += 0.5f*height; if ( px >= 0 && py >= 0 ) { int ix = (int)px; int iy = (int)py; int ixPlusOne = ix+1; int iyPlusOne = iy+1; if ( ixPlusOne < width && iyPlusOne < height ){ float fx = px - ix; float fy = py - iy; float oneMinusFx = 1.0f - fx, oneMinusFy = 1.0f - fy; float btl = oneMinusFx * oneMinusFy; float btr = fx * oneMinusFy; float bbl = oneMinusFx * fy; float bbr = fx * fy; float red = (255f*particle[ this.red ]); float green = (255f*particle[ this.green ]); float blue = (255f*particle[ this.blue ]); plotPixel( (btl*red), (btl*green), (btl*blue), ix, iy ); plotPixel( (btr*red), (btr*green), (btr*blue), ixPlusOne, iy ); plotPixel( (bbl*red), (bbl*green), (bbl*blue), ix, iyPlusOne ); plotPixel( (bbr*red), (bbr*green), (bbr*blue), ixPlusOne, iyPlusOne ); } } } long stop = System.currentTimeMillis(); image.flush(); offScrGr.drawImage( image, 0, 0, this ); repaint(); long time = start+40 - stop; if ( time > 0 ){ try{ Thread.sleep( time ); } catch( Exception e ){} } } } public void stop(){ running = false; } private void plotPixel( float red, float green, float blue, int x, int y ){ int index = y*width + x; int prev_pixel = pixels[ index ]; int new_red = ((prev_pixel & 0x00FF0000) >> 16) + (int)red; new_red = new_red > 255 ? 255 : new_red; // so stays in range int new_green = ((prev_pixel & 0x0000FF00) >> 8) + (int)green; new_green = new_green > 255 ? 255 : new_green; // so stays in range int new_blue = ((prev_pixel & 0x000000FF)) + (int)blue; new_blue = new_blue > 255 ? 255 : new_blue; // so stays in range pixels[ index ] = 0xFF000000 | (new_red << 16) | (new_green << 8) | new_blue; } public void update( Graphics g ){ if ( offScrImage == null ) return; g.drawImage( offScrImage, 0, 0, this ); } }