433 lines
16 KiB
Java
Executable File
433 lines
16 KiB
Java
Executable File
//******************************************************************************
|
|
// 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 Lake2 extends Applet implements Runnable
|
|
{
|
|
// THREAD SUPPORT:
|
|
// m_Lake is the Thread object for the applet
|
|
//--------------------------------------------------------------------------
|
|
Thread m_Lake = null;
|
|
|
|
// ANIMATION SUPPORT:
|
|
// m_Graphics used for storing the applet's Graphics context
|
|
// m_WaveGraphics used for storing the animation's Graphics context
|
|
// m_Image the original image
|
|
// m_WaveImage the image containing the wave animations
|
|
// m_nCurrImage the index of the next image to be displayed
|
|
// m_ImgWidth width of each image
|
|
// m_ImgHeight height of each image
|
|
// m_OvlWidth width of each overlay
|
|
// m_OvlHeight height of each overlay
|
|
// m_fAllLoaded indicates whether all images have been loaded
|
|
// m_tAnimate indicates 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 = "frame.html";
|
|
|
|
// 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 Lake2()
|
|
{
|
|
// 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", "http://o2000?~airtria/frame.html" },
|
|
{ PARAM_target, "String", "frame.html" },
|
|
};
|
|
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);
|
|
showStatus("frame.html");
|
|
getAppletContext().showDocument( "URL","frame.html");
|
|
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);
|
|
}
|
|
}
|