/* * MandelBar is a more interesting replacement for horizontal rules. * Copyright (C) 1998 Scott Maxwell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * You can reach me at s-max@pacbell.net. */ // Warning, this code is ALPHA! Right now it's just a // proof-of-concept hack. import java.awt.*; import java.applet.*; // The main applet class. public class MandelBar extends Applet implements Runnable { private boolean initialized = false; // Guard redundant calls to init(). private int w, h; // Applet (width, height) in pixels. private int freq; // Updates/sec. private int nColors; // # colors in palette. private int maxIter; // Max iterations (32 is OK, 64 is better). private Thread kickMe; // My kicker thread. private Object kickMeLock = new Object(); // Lock object for above. private Image img; // Where to draw the current line. private Graphics gImg; // GC for above. private Object imgLock = new Object(); // Lock object for img/gImg. private int blockSize = 4; private int trueHeight; private double CY_LO = -2.0; private double CY_HI = 1.5; private double CX_LO = -2.0; private double CX_HI = 2.0; // Ctor. public MandelBar() {} // Called by the browser to perform one-time initialization. public void init() { // Gracefully handle multiple calls to this method. if (initialized) return; initialized = true; w = Integer.getInteger("WIDTH", 400).intValue(); h = Integer.getInteger("HEIGHT", 4).intValue(); freq = Integer.getInteger("FREQ", 10).intValue(); maxIter = 32; img = createImage(w, h); trueHeight = w; // For now. } // Start calculating. public void start() { synchronized (kickMeLock) { if (kickMe != null) return; kickMe = new Thread(this); kickMe.start(); } } // Whoa! public void stop() { synchronized (kickMeLock) { if (kickMe == null) return; kickMe.stop(); kickMe = null; } } // GUI events. public boolean action(Event e, Object arg) { // No GUI, no events. return false; } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { synchronized (imgLock) { if (img == null) return; g.drawImage(img, 0, 0, this); } } public void run() { int dir = blockSize; Color colors [] = new Color [maxIter + 1]; for (int i = 0; i < maxIter; ++i) colors[i] = new Color( (maxIter - i) / (float) maxIter, i / (float) maxIter, i / (float) maxIter ); colors[maxIter] = Color.black; while (true) { synchronized (imgLock) { if (gImg == null) { gImg = img.getGraphics(); Thread.currentThread().yield(); } else break; } } Image imgs [] = new Image[trueHeight]; boolean done [] = new boolean[trueHeight]; int y = 0; while (true) { synchronized (kickMeLock) { if (kickMe == null) return; y += dir; if ((y < 0) || (y >= trueHeight)) y += (dir = -dir); double cy = CY_LO + (CY_HI - CY_LO) * y / trueHeight; if (!done[y]) { imgs[y] = createImage(w, blockSize); Graphics g = imgs[y].getGraphics(); done[y] = true; int ww = w / blockSize; g.setColor(Color.green); g.fillRect(0, 0, w, blockSize); for (int x = 0; x < ww; ++x) { double cx = CX_LO + (CX_HI - CX_LO) * x / ww; double zx = cx; double zy = cy; int iter = 0; double zx2 = zx * zx; double zy2 = zy * zy; while (((zx2 + zy2) < 4.0) && (iter < maxIter)) { zy = 2 * zx * zy + cy; zx = zx2 - zy2 + cx; ++iter; zx2 = zx * zx; zy2 = zy * zy; } g.setColor(colors[iter]); g.fillRect(x * blockSize, 0, blockSize, blockSize); } } synchronized (imgLock) { gImg.drawImage(imgs[y], 0, 0, this); } repaint(); if (false) kickMe.yield(); else { try { kickMe.sleep((long) (1000.0 / freq)); } catch(java.lang.InterruptedException e) { } } } } } }