import java.awt.*; import java.awt.image.*; import kinetoscope.awt.*; /** * * * This is a Java port of grav, which is included in * xscreensaver. *

* This is the original copyright notice in the C source: *

 * Copyright (c) 1993 Greg Bowering 
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 * Revision history:
 * 10-May-97: jwz@jwz.org: turned into a standalone program.
 * 11-Jul-94: color version
 * 06-Oct-93: by Greg Bowering 
 * 
* * */ public class Grav extends DoubleBufferedFrame implements Runnable { public static long kRefreshInterval = 0; private Thread refreshThread; int width, height; ModeInfo myInfo; java.util.Random rand = new java.util.Random(); public final static double GRAV = -0.02; public final static double DIST = 16.0; public final static double COLLIDE = 0.0001; public final static double ALMOST = 15.99; public final static double HALF = 0.5; public final static double VR = 0.04; public final static int DIMENSIONS = 3; public final static int X = 0; public final static int Y = 1; public final static int Z = 2; public final static double DAMP = 0.999999; public final static double MaxA = 0.1; public static double XR; public static double YR; public static double ZR; public static boolean decay; public static boolean trail; public static int count; GravStruct[] gravs; public Grav() { super("COLOR FRAME"); setSize(512, 384); initFrame(); XR = HALF*ALMOST; YR = HALF*ALMOST; ZR = HALF*ALMOST; refreshThread = new Thread(this); refreshThread.setPriority(Thread.MIN_PRIORITY); refreshThread.start(); this.show(); } void Planet(int x, int y, Graphics g, int ri, GravStruct gp, Color gc) { if ((x) >= 0 && (y) >= 0 && (x) <= gp.width && (y) <= gp.height) { if (ri < 2) { g.setColor(gc); g.drawLine(x,y,x,y); } else { g.setColor(gc); g.fillArc((x) - ri / 2, (y) - ri / 2, ri, ri, 0, 360); } } } double FLOATRAND(double min, double max) { return((rand.nextDouble()*(max-min))+min); } void init_planet(ModeInfo mi, PlanetStruct planet) { Color gc = (mi).xgwa.getColor(); GravStruct gp = gravs[0]; if ((mi).npixels > 2) planet.colors = mi.pixels[Math.abs((int)rand.nextInt()%(mi).npixels)]; else planet.colors = (mi).white; /* Initialize positions */ planet.P[X] = FLOATRAND(-XR, XR); planet.P[Y] = FLOATRAND(-YR, YR); planet.P[Z] = FLOATRAND(-ZR, ZR); if (planet.P[Z] > -ALMOST) { planet.xi = (int) ((double) gp.width * (HALF + planet.P[X] / (planet.P[Z] + DIST))); planet.yi = (int) ((double) gp.height * (HALF + planet.P[Y] / (planet.P[Z] + DIST))); } else { planet.xi = planet.yi = -1; } planet.ri = (int)(((float) (gp.height/5))/(planet.P[Z]+DIST)); if(trail) { planet.x1 = planet.xi; planet.x2 = planet.xi; planet.x3 = planet.xi; planet.x4 = planet.xi; planet.y1 = planet.xi; planet.y2 = planet.xi; planet.y3 = planet.xi; planet.y4 = planet.xi; } /* Initialize velocities */ planet.V[X] = FLOATRAND(-VR, VR); planet.V[Y] = FLOATRAND(-VR, VR); planet.V[Z] = FLOATRAND(-VR, VR); /* Draw planets */ Planet(planet.xi, planet.yi, mi.xgwa, planet.ri, gp, planet.colors); } void draw_planet(ModeInfo mi, PlanetStruct planet) { Color gc = (mi).xgwa.getColor(); GravStruct gp = gravs[0]; double D; /* A distance variable to work with */ int cmpt; D = planet.P[X] * planet.P[X] + planet.P[Y] * planet.P[Y] + planet.P[Z] * planet.P[Z]; if (D < COLLIDE) D = COLLIDE; D = Math.sqrt(D); D = D * D * D; for (cmpt = X; cmpt < DIMENSIONS; cmpt++) { planet.A[cmpt] = planet.P[cmpt] * GRAV / D; if (decay) { if (planet.A[cmpt] > MaxA) planet.A[cmpt] = MaxA; else if (planet.A[cmpt] < -MaxA) planet.A[cmpt] = -MaxA; planet.V[cmpt] = planet.V[cmpt] + planet.A[cmpt]; planet.V[cmpt] *= DAMP; } else { /* update velocity */ planet.V[cmpt] = planet.V[cmpt] + planet.A[cmpt]; } /* update position */ planet.P[cmpt] = planet.P[cmpt] + planet.V[cmpt]; } gp.x = planet.xi; gp.y = planet.yi; if (planet.P[Z] > -ALMOST) { planet.xi = (int) ((double) gp.width * (HALF + planet.P[X] / (planet.P[Z] + DIST))); planet.yi = (int) ((double) gp.height * (HALF + planet.P[Y] / (planet.P[Z] + DIST))); } else planet.xi = planet.yi = -1; /* Mask */ // Planet(gp.x, gp.y, mi.xgwa, planet.ri, gp, mi.black); if (trail) { int size = planet.ri; mi.xgwa.setColor(planet.colors); mi.xgwa.fillArc(gp.x-size/2,gp.y-size/2,(size*2)/3,(size*2)/3,0,360); mi.xgwa.fillArc(planet.x1-size/3,planet.y1-size/3,size*2/5,size*2/5,0,360); mi.xgwa.fillArc(planet.x2-size/4,planet.y2-size/4,size/3,size/3,0,360); mi.xgwa.fillArc(planet.x3-size/6,planet.y3-size/6,(size/4)+1,(size/4)+1,0,360); mi.xgwa.fillArc(planet.x4-size/8,planet.y4-size/8,(size/6)+1,(size/6)+1,0,360); planet.x4 = planet.x3; planet.x3 = planet.x2; planet.x2 = planet.x1; planet.x1 = gp.x; planet.y4 = planet.y3; planet.y3 = planet.y2; planet.y2 = planet.y1; planet.y1 = gp.y; } /* Move */ gp.x = planet.xi; gp.y = planet.yi; planet.ri = (int)(((float) (gp.height/5))/(planet.P[Z]+DIST)); /* Redraw */ Planet(gp.x, gp.y, mi.xgwa, planet.ri, gp, planet.colors); } void init_grav(ModeInfo mi) { Color gc = (mi).xgwa.getColor(); GravStruct gp; int ball; if (gravs == null) { gravs = new GravStruct[1]; gravs[0] = new GravStruct(); } gp = gravs[0]; gp.width = (mi).width; gp.height = (mi).height; gp.sr = (int)(gp.height/(2*DIST)); gp.nplanets = (mi).batchcount; if (gp.nplanets < 0) { if (gp.planets != null) { gp.planets=null; } gp.nplanets = Math.abs(rand.nextInt()%(-gp.nplanets)) + 1; /* Add 1 so its not too boring */ } if (gp.planets==null) { gp.planets = new PlanetStruct[gp.nplanets]; for(int i=0;i 2) { gp.starcolor = mi.pixels[Math.abs(rand.nextInt()%((mi).npixels))]; } else { gp.starcolor = (mi).white; } for (ball = 0; ball < gp.nplanets; ball++) { init_planet(mi, gp.planets[ball]); } /* Draw centrepoint */ mi.xgwa.setColor(gp.starcolor); mi.xgwa.drawArc(gp.width / 2 - gp.sr / 2, gp.height / 2 - gp.sr / 2, gp.sr, gp.sr, 0, 23040); } void draw_grav(ModeInfo mi) { Color gc = (mi).xgwa.getColor(); GravStruct gp = gravs[0]; int ball; /* Mask centrepoint */ mi.xgwa.setColor(mi.black); mi.xgwa.drawArc(gp.width / 2 - gp.sr / 2, gp.height / 2 - gp.sr / 2, gp.sr, gp.sr, 0, 23040); /* Resize centrepoint */ switch (Math.abs(rand.nextInt()%4)) { case 0: if (gp.sr < (int) (gp.height/(2*DIST))) gp.sr++; break; case 1: if (gp.sr > 2) gp.sr--; } /* Draw centrepoint */ mi.xgwa.setColor(gp.starcolor); mi.xgwa.drawArc(gp.width / 2 - gp.sr / 2, gp.height / 2 - gp.sr / 2, gp.sr, gp.sr, 0, 23040); for (ball = 0; ball < gp.nplanets; ball++) { draw_planet(mi, gp.planets[ball]); } } class ModeInfo { int npixels; Color[] pixels; Color[] colors; Color white; Color black; Graphics xgwa; int batchcount; int width; int height; ModeInfo() { npixels = 10; pixels = new Color[10]; pixels[0] = Color.cyan; pixels[1] = Color.magenta; pixels[2] = Color.yellow; pixels[3] = Color.green; pixels[4] = Color.red; pixels[5] = Color.pink; pixels[6] = Color.orange; pixels[7] = Color.white; pixels[8] = Color.lightGray; pixels[9] = Color.gray; white = Color.white; black = Color.black; batchcount = Grav.count; } } class PlanetStruct { double[] P = new double[Grav.DIMENSIONS]; double[] V = new double[Grav.DIMENSIONS]; double[] A = new double[Grav.DIMENSIONS]; int xi,yi,ri; Color colors; int x1,y1; int x2,y2; int x3,y3; int x4,y4; PlanetStruct() { } } class GravStruct { int width = 512, height = 384; int x,y,sr,nplanets; Color starcolor; PlanetStruct[] planets; GravStruct() { } } public void initFrame() { width = getSize().width; height = getSize().height; setBackground(Color.black); } public void paintContent(Graphics g, int width, int height) { if(myInfo == null) { myInfo = new ModeInfo(); myInfo.xgwa = g; myInfo.width = width; myInfo.height = height; this.width = width; this.height = height; init_grav(myInfo); } else { myInfo.xgwa = g; myInfo.width = width; myInfo.height = height; if(this.width==width && this.height==height) { draw_grav(myInfo); } else { this.width = width; this.height = height; init_grav(myInfo); } } } public void run() { while (true) { repaint(); try { Thread.sleep(kRefreshInterval); } catch (InterruptedException e) { ; } } } public static void main(String[] argv) { try { Grav.decay = false; Grav.trail = false; Grav.count = 9; for(int x=0;x"); System.out.println(" -delay "); System.exit(-1); } Grav frame = new Grav(); } }