| 
 
 
 
 <!--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_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 = "_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 " +
         "Author: David Griffiths " +
         "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);
  }
  }
 
  |    |