home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / handson / archive / Issue153 / java / Lake.java < prev    next >
Encoding:
Java Source  |  1999-04-05  |  14.2 KB  |  597 lines

  1. /*
  2.  * @(#)Lake.java    1999/03/04 
  3.  * 
  4.  * Copyright (c) 1999, David Griffiths. All Rights Reserved.
  5.  * 
  6.  * This software is the proprietary information of David Griffiths.
  7.  * This source code may not be published or redistributed without the 
  8.  * express permission of the author. 
  9.  * 
  10.  * THE AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY 
  11.  * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  12.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  13.  * PURPOSE, OR NON-INFRINGEMENT. THE AUTHOR SHALL NOT BE LIABLE FOR ANY DAMAGES
  14.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  15.  * THIS SOFTWARE OR ITS DERIVATIVES.
  16.  */
  17.  
  18. /**
  19.  * Lake is an applet class which takes in an  
  20.  * image and reflects it in a virtual Lake. 
  21.  * @version    3.1 1999/03/04
  22.  * @author     David Griffiths 
  23.  */
  24.  
  25. import java.lang.String;
  26. import java.net.MalformedURLException;
  27. import java.net.URL;
  28. import java.awt.*;
  29. import java.awt.event.*;
  30. import java.applet.Applet;
  31. import java.applet.AppletContext;
  32. import java.io.*;
  33. import java.net.*;
  34. import java.awt.image.MemoryImageSource;
  35.  
  36. public class Lake extends Applet implements Runnable {
  37.     private int boatHeight;
  38.  
  39.     private boolean keepRunning = true;
  40.  
  41.  
  42.     ///////////////////////
  43.     //                   //
  44.     // THREAD MANAGEMENT //
  45.     //                   //
  46.     ///////////////////////
  47.     transient private Thread thrLake;
  48.  
  49.     public void start() {
  50.         keepRunning = true;
  51.         if (thrLake == null) {
  52.             thrLake = new Thread(this);
  53.             thrLake.start();
  54.         }
  55.     }
  56.  
  57.     public void stop() {
  58.         keepRunning = false;
  59.     }
  60.  
  61.     public void run() {
  62.         currImage = 0;
  63.         while (keepRunning) {
  64.             try {
  65.                 while (!isAnimating)
  66.                     Thread.sleep(500);
  67.                 if (++currImage == numFrames)
  68.                     currImage = 0;
  69.                 if (++boatPhase == boatPhaseTotal)
  70.                     boatPhase = 0;
  71.                 displayImage();
  72.                 repaint();
  73.                 Thread.sleep(30);
  74.             }
  75.             catch (InterruptedException e2) {
  76.                 stop();
  77.             }
  78.         }
  79.     }
  80.  
  81.  
  82.         
  83.     /**
  84.      * Information about this applet. 
  85.      */
  86.     public String getAppletInfo() {
  87.         return "Name: Lake Version 3.1\r\n"
  88.             + "Author: David Griffiths\r\n"
  89.             + "is an applet class which takes in an \r\n"
  90.             + "image and reflects it in a virtual Lake.\r\n"
  91.             + "Last compiled: 4th April 1999 at 08:27  \r\n"
  92.             + "For more information about this and other applets\r\n"
  93.             + "go to http://www.demon.co.uk/davidg/spigots.htm\r\n"
  94.             + "Created with Sun JDK 1.1";
  95.     }
  96.  
  97.  
  98.     ////////////////////////
  99.     //                    //
  100.     // ATTRIBUTES SECTION //
  101.     //                    //
  102.     ////////////////////////
  103.     private final static String PARAM_IMAGE = "image";
  104.     private final static String PARAM_OVERLAY = "overlay";
  105.     private final static String PARAM_TARGET = "target";
  106.     private final static String PARAM_HREF = "hRef";
  107.     private final static String PARAM_ROCKING = "rocking";
  108.     private final static String PARAM_UNDERWATER = "underwater";
  109.     private final static String PARAM_SPEED = "speed";
  110.  
  111.     /**
  112.      * Declaration of the image attribute (JPG or GIF file to reflect) 
  113.      * and the definition of its getter and setter methods. 
  114.      */
  115.  
  116.     private Image    image = null;
  117.  
  118.     /**
  119.      * Returns JPG or GIF file to reflect  
  120.      * @return This Lake's image  
  121.      * @see #setImage  
  122.      * @since JDK1.0 
  123.      */
  124.     public Image getImage() {
  125.         return image;
  126.     }
  127.  
  128.     /**
  129.      * Sets JPG or GIF file to reflect  
  130.      * @param <code>image</code> the Image that is to be the Lake's image  
  131.      * @see #getImage  
  132.      * @since JDK1.0 
  133.      */
  134.     public void setImage(Image image) {
  135.         this.image = image;
  136.         widthImage = this.image.getWidth(this); // Start it loading
  137.         heightImage = this.image.getHeight(this); // Start it loading
  138.         allLoaded = true;
  139.         createAnimation(); 
  140.     }
  141.  
  142.     /**
  143.      * Sets the JPG or GIF file to reflect  
  144.      * @param <code>image</code> the String representing the Lake's image  
  145.      * @see #getImage  
  146.      * @since JDK1.0 
  147.      */
  148.  
  149.     public void setImageValue(String strImage) {
  150.         setImage(getImage(getDocumentBase(), strImage));
  151.     }
  152.  
  153.     /**
  154.      * Implementation of imageUpdate method so that we
  155.      * can have asynchronous image loading.
  156.      */
  157.     public boolean imageUpdate(Image img, int flags,
  158.                         int x, int y, int w, int h) {
  159.         boolean status = super.imageUpdate(img, flags, x, y, w, h);
  160.  
  161.         if (img == image) {
  162.             int oldImageHeight = heightImage;
  163.  
  164.             if ((flags & (FRAMEBITS|ALLBITS)) != 0) { // if complete frame loaded
  165.                 widthImage = w;
  166.                 heightImage = h;
  167.             }
  168.             else { // guess dimensions
  169.                 widthImage = size().width;
  170.                 heightImage = 10 * size().height / 18;
  171.             }
  172.             if (oldImageHeight != heightImage)
  173.                 createAnimation(); 
  174.         }
  175.  
  176.         return status;
  177.     }
  178.  
  179.     /**
  180.      * Declaration of the overlay attribute (JPG or GIF file to use as an overlay) 
  181.      * and the definition of its getter and setter methods. 
  182.      */
  183.  
  184.     private Image    overlay = null;
  185.     private MediaTracker overlayTracker = null;
  186.  
  187.     /**
  188.      * Returns JPG or GIF file to use as an overlay  
  189.      * @return This Lake's overlay  
  190.      * @see #setOverlay  
  191.      * @since JDK1.0 
  192.      */
  193.     public Image getOverlay() {
  194.         return overlay;
  195.     }
  196.  
  197.     /**
  198.      * Sets JPG or GIF file to use as an overlay  
  199.      * @param <code>overlay</code> the Image that is to be the Lake's overlay  
  200.      * @see #getOverlay  
  201.      * @since JDK1.0 
  202.      */
  203.     public void setOverlay(Image overlay) {
  204.         this.overlay = overlay;
  205.         overlayTracker = new MediaTracker(this);
  206.         overlayTracker.addImage(overlay, 0);
  207.     }
  208.  
  209.     public void setOverlayValue(String strImage) {
  210.         setOverlay(getImage(getDocumentBase(), strImage));
  211.     }
  212.  
  213.     private boolean overlayReady() {
  214.         if (overlayTracker != null)
  215.             return (overlayTracker.statusID(0, true) == MediaTracker.COMPLETE);
  216.         else
  217.             return false;
  218.     }
  219.  
  220.     /**
  221.      * Declaration of the target attribute (Target frame) 
  222.      * and the definition of its getter and setter methods. 
  223.      */
  224.  
  225.     private String    target = "_self";
  226.  
  227.     /**
  228.      * Returns Target frame  
  229.      * @return This Lake's target  
  230.      * @see #setTarget  
  231.      * @since JDK1.0 
  232.      */
  233.     public String getTarget() {
  234.         return target;
  235.     }
  236.  
  237.     /**
  238.      * Sets Target frame  
  239.      * @param <code>target</code> the String that is to be the Lake's target  
  240.      * @see #getTarget  
  241.      * @since JDK1.0 
  242.      */
  243.     public void setTarget(String target) {
  244.         this.target = target;
  245.      }
  246.  
  247.     public void setTargetValue(String target) {
  248.         setTarget(target);
  249.      }
  250.  
  251.  
  252.     /**
  253.      * Declaration of the hRef attribute (URL to link to) 
  254.      * and the definition of its getter and setter methods. 
  255.      */
  256.  
  257.     private URL    hRef;
  258.  
  259.     /**
  260.      * Returns URL to link to  
  261.      * @return This Lake's hRef  
  262.      * @see #setHRef  
  263.      * @since JDK1.0 
  264.      */
  265.     public URL getHRef() {
  266.         return hRef;
  267.     }
  268.  
  269.     /**
  270.      * Sets URL to link to  
  271.      * @param <code>hRef</code> the URL that is to be the Lake's hRef  
  272.      * @see #getHRef  
  273.      * @since JDK1.0 
  274.      */
  275.     public void setHRef(URL hRef) {
  276.         this.hRef = hRef;
  277.     }
  278.  
  279.  
  280.     /**
  281.      * Sets URL to link to  
  282.      * @param <code>hRef</code> the URL that is to be the Lake's hRef  
  283.      * @see #getHRef  
  284.      * @since JDK1.0 
  285.      */
  286.     public void setHRefValue(String u) {
  287.         setHRef(createURL(u));
  288.     }
  289.  
  290.  
  291.     private URL createURL(String u) {
  292.         URL createURL = null;
  293.  
  294.         if (u != null) {
  295.             try {
  296.                 createURL = new URL(getDocumentBase(), u);
  297.             }
  298.             catch (MalformedURLException e) {
  299.                 error("Bad URL: " + u);
  300.                 createURL = null;
  301.             }
  302.         }
  303.         return createURL;
  304.     }
  305.  
  306.     /**
  307.      * Declaration of the rocking attribute (TRUE if boat rocking) 
  308.      * and the definition of its getter and setter methods. 
  309.      */
  310.  
  311.     private boolean    rocking = false;
  312.  
  313.     /**
  314.      * Returns TRUE if boat rocking  
  315.      * @return This Lake's rocking  
  316.      * @see #setRocking  
  317.      * @since JDK1.0 
  318.      */
  319.     public boolean isRocking() {
  320.         return rocking;
  321.     }
  322.  
  323.     /**
  324.      * Sets TRUE if boat rocking  
  325.      * @param <code>rocking</code> the boolean that is to be the Lake's rocking  
  326.      * @see #isRocking  
  327.      * @since JDK1.0 
  328.      */
  329.     public void setRocking(boolean rocking) {
  330.         this.rocking = rocking;
  331.     }
  332.  
  333.     public void setRockingValue(String r) {
  334.         setRocking(r.toUpperCase().equals("TRUE"));
  335.     }
  336.  
  337.     public void toggleRocking() {
  338.         setRocking(!isRocking());
  339.     }
  340.  
  341.     /**
  342.      * Declaration of the underwater attribute (TRUE if viewer underwater) 
  343.      * and the definition of its getter and setter methods. 
  344.      */
  345.  
  346.     private boolean    underwater = false;
  347.  
  348.     /**
  349.      * Returns TRUE if viewer underwater  
  350.      * @return This Lake's underwater  
  351.      * @see #setunderwater  
  352.      * @since JDK1.0 
  353.      */
  354.     public boolean isUnderwater() {
  355.         return underwater;
  356.     }
  357.  
  358.     /**
  359.      * Sets TRUE if viewer underwater  
  360.      * @param <code>underwater</code> the boolean that is to be the Lake's underwater  
  361.      * @see #isUnderwater()  
  362.      * @since JDK1.0 
  363.      */
  364.     public void setUnderwater(boolean underwater) {
  365.         this.underwater = underwater;
  366.     }
  367.  
  368.     public void setUnderwaterValue(String r) {
  369.         setUnderwater(r.toUpperCase().equals("TRUE"));
  370.     }
  371.  
  372.     public void toggleUnderwater() {
  373.         setUnderwater(!isUnderwater());
  374.     }
  375.  
  376.     /**
  377.      * Declaration of the speed attribute (animation speed) 
  378.      * and the definition of its getter and setter methods. 
  379.      */
  380.  
  381.     private int speed = 50;
  382.  
  383.     /**
  384.      * Returns animation speed
  385.      * @return This Lake's speed
  386.      * @see #setSpeed
  387.      * @since JDK1.0 
  388.      */
  389.     public int getSpeed() {
  390.         return speed;
  391.     }
  392.  
  393.     /**
  394.      * Sets animation speed
  395.      * @param <code>speed</code> the int that is to be the Lake's speed
  396.      * @see #getSpeed
  397.      * @since JDK1.0 
  398.      */
  399.     public void setSpeed(int speed) {
  400.         if (speed > 100)
  401.             speed = 100;
  402.         else if (speed < 1)
  403.             speed = 1;
  404.         this.speed = speed;
  405.         numFrames = 12 * 50 / speed;
  406.      }
  407.  
  408.     public void setSpeedValue(String speed) {
  409.         setSpeed(Integer.parseInt(speed));
  410.      }
  411.  
  412.  
  413.     public String[][] getParameterInfo() {
  414.         String s[][] = {
  415.             {PARAM_IMAGE, "Image", "JPG or GIF file to reflect"},
  416.             {PARAM_OVERLAY, "Image", "JPG or GIF file to use as an overlay"},
  417.             {PARAM_TARGET, "String", "Target frame"},
  418.             {PARAM_HREF, "URL", "URL to link to"},
  419.             {PARAM_ROCKING, "boolean", "TRUE if boat rocking"},
  420.             {PARAM_UNDERWATER, "boolean", "TRUE if viewer underwater"},
  421.             {PARAM_SPEED, "int", "The animation speed: 1-100"}
  422.         };
  423.         return s;
  424.     }
  425.  
  426.     private void loadParams() {
  427.         String param;
  428.  
  429.         param = getParameter(PARAM_IMAGE);
  430.         if (param != null)
  431.             setImageValue(param);
  432.  
  433.         param = getParameter(PARAM_OVERLAY);
  434.         if (param != null)
  435.             setOverlayValue(param);
  436.  
  437.         param = getParameter(PARAM_TARGET);
  438.  
  439.         param = getParameter(PARAM_HREF);
  440.         if (param != null)
  441.             setHRefValue(param);
  442.  
  443.         param = getParameter(PARAM_ROCKING);
  444.         if (param != null)
  445.             setRockingValue(param);
  446.  
  447.         param = getParameter(PARAM_UNDERWATER);
  448.         if (param != null)
  449.             setUnderwaterValue(param);
  450.  
  451.         param = getParameter(PARAM_SPEED);
  452.         if (param != null)
  453.             setSpeedValue(param);
  454.     }
  455.  
  456.     public boolean mouseUp(Event evt, int i, int j) {
  457.         if (hRef != null) {
  458.             error("" + hRef);
  459.             getAppletContext().showDocument(hRef, target);
  460.         }
  461.         return true;
  462.     }
  463.  
  464.     private int numFrames = 12;
  465.  
  466.     transient private Graphics gMain, gWave;
  467.     transient private Image imgWave;
  468.     transient private int currImage;
  469.     transient private int widthImage, heightImage;
  470.     transient private int widthOverlay, heightOverlay;
  471.     transient private boolean allLoaded = false, isAnimating = true;
  472.     transient private int boatPhase = 0;
  473.     transient private int boatPhaseTotal = 50;
  474.  
  475.     /**
  476.      * Initialisation section.
  477.      */
  478.     public void init() {
  479.         repaint();
  480.         System.out.println(getAppletInfo());
  481.         loadParams();
  482.         allLoaded = true;
  483.     }
  484.  
  485.     /**
  486.      * getPreferredSize() method used for when the class is a component.
  487.      */
  488.     public Dimension getPreferredSize() {
  489.         return new Dimension(widthImage,
  490.             (int)((double)heightImage * 1.8));
  491.     }
  492.  
  493.     /**
  494.      * Display section.
  495.      *
  496.      * The following methods are those used to create and display the
  497.      * final images.
  498.      */
  499.  
  500.     private void error(String msg) {
  501.         getAppletContext().showStatus(msg);
  502.     }
  503.  
  504.     /**
  505.      * Stop a Lake performing unnecessary 
  506.      * screen clears by over-riding the update method and 
  507.      * calling paint straight away. 
  508.      */
  509.     public void update(Graphics g) {
  510.         paint(g);
  511.     }
  512.  
  513.     public void paint(Graphics g) {
  514.         if (imgWave != null) {
  515.             g.drawImage(imgWave, 0, boatHeight, this);
  516.         }
  517.     }
  518.  
  519.     private void displayImage() {
  520.         if (isRocking())
  521.             boatHeight = (int)((double)heightImage * 
  522.                     Math.sin(2.0 * Math.PI * boatPhase / boatPhaseTotal)
  523.                     / 8.0) - (heightImage / 8);
  524.         else
  525.             boatHeight = 0;
  526.  
  527.         if (imgWave != null) {
  528.             if (isUnderwater()) {
  529.                 gWave.drawImage(image, 0, (size().height - heightImage), this);
  530.                 makeWavesInverse(gWave, currImage);
  531.                 boatHeight = -boatHeight;
  532.             }
  533.             else {
  534.                 gWave.drawImage(image, 0, 0, this);
  535.                 makeWaves(gWave, currImage);
  536.             }
  537.  
  538.             if (overlay != null)
  539.                 if (overlayReady())
  540.                     gWave.drawImage(overlay, 
  541.                         ((widthImage - overlay.getWidth(this)) >> 1),
  542.                         (heightImage - (overlay.getHeight(this) >> 1))
  543.                             + boatHeight,
  544.                         this);
  545.         }
  546.     }
  547.  
  548.     private void createAnimation() {
  549.         if ((widthImage > 0) && (heightImage > 0)) {
  550.             synchronized(this) {
  551.                 imgWave = createImage(widthImage, 2 * heightImage);
  552.                 gWave = imgWave.getGraphics();
  553.             }
  554.         }
  555.         repaint();
  556.     }
  557.  
  558.     private void makeWaves(Graphics g, int phase) {
  559.         double d = 2.0 * Math.PI * phase / (double)numFrames;
  560.         for (int row = 0; row < heightImage; row++) {
  561.             int dispY = (int)((double)(heightImage / 14) 
  562.                 * ((double)row + 28.0) 
  563.                 * Math.sin((double)(heightImage / 14 * (heightImage - row)) 
  564.                         / (row + 1) + d)
  565.                 / heightImage);
  566.  
  567.             if ((row - heightImage) > dispY)
  568.                 g.copyArea(0, (heightImage - row),
  569.                     widthImage, 1, 0, row << 1);
  570.             else
  571.                 g.copyArea(0, (heightImage - row + dispY),
  572.                     widthImage, 1, 0, (row << 1) - dispY);
  573.         }
  574.     }
  575.  
  576.     private void makeWavesInverse(Graphics g, int phase) {
  577.         double d = 2.0 * Math.PI * phase / (double)numFrames;
  578.         int appletHeight = size().height;
  579.  
  580.         for (int row = 0; row < heightImage; row++) {
  581.             int dispY = (int)((double)(heightImage / 14) 
  582.                 * ((double)row + 28.0) 
  583.                 * Math.sin((double)(heightImage / 14 * (heightImage - row)) 
  584.                         / (row + 1) + d)
  585.                 / heightImage);
  586.  
  587.             if ((row - heightImage) > dispY)
  588.                 g.copyArea(0, ((appletHeight - heightImage) + row),
  589.                     widthImage, 1, 0, -(row << 1));
  590.             else
  591.                 g.copyArea(0, ((appletHeight - heightImage) + row - dispY),
  592.                     widthImage, 1, 0, dispY - (row << 1));
  593.         }
  594.     }
  595. }
  596.  
  597.