home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / handson / archive / Issue159 / files / copyjava.exe / ex2 / GIFLake.java < prev    next >
Encoding:
Java Source  |  1999-10-03  |  14.9 KB  |  628 lines

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