<!--StartFragment-->******************************************************************************
// Lake.java:Applet
//
// (c) David Griffiths, 1997
// This source code may not be reproduced without the express permission of the
// author.
//******************************************************************************
import java.applet.*;
import java.net.URL;
import java.net.MalformedURLException;
import java.awt.*;
//==============================================================================
// Main Class for applet Lake
//
//==============================================================================
public class Lake extends Applet implements Runnable
{
// THREAD SUPPORT:
//m_Lakeis the Thread object for the applet
//--------------------------------------------------------------------------
Thread m_Lake = null;
// ANIMATION SUPPORT:
//m_Graphicsused for storing the applet's Graphics context
//m_WaveGraphicsused for storing the animation's Graphics context
//m_Image the original image
//m_WaveImage the image containing the wave animations
//m_nCurrImagethe index of the next image to be displayed
//m_ImgWidthwidth of each image
//m_ImgHeightheight of each image
//m_OvlWidthwidth of each overlay
//m_OvlHeightheight of each overlay
//m_fAllLoadedindicates whether all images have been loaded
//m_tAnimateindicates that OK to do animation (changed by mouse
//click)
//NUM_FRAMES number of NUM_FRAMES used in the animation
//--------------------------------------------------------------------------
private Graphics m_Graphics, m_WaveGraphics;
private Image m_Image, m_Overlay, m_WaveImage;
private int m_nCurrImage;
private int m_nImgWidth = 0;
private int m_nImgHeight = 0;
private int m_nOvlWidth = 0;
private int m_nOvlHeight = 0;
private boolean m_fAllLoaded = false, m_tAnimate = true;
private final int NUM_FRAMES = 12;
// PARAMETER SUPPORT:
//Parameters allow an HTML author to pass information to the applet;
// the HTML author specifies them using the <PARAM> tag within the <APPLET>
// tag. The following variables are used to store the values of the
// parameters.
//--------------------------------------------------------------------------
// Members for applet parameters
// <type> <MemberVar> = <Default Value>
//--------------------------------------------------------------------------
private String m_ImageName = "";
private String m_OverlayName = "";
private URL m_HRef;
private String m_Frame = "_self";
// Parameter names. To change a name of a parameter, you need only make
// a single change. Simply modify the value of the parameter string below.
//--------------------------------------------------------------------------
private final String PARAM_image = "image";
private final String PARAM_overlay = "overlay";
private final String PARAM_href = "href";
private final String PARAM_target = "target";
// Lake Class Constructor
//--------------------------------------------------------------------------
public Lake()
{
// TODO: Add constructor code here
}
// APPLET INFO SUPPORT:
//The getAppletInfo() method returns a string describing the applet's
// author, copyright date, or miscellaneous information.
//--------------------------------------------------------------------------
public String getAppletInfo()
{
return "Name: Lake v3.0\r\n" +
"Author: David Griffiths\r\n" +
"Created with Microsoft Visual J++ Version 1.0";
}
// PARAMETER SUPPORT
//The getParameterInfo() method returns an array of strings describing
// the parameters understood by this applet.
//
// Lake Parameter Information:
// { "Name", "Type", "Description" },
//--------------------------------------------------------------------------
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_image, "String", "JPG or GIF file to reflect" },
{ PARAM_overlay, "String", "JPG or GIF file to use as overlay" },
{ PARAM_href, "URL", "URL to link to" },
{ PARAM_target, "String", "Target frame" },
};
return info;
}
// The init() method is called by the AWT when an applet is first loaded or
// reloaded. Override this method to perform whatever initialization your
// applet needs, such as initializing data structures, loading images or
// fonts, creating frame windows, setting the layout manager, or adding UI
// components.
//--------------------------------------------------------------------------
public void init()
{
// PARAMETER SUPPORT
//The following code retrieves the value of each parameter
// specified with the <PARAM> tag and stores it in a member
// variable.
//----------------------------------------------------------------------
String param;
// image: JPG of GIF file to reflect
//----------------------------------------------------------------------
param = getParameter(PARAM_image);
if (param != null)
m_ImageName = param;
// overlay: JPG of GIF file to use as overlay
//----------------------------------------------------------------------
param = getParameter(PARAM_overlay);
if (param != null)
m_OverlayName = param;
// href: URL to link to
//----------------------------------------------------------------------
param = getParameter(PARAM_href);
if (param != null)
try
{
m_HRef = new URL(getDocumentBase(), param);
}
catch (MalformedURLException e)
{
getAppletContext().showStatus("Bad URL: " + param);
return;
}
// target: Target frame
//----------------------------------------------------------------------
param = getParameter(PARAM_target);
if (param != null)
m_Frame = param;
}
// Place additional applet clean up code here. destroy() is called when
// when you applet is terminating and being unloaded.
//-------------------------------------------------------------------------
public void destroy()
{
// TODO: Place applet cleanup code here
}
// ANIMATION SUPPORT:
//Draws the next image, if all images are currently loaded
//--------------------------------------------------------------------------
private void displayImage(Graphics g)
{
if (!m_fAllLoaded)
return;
// Draw frame of rippled lower half
//----------------------------------------------------------------------
if (m_WaveImage != null) {
g.drawImage (m_WaveImage, (-m_nCurrImage * m_nImgWidth), m_nImgHeight, this);
g.drawImage (m_WaveImage, ((NUM_FRAMES-m_nCurrImage) * m_nImgWidth),
m_nImgHeight, this);
}
// Draw the original in the tophalf.
//----------------------------------------------------------------------
g.drawImage (m_Image, 0, -1, this);
}
// Lake Paint Handler
//--------------------------------------------------------------------------
public void paint(Graphics g)
{
// ANIMATION SUPPORT:
//The following code displays a status message until all the
// images are loaded. Then it calls displayImage to display the current
// image.
//----------------------------------------------------------------------
if (m_fAllLoaded)
displayImage(g);
else
g.drawString("Loading images...", 10, 20);
// TODO: Place additional applet Paint code here
}
//The start() method is called when the page containing the applet
// first appears on the screen. The AppletWizard's initial implementation
// of this method starts execution of the applet's thread.
//--------------------------------------------------------------------------
public void start()
{
if (m_Lake == null)
{
m_Lake = new Thread(this);
m_Lake.start();
}
}
// The stop() method is called when the page containing the applet is
// no longer on the screen. The AppletWizard's initial implementation of
// this method stops execution of the applet's thread.
//--------------------------------------------------------------------------
public void stop()
{
if (m_Lake != null)
{
m_Lake.stop();
m_Lake = null;
}
}
// THREAD SUPPORT
//The run() method is called when the applet's thread is started. If
// your applet performs any ongoing activities without waiting for user
// input, the code for implementing that behavior typically goes here. For
// example, for an applet that performs animation, the run() method controls
// the display of images.
//--------------------------------------------------------------------------
public void run()
{
m_nCurrImage = 0;
// If re-entering the page, then the images have already been loaded.
// m_fAllLoaded == TRUE.
//----------------------------------------------------------------------
if (!m_fAllLoaded)
{
repaint();
m_Graphics = getGraphics();
// Now load up the image to be used in the animation. Rather than do
// this asynchronously with imageUpdate (which is a pain in the bum to
// use) we'll do it synchronously with a MediaTracker. This hangs
// around until the image is loaded. Using the waitForAll method, just
// in case we ever add other images to the applet.
//------------------------------------------------------------------
MediaTracker tracker = new MediaTracker(this);
String strImage;
m_Image = getImage(getDocumentBase(), m_ImageName);
if (!"".equals(m_OverlayName))
m_Overlay = getImage(getDocumentBase(), m_OverlayName);
tracker.addImage(m_Image, 0);
if (!"".equals(m_OverlayName))
tracker.addImage(m_Overlay, 1);
// Wait until all images are fully loaded
//------------------------------------------------------------------
try
{
tracker.waitForAll();
m_fAllLoaded = !tracker.isErrorAny();
}
catch (InterruptedException e) {}
if (!m_fAllLoaded)
{
stop();
m_Graphics.drawString("Error loading images!", 10, 40);
return;
}
// Can now set width and height straight away because the
// MediaTracker object has ensured this information is now available.
//--------------------------------------------------------------
m_nImgWidth = m_Image.getWidth(this);
m_nImgHeight = m_Image.getHeight(this);
if (!"".equals(m_OverlayName)) {
m_nOvlWidth = m_Overlay.getWidth(this);
m_nOvlHeight = m_Overlay.getHeight(this);
}
// Now create the animation of the rippling waves.
//--------------------------------------------------------------
createAnimation();
}
repaint();
while (true)
{
try
// Draw next image in animation
//--------------------------------------------------------------
if (m_tAnimate)
{
displayImage(m_Graphics);
if (++m_nCurrImage == NUM_FRAMES)
m_nCurrImage = 0;
Thread.sleep(50);
}
else
Thread.sleep(500);
catch (InterruptedException e)
stop();
}
}
// MOUSE SUPPORT:
// Clicking on the applet starts/stops it.
// Doesn't call 'stop()' directly because otherwise an InterruptedException
// is thrown. ..
//--------------------------------------------------------------------------
public boolean mouseUp(Event event, int i, int j)
{
boolean flag = super.mouseUp(event, i, j);
if (m_HRef == null)
m_tAnimate = !m_tAnimate; // Toggle m_tAnimate to start/stop animation.
else
{
showStatus("" + m_HRef);
getAppletContext().showDocument(m_HRef, m_Frame);
}
return true;
}
// ANIMATION
// Create the animation within a single background image. We use a single
// image rather than the default multiple images because it's quicker.
//---------------------------------------------------------------------------
public void createAnimation ()
{
// Create inverted image of original loaded image.
// We create a background image (backImg) 1 pixel higher
// than the original because we'll need an extra line of
// pixels to play with when we flip the image upside down.
//--------------------------------------------------------
Image backImg = createImage (m_nImgWidth, m_nImgHeight + 1);
Graphics backG = backImg.getGraphics();
// Copy the original image (m_Image) onto the background
// version.
//--------------------------------------------------------
backG.drawImage (m_Image, 0, 1, this);
// Now flip the image upside down.
//--------------------------------------------------------
for (int i = 0; i < (m_nImgHeight >> 1); i++)
{
backG.copyArea (0, i, m_nImgWidth, 1, 0, m_nImgHeight - i);
backG.copyArea (0, m_nImgHeight - 1 - i, m_nImgWidth, 1,
0, -m_nImgHeight + 1 + (i << 1));
backG.copyArea (0, m_nImgHeight, m_nImgWidth, 1, 0, -1 - i);
}
// Now create the large (NUM_FRAMES + 1 times the width) image
// that will store dithered copies of the inverted original.
//--------------------------------------------------------
m_WaveImage = createImage ((NUM_FRAMES + 1) * m_nImgWidth, m_nImgHeight);
m_WaveGraphics = m_WaveImage.getGraphics();
m_WaveGraphics.drawImage (backImg, NUM_FRAMES * m_nImgWidth, 0, this);
// Now create dithered copies (sine displacement up or down) of the
// inverted original.
//--------------------------------------------------------
for (int phase = 0; phase < NUM_FRAMES; phase++)
makeWaves (m_WaveGraphics, phase);
// Now, if there is an overlay image, draw the top half of it
// over the frame. (The bottom half of the overlay will be drawn over
// the rippled image)
//------------------------------------------------------------
backG.drawImage (m_Image, 0, 1, this);
if (!"".equals(m_OverlayName))
backG.drawImage (m_Overlay,
(m_nImgWidth - m_nOvlWidth) >> 1,
m_nImgHeight - (m_nOvlHeight >> 1), this);
m_Image = backImg;
}
// ANIMATION
// Take the initial (unwaved) image from the left-hand-side of the graphics
// and make NUM_FRAMES copies of it - the pixels rows of each one dithered
// up or down depending upon the dispy sine function.
//---------------------------------------------------------------------------
public void makeWaves (Graphics g, int phase)
{
double p1;
int dispx, dispy;
// Convert the phase into radians (by splitting 2*PI into
// NUM_FRAMES segments).
//--------------------------------------------------------
p1 = 2 * Math.PI * (double)phase / (double)NUM_FRAMES;
// dispx defines how far across the image has to be copied
// from the original LHS frame.
//--------------------------------------------------------
dispx = (NUM_FRAMES - phase) * m_nImgWidth;
// Now process each horizontal line of pixels. Copy across
// from original frame on the left-had-side and displacing
// up or down WRT the dispy sine function.
//--------------------------------------------------------
for (int i = 0; i < m_nImgHeight; i++)
{
// dispy defines the vertical sine displacement. It
// attenuates higher up the image, for perspective.
//--------------------------------------------------------
dispy = (int)((m_nImgHeight/14) * ((double) i + 28.0)
* Math.sin ((double)((m_nImgHeight/14)*(m_nImgHeight - i))
/(double)(i + 1)
+ p1)
/ (double) m_nImgHeight);
// If no line dithers here then copy original.
//--------------------------------------------------------
if (i < -dispy)
g.copyArea (NUM_FRAMES * m_nImgWidth, i, m_nImgWidth, 1,
-dispx, 0);
else
// Else copy dithered line.
//--------------------------------------------------------
g.copyArea (NUM_FRAMES * m_nImgWidth, i + dispy,
m_nImgWidth, 1, -dispx, -dispy);
}
// Now, if there is an overlay image, draw the bottom half of it
// over the frame. (The top half of the overlay will be drawn over
// the original image)
//------------------------------------------------------------
if (!"".equals(m_OverlayName))
g.drawImage (m_Overlay,
(phase * m_nImgWidth) + ((m_nImgWidth - m_nOvlWidth) >> 1),
-m_nOvlHeight >> 1, this);
}
}