package ca.spaz.fractal;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
/**
* Created on Feb 8, 2004
*
* Source code given to public domain. Enjoy.
*
* @author Aaron Davidson <aaron@spaz.ca>
*/
public class BuddhaBrot extends JComponent {
private static final int RED_DWELL = 8000;
private static final int GREEN_DWELL = 2000;
private static final int BLUE_DWELL = 500;
private boolean stop = false;
// exposure counters for each pixel & color
private int[][] exposureBlue;
private int[][] exposureRed;
private int[][] exposureGreen;
// max values for normalization
private int maxexposureBlue;
private int maxexposureRed;
private int maxexposureGreen;
// number of actual exposures
private int exposures = 0;
// out image buffer for rendering
private BufferedImage off;
public BuddhaBrot(int w, int h) {
exposureBlue = new int[w][h];
exposureRed = new int[w][h];
exposureGreen = new int[w][h];
off = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Thread t = new Thread(new Runnable() {
public void run() {
renderLoop();
}
});
t.start();
}
/**
* We just keep adding samples and redrawing the screen. Forever.
*/
public void renderLoop() {
while (!stop) {
refresh();
plot(100000);
}
}
public int getWidth() {
return off.getWidth();
}
public int getHeight() {
return off.getHeight();
}
/**
* Generates another round of sample exposures to add to the image
* @param samples number of samples to take
*/
void plot(int samples) {
double x, y;
// iterate through some plots
for (int n=0; n<samples; n++) {
// Choose a random point in same range
x = random(-2.0,1.0);
y = random(-1.5,1.5);
if (iterate(x, y, false, BLUE_DWELL, exposureBlue)) {
iterate(x, y, true, BLUE_DWELL, exposureBlue);
exposures++;
}
if (iterate(x, y, false, GREEN_DWELL, exposureGreen)) {
iterate(x, y, true, GREEN_DWELL, exposureGreen);
exposures++;
}
if (iterate(x, y, false, RED_DWELL, exposureRed)) {
iterate(x, y, true, RED_DWELL, exposureRed);
exposures++;
}
}
}
/**
* Pick a random value between min and max.
*/
final double random(double min, double max) {
return min + (Math.random() * Math.abs(max - min));
}
/**
* Test a single coordinate against a given dwell value.
* @param x0 random x coordinate
* @param y0 random y coordinate
* @param drawIt if true, we fill in values
* @param dwell the dwell (bailout) value
* @param expose exposure array to fill in results
* @return true if we escaped before bailout
*/
private boolean iterate(double x0, double y0, boolean drawIt, int dwell, int[][] expose) {
double x = 0;
double y = 0;
double xnew, ynew;
int ix, iy;
for (int i=0; i<dwell; i++) {
xnew = x * x - y * y + x0;
ynew = 2 * x * y + y0;
if (drawIt && (i > 3)) {
ix = (int)(getHeight() * (xnew + 2.0) / 3.0);
iy = (int)(getWidth() * (ynew + 1.5) / 3.0);
if (ix >= 0 && iy >= 0 && ix < getHeight() && iy < getWidth()) {
expose[iy][ix]++; // rotate and expose point
}
}
if ((xnew*xnew + ynew*ynew) > 4) {
return true; // escapes
}
x = xnew;
y = ynew;
}
return false; // does not escape
}
/**
* Find the largest exposure values for normalization
*/
private void findMaxExposure() {
maxexposureBlue = maxexposureRed = maxexposureGreen =0;
for (int i=0;i<getHeight();i++) {
for (int j=0;j<getWidth();j++) {
maxexposureBlue = Math.max(maxexposureBlue,exposureBlue[j][i]);
maxexposureRed = Math.max(maxexposureRed,exposureRed[j][i]);
maxexposureGreen = Math.max(maxexposureGreen,exposureGreen[j][i]);
}
}
}
/**
* Update screen bitmap with latest results
*/
public synchronized void refresh() {
findMaxExposure();
for (int i=0;i<getHeight();i++) {
for (int j=0;j<getWidth();j++) {
double blue = exposureBlue[j][i] / (maxexposureBlue / 2.5);
if (blue > 1) {
blue = 1;
}
double red = exposureRed[j][i] / (maxexposureRed / 2.5);
if (red > 1) {
red = 1;
}
double green = exposureGreen[j][i] / (maxexposureGreen / 2.5);
if (green > 1) {
green = 1;
}
Color c = new Color((int)(red*255), (int)(green*255), (int)(blue*255));
off.setRGB(j,i,c.getRGB());
}
}
repaint(); // trigger a repaint
}
/**
* Override update method to prevent flicker
*/
public void update(Graphics g) {
repaint();
}
/**
* Just blit our image buffer to the screen
*/
public synchronized void paint(Graphics g) {
g.drawImage(off, 0, 0, null);
}
}
|