import java.lang.*; import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.*; import Bitmap; final public class Cloud extends Applet implements Runnable, ActionListener { private final static int FIELD_BIT = 8; private final static int FIELD_SIZE = 1 << FIELD_BIT, FIELD_MASK = FIELD_SIZE - 1; private final static double SQRT_1_2 = Math.sqrt(1.0 / 2); private final static double _dHeightFactor = 3; private final static double _dLightX = -Math.sqrt(1.0 / 3), _dLightY = Math.sqrt(1.0 / 3), _dLightZ = Math.sqrt(1.0 / 3); private final static double _dAmbient = 0.3; private Panel _panel; private Thread _thread; private Image _image; private Choice _choiceType; private boolean _fCloud = true; final public void init() { setBackground(Color.white); Panel panel = new Panel(); panel.setLayout(new GridLayout(1, 2)); panel.setBackground(Color.white); _choiceType = new Choice(); _choiceType.addItem(getString("Cloud")); _choiceType.addItem(getString("Sea")); panel.add(_choiceType); Button button = new Button(getString("Go")); button.addActionListener(this); panel.add(button); add(_panel = panel); } final private String getString(String strName) { String strValue = getParameter(strName); return strValue != null ? strValue : strName; } final public void doLayout() { if (_panel != null) { Dimension dimWindow = getSize(), dimPanel = _panel.getPreferredSize(); _panel.setBounds(0, 0, Math.min(dimWindow.width, dimPanel.width), Math.min(dimWindow.height, dimPanel.height)); } } final public void start() { calculate(); } final private void calculate() { if (_thread == null) { try { _fCloud = (_choiceType.getSelectedIndex() == 0); _image = null; repaint(); (_thread = new Thread(this)).start(); } catch (Exception e) { } } } final public void stop() { if (_thread != null && _thread.isAlive()) { _thread.stop(); } _thread = null; _image = null; } final public void update(Graphics g) { if (_image != null) { paint(g); } else { super.update(g); } } final public void paint(Graphics g) { if (_image != null) { Dimension dimWindow = getSize(); for (int y = 0; y < dimWindow.height; y += FIELD_SIZE) { for (int x = 0; x < dimWindow.width; x += FIELD_SIZE) { g.drawImage(_image, x, y, this); } } } } final public void run() { double aadField[][] = new double[FIELD_SIZE][FIELD_SIZE]; Random random = new Random(); double dFactor = 1; int xOffset = random.nextInt() & FIELD_MASK, yOffset = random.nextInt() & FIELD_MASK; for (int iFieldSize = FIELD_SIZE; iFieldSize >= 2; iFieldSize >>>= 1) { for (int y = 0; y < FIELD_SIZE; y += iFieldSize) { int yBottom = (y + yOffset) & FIELD_MASK, yCenter = (y + iFieldSize / 2 + yOffset) & FIELD_MASK, yTop = (y + iFieldSize + yOffset) & FIELD_MASK; for (int x = 0; x < FIELD_SIZE; x += iFieldSize) { int xLeft = (x + xOffset) & FIELD_MASK, xCenter = (x + iFieldSize / 2 + xOffset) & FIELD_MASK, xRight = (x + iFieldSize + xOffset) & FIELD_MASK; // lower center; aadField[yBottom][xCenter] = (aadField[yBottom][xLeft] + aadField[yBottom][xRight]) / 2 + random.nextGaussian() * dFactor; // left center; aadField[yCenter][xLeft] = (aadField[yBottom][xLeft] + aadField[yTop][xLeft]) / 2 + random.nextGaussian() * dFactor; } } for (int y = 0; y < FIELD_SIZE; y += iFieldSize) { int yBottom = (y + yOffset) & FIELD_MASK, yCenter = (y + iFieldSize / 2 + yOffset) & FIELD_MASK, yTop = (y + iFieldSize + yOffset) & FIELD_MASK; for (int x = 0; x < FIELD_SIZE; x += iFieldSize) { int xLeft = (x + xOffset) & FIELD_MASK, xCenter = (x + iFieldSize / 2 + xOffset) & FIELD_MASK, xRight = (x + iFieldSize + xOffset) & FIELD_MASK; // center; aadField[yCenter][xCenter] = (aadField[yBottom][xCenter] + aadField[yTop][xCenter] + aadField[yCenter][xLeft] + aadField[yCenter][xRight]) / 4 + random.nextGaussian() * dFactor; } } dFactor *= SQRT_1_2; } Bitmap bitmap = new Bitmap(FIELD_SIZE, FIELD_SIZE); for (int y = 0; y < FIELD_SIZE; y++) { for (int x = 0; x < FIELD_SIZE; x++) { double dValue = aadField[y][x]; int iColor; if (_fCloud) { iColor = Math.max(0, Math.min(255, 160 + (int)(dValue * 40))) * 0x010100 + 255; } else { if (dValue < 0) { iColor = Math.max(0, 50 + (int)(dValue * 70)) * 0x010100 + 0x0020d0; } else { dValue = Math.min(350, dValue * 200); double dVectorX = (aadField[y][(x - 1) & FIELD_MASK] - aadField[y][(x + 1) & FIELD_MASK]) * _dHeightFactor, dVectorY = (aadField[(y - 1) & FIELD_MASK][x] - aadField[(y + 1) & FIELD_MASK][x]) * _dHeightFactor; double dCosTheta = (dVectorX * _dLightX + dVectorY * _dLightY + (2 * _dLightZ)) / Math.sqrt(dVectorX * dVectorX + dVectorY * dVectorY + 2 * 2); double dLight = Math.max(0, dCosTheta) + _dAmbient; iColor = (Math.min(255, (int)(dValue / 4 * dLight)) << 16) | (Math.min(255, (int)((200 - dValue / 3) * dLight)) << 8); } } bitmap.put(x, y, iColor); } } _image = createImage(bitmap); _thread = null; repaint(); } final public void actionPerformed(ActionEvent ae) { calculate(); } }