package ch.werner_randelshofer.gui.image;/*Copyright (C) 1999 Werner Randelshoferwerner.randelshofer@mythen.chhttp://www.mythen.ch/w.randelshofer/    Permission to use this release of ANIMPlayer is herebygranted without fee provided that the complete copyrightnotice and this permission notice appear in all copiesand in supporting documentation.*/import java.util.Vector;import java.awt.image.MemoryImageSource;import java.awt.image.ColorModel;import java.awt.Component;import java.awt.Toolkit;import java.awt.image.DirectColorModel;import java.awt.image.ImageProducer;import ch.werner_randelshofer.gui.MovieControlAWT;import ch.werner_randelshofer.gui.ImagePanel;import ch.werner_randelshofer.gui.model.BoundedRangeModel;import ch.werner_randelshofer.gui.model.DefaultBoundedRangeModel;import ch.werner_randelshofer.gui.event.ChangeListener;import ch.werner_randelshofer.gui.event.ChangeEvent;import ch.werner_randelshofer.gui.event.EventListenerList;import ch.werner_randelshofer.gui.model.Player;/** * @author	Werner Randelshofer, Staldenmattweg 2, CH-6405 Immensee, Switzerland * @version	1999-02-18	Created. */public class ANIMPlayerimplements Runnable, ChangeListener, Player	{	private ANIMMovieTrack track_;	private Thread animator_;	private int index_;	private final static float JIFFIE = 1000f / 60f;	private boolean isSkipFrames_;	private boolean isActive_;	private BoundedRangeModel boundedRange_ = new DefaultBoundedRangeModel();	private MovieControlAWT controlComponent_;	private ImagePanel visualComponent_;    /** The listeners waiting for model changes. */    protected EventListenerList listenerList_ = new EventListenerList();    protected ChangeEvent changeEvent_;		public ANIMPlayer()		{		boundedRange_.addChangeListener(this);		}		public void setMovieTrack(ANIMMovieTrack track)		{		track_ = track;		boundedRange_.setRangeProperties(0,0,0,track_.getFrameCount()-1,false);		}			public ImageProducer getImageProducer()		{		return track_.getImageProducer();		}		public synchronized void start()		{		if (! isActive_)			{			isActive_ = true;			boundedRange_.setRangeProperties(0,0,0,track_.getFrameCount()-1,false);			animator_ = new Thread(this);			animator_.setPriority(Thread.MIN_PRIORITY);			animator_.start();			fireStateChanged();			}		}		public void stateChanged(ChangeEvent event)		{		if ( !isActive() )			{			int frameIndex = boundedRange_.getValue();			if (frameIndex < track_.getFrameCount())				{				track_.showFrame(frameIndex);				}			}		}		public synchronized void stop()		{		if (isActive_)			{			isActive_ = false;			Thread animator = animator_;			animator_ = null;			animator.interrupt();			fireStateChanged();			}		}		public boolean isActive()		{		return isActive_;		}			public boolean isSkipFrames()		{		return isSkipFrames_;		}	public void setSkipFrames(boolean isSkip)		{		isSkipFrames_ = isSkip;		if (isActive_)			{			stop();			start();			}		}		public BoundedRangeModel getBoundedRangeModel()		{ return boundedRange_; }		public void run()		{		if (isSkipFrames_)			{			int max = track_.getFrameCount() -1;			long showTime = System.currentTimeMillis() + (long)JIFFIE;			while(Thread.currentThread() == animator_)				{				index_ = boundedRange_.getValue();				track_.fetchFrame(index_);				if (showTime > System.currentTimeMillis())					{					track_.prepareFrame(index_);					long delayTime = showTime - System.currentTimeMillis();					if (delayTime > 0)						{						try { Thread.sleep(delayTime); } catch (InterruptedException e) { return; }						}					track_.showFrame(index_);					Thread.yield();					}				showTime = showTime + (long)(track_.getRelTime(index_) * JIFFIE + JIFFIE);				if (track_.getFrameCount()-1 != boundedRange_.getMaximum())					{ boundedRange_.setMaximum(track_.getFrameCount() -1); }				boundedRange_.setValue(					(boundedRange_.getValue() == boundedRange_.getMaximum()) ? boundedRange_.getMinimum() : boundedRange_.getValue()+1					);				}			}		else			{			int max = track_.getFrameCount() -1;			long showTime = System.currentTimeMillis() + (long)JIFFIE;			while(Thread.currentThread() == animator_)				{				index_ = boundedRange_.getValue();				track_.prepareFrame(index_);				long delayTime = showTime - System.currentTimeMillis();				if (delayTime > 0)					{					try { Thread.sleep(delayTime); } catch (InterruptedException e) { return; }					}				showTime = System.currentTimeMillis() + (long)(track_.getRelTime(index_) * JIFFIE + JIFFIE);				track_.showFrame(index_);				Thread.yield();				if (track_.getFrameCount()-1 != boundedRange_.getMaximum())					{ boundedRange_.setMaximum(track_.getFrameCount() -1); }				boundedRange_.setValue(					(boundedRange_.getValue() == boundedRange_.getMaximum()) ? boundedRange_.getMinimum() : boundedRange_.getValue()+1					);				}			}		}		public Component getControlPanelComponent()		{		if (controlComponent_ == null)			{			controlComponent_ = new MovieControlAWT();			controlComponent_.setPlayer(this);			}		return controlComponent_;		}	public Component getVisualComponent()		{		if (visualComponent_ == null)			{			visualComponent_ = new ImagePanel();			visualComponent_.setImage(visualComponent_.getToolkit().createImage(getImageProducer()));			}		return visualComponent_;		}    /**     * Adds a ChangeListener.  The change listeners are run each     * time Player is started and stopped.     *     * @param l the ChangeListener to add     * @see #removeChangeListener     * @see BoundedRangeModel#addChangeListener     */	public void addChangeListener(ChangeListener l)		{ listenerList_.add(ChangeListener.class, l); }        /**     * Removes a ChangeListener.     *     * @param l the ChangeListener to remove     * @see #addChangeListener     * @see BoundedRangeModel#removeChangeListener     */	public void removeChangeListener(ChangeListener l)		{ listenerList_.remove(ChangeListener.class, l); }    /**      * Run each ChangeListeners stateChanged() method.     *      * @see #setRangeProperties     * @see EventListenerList     */	protected void fireStateChanged() 		{		Object[] listeners = listenerList_.getListenerList();		for (int i = listeners.length - 2; i >= 0; i -=2 )			{			if (listeners[i] == ChangeListener.class)				{				if (changeEvent_ == null)					{					changeEvent_ = new ChangeEvent(this);					}				((ChangeListener)listeners[i+1]).stateChanged(changeEvent_);				}          			}		}	}