JMU
Sampled Dynamic Visual Content
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Introduction
Sampling Dynamic Visual Content

An Illustration

images/dynamic-sampling.gif
Some Observations
"Quick Start"
"Quick Start" (cont.)
"Quick Start" (cont.)
"Quick Start" (cont.)

Controlling the Timing of the Rendering Process

images/sampled-dynamics_design-overview.gif
"Quick Start" (cont.)

Outline of a Screen Class

javaexamples/visual/dynamic/sampled/Screen.java (Fragment: skeleton)
        
package visual.dynamic.sampled;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

import collectionframework.*;
import event.*;
import visual.*;
import visual.statik.SimpleContent;

/**
 * A component that renders a sequence of Content objects
 * (i.e., static visual content)
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Screen extends    Visualization 
                    implements MetronomeListener
{
    private   boolean                     repeating;    
    private   int                         frameNumber, height, width;
    private   Iterator<SimpleContent>     frames;    
    protected Metronome                   metronome;
    protected SimpleContent               currentFrame;    

    public static final int               FRAME_DELAY = 42;    

    /**
     * Default Constructor
     */
    public Screen()
    {
       super();
       metronome = new Metronome(FRAME_DELAY);
       metronome.addListener(this);       
       setRepeating(false);       

    }

    /**
     * Create the default view associated with this Visualization
     *
     * Note: This method should only be called by constructors.
     *       It should be overridden by derived classes that 
     *       need to use a specialized view
     */
    protected VisualizationView createDefaultView()
    {
       ScreenRenderer    renderer;
       
       renderer = new ScreenRenderer(new PlainVisualizationRenderer());       

       return new VisualizationView(this, renderer);
    }

    /**
     * Get the numebr of the current frame
     *
     * @return  The number of the current frame
     */
    public int getFrameNumber()
    {
       return frameNumber;       
    }

    /**
     * Set the frame rate (i.e., the number of frames per second)
     *
     * @param frameRate
     */
    public void setFrameRate(double frameRate)
    {
       int      delay;
       
       delay = (int)(1000.0 / frameRate);
       metronome.setDelay(delay);       
    }


    /**
     * Set whether this presentation should repeat/loop
     *
     * @param repeating    true to repeat/loop; false otherwise
     */
    public void setRepeating(boolean repeating)
    {
       this.repeating = repeating;       
    }


    /**
     * Start the presentation
     */
    public void start()
    {
       reset();          
       if (frames != null) metronome.start();
    }


    /**
     * Stop the presentation
     *
     */
    public void stop()
    {
       metronome.stop();          
    }

}
        

Handling Metronome Ticks

javaexamples/visual/dynamic/sampled/Screen.java (Fragment: handleTick)
        
    /**
     * Handle tick events (required by MetronomeListener)
     *
     * Specifically, make the current frame the "current" Content
     * and call repaint() to start the rendering process.
     * 
     * @param evt  The ActionEvent
     */
    public void handleTick(int time)
    {
       if (frames != null)
       {
          // See if we're done
          if (frameNumber < 0)
          {
             if   (repeating) reset();
             else             stop();             
          }

          // Start the rendering process (i.e., request that the
          // paint() method be called)
          repaint();

          // Advance the frame
          advanceFrame();          
       }
    }
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: advanceFrame)
        
    /**
     * Advance to the next frame
     */
    private void advanceFrame()
    {
       if ((frames != null) && (frames.hasNext()))
       {
          currentFrame = frames.next();
          frameNumber++;          
       }
       else
       {
          currentFrame = null;
          frameNumber  = -1;          
       }
    }
        

Modifying Behavior in the Parent Class

javaexamples/visual/dynamic/sampled/Screen.java (Fragment: iterator)
        
    protected NullIterator<SimpleContent> currentFrameIterator;    

       currentFrameIterator = new NullIterator<SimpleContent>();

    /**
     * Get an Iterator that contains the current SimpleContent
     * object
     *
     * @return   The Iterator (containing 0 or 1 elements)
     */
    public Iterator<SimpleContent> iterator()
    {
       currentFrameIterator.setElement(currentFrame);
       if (frameNumber < 0) currentFrameIterator.clear();

       return currentFrameIterator;       
    }

    /**
     * Get an Iterator that contains either all of the SimpleContent
     * objects or the current SimpleContent Object
     *
     * @param  all  true to get all frames; false to get the current frame
     * @return   The SimpleContent objects
     */
    public Iterator<SimpleContent> iterator(boolean all)
    {
       Iterator<SimpleContent>       result;       

       if  (all) result = super.iterator();
       else      result = iterator();       

       return result;
    }
        
"Quick Start" (cont.)

The Rendering Process

images/sampled-dynamics_sequence1.gif
Double Buffering
Double Buffering (cont.)
javaexamples/visual/VisualizationView.java (Fragment: doublebuffer1)
        
    // Attributes used for double-buffering
    protected boolean               useDoubleBuffering;    
    protected Graphics2D            bg;    
    protected Image                 offscreenImage;
    protected int                   height, width;    
        
javaexamples/visual/VisualizationView.java (Fragment: doublebuffer2)
        
    /**
     * Create the off-screen buffer if necessary
     * (i.e., if the size has changed)
     *
     * @return  The rendering engine for the off-screen buffer
     */
    private Graphics2D createOffscreenBuffer()
    {
       Dimension                    d;       

       d = getSize();
       if ((d.height != height) || (d.width != width))
       {
          height = d.height;
          width  = d.width;
          
          offscreenImage = createImage(width, height);
          bg = (Graphics2D)offscreenImage.getGraphics();
          bg.setClip(0,0,width,height);
       }

       return bg;       
    }
        
javaexamples/visual/VisualizationView.java (Fragment: doublebuffer3)
        
    /**
     * Paint (i.e., render) this JComponent
     *
     * @param g       The rendering engine to use
     */
    public void paint(Graphics g)
    {
       Graphics2D      bg;
       

       if (useDoubleBuffering)
       {
          bg = createOffscreenBuffer();          
       }
       else
       {
          bg = (Graphics2D)g;
       }
       
       
       if (bg != null)
       {
          // Perform necessary operations before rendering
          preRendering(bg);

          // Render the visual content
          render(bg);

          // Perform necessary operations after rendering
          postRendering(bg);


          if (useDoubleBuffering)
          {
             // Put the offscreen image on the screen
             g.drawImage(offscreenImage, 0, 0, null);

             // Reset the clipping area
             bg.setClip(0,0,width,height);
          }
       }
    }
        
Double Buffering (cont.)
Operating on Multiple Frames
Operating on Multiple Frames (cont.)
Operating on Multiple Frames (cont.)

A Fade Class

javaexamples/visual/dynamic/sampled/Fade.java (Fragment: setDestinationPixels)
        
    /**
     * Set the destination (in the Porter-Duff sense) pixels
     * to be used in alpha blending
     *
     * @param g  The rendering engine
     */
    protected void setDestinationPixels(Graphics g)
    {
       Graphics2D       g2;
       Rectangle        r;

       g2 = (Graphics2D)g;

       r = g2.getClipBounds();

       g2.setComposite(AlphaComposite.Src);
       g2.setColor(g2.getBackground());
       g2.fill(r);
       g2.draw(r);
    }
        

Pre-Rendering Phase

javaexamples/visual/dynamic/sampled/Fade.java (Fragment: preRendering)
        
          g2 = (Graphics2D)g;
          originalComposite = g2.getComposite();          

          alpha = ((float)(frame - first + 1))/(float)duration;
          if (direction == FADE_OUT) alpha = 1.0f - alpha;
           
          if      (alpha > 1.0f) alpha = 1.0f;
          else if (alpha < 0.0f) alpha = 0.0f;
           
           
          setDestinationPixels(g2);
           
          ac  = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                           alpha);
          g2.setComposite(ac);
        

Post-Rendering Phase

javaexamples/visual/dynamic/sampled/Fade.java (Fragment: postRendering)
        
          g2 = (Graphics2D)g;
          if (originalComposite != null) g2.setComposite(originalComposite);
        
Operating on Multiple Frames (cont.)
Operating on Multiple Frames (cont.)

A Disolve Class

javaexamples/visual/dynamic/sampled/Dissolve.java
        package visual.dynamic.sampled;

import java.awt.*;

/**
 * A transition that fades-out the previous frame and
 * fades-in the new one
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Dissolve extends Fade
{

    /**
     * Explicit Value Constructor
     *
     * @param first     The first frame
     * @param duration  The duration (in frames)
     */
    public Dissolve(int first, int duration)
    {
        super(FADE_IN, first, duration);
    }


    /**
     * Set the destination (in the Porter-Duff sense) pixels
     * to be used in alpha blending
     *
     * @param g  The rendering engine
     */
    protected void setDestinationPixels(Graphics g)
    {
        // Use the last frame
    }

}
        
Operating on Multiple Frames (cont.)
Operating on Multiple Frames (cont.)

A RectangleWipe Class

javaexamples/visual/dynamic/sampled/RectangleWipe.java (Fragment: calculateClip)
        
    /**
     * Calculate the size of the clip rectangle
     *
     * @param width   The width  of the image
     * @param height  The height of the image
     * @param int     The frame of the wipe
     */
    protected Rectangle2D calculateClip(float width,
                                        float height,
                                        int   frame)
    {
       float              h, w, x, y;
       Rectangle2D        clip;


       w = scale*frame*width;
       h = scale*frame*height;
       x = width/2.0f  - w/2.0f;
       y = height/2.0f - h/2.0f;

       clip = new Rectangle2D.Float(x, y, w, h);

       return clip;
    }
        

Pre-Rendering Phase

javaexamples/visual/dynamic/sampled/RectangleWipe.java (Fragment: preRendering)
        
          g2 = (Graphics2D)g;
          originalClip = g2.getClip();        
           
          bounds = g2.getClipBounds();
          height = (float)(bounds.getHeight());
          width  = (float)(bounds.getWidth());
           
           
          clip = calculateClip(width, height, frame-first+1);
          g2.setClip(clip);
        

Post-Rendering Phase

javaexamples/visual/dynamic/sampled/RectangleWipe.java (Fragment: postRendering)
        
       g2 = (Graphics2D)g;

       if (originalClip != null) g2.setClip(originalClip);       
        
Operating on Multiple Frames (cont.)

A LineWipe Class

javaexamples/visual/dynamic/sampled/LineWipe.java (Fragment: calculateClip)
        
    /**
     * Calculate the size of the clip rectangle
     *
     * @param width   The width  of the image
     * @param height  The height of the image
     * @param frame   The frame of the wipe
     */
    protected Rectangle2D calculateClip(float width,
                                        float height,
                                        int frame)
    {
       float              h, w, x, y;
       Rectangle2D        clip;


       w = width;
       h = height;
       x = 0.0f;
       y = 0.0f;
        
       if        (direction == RIGHT) 
       {
          w = scale*frame*width;
          h = height;
          x = 0.0f;
          y = 0.0f;
       } 
       else if (direction == LEFT) 
       {
          w = scale*frame*width;
          h = height;
          x = width - w;
          y = 0.0f;
       } 
       else if (direction == UP) 
       {
          w = width;
          h = scale*frame*height;
          x = 0.0f;
          y = height - h;
       } 
       else
       {
          w = width;
          h = scale*frame*height;
          x = 0.0f;
          y = 0.0f;
       }

       clip = new Rectangle2D.Float(x, y, w, h);

       return clip;
    }
        
Operating on Individual Frames
Operating on Individual Frames (cont.)

An AbstractSuperimposition Class

javaexamples/visual/dynamic/sampled/AbstractSuperimposition.java
        package visual.dynamic.sampled;

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;


/**
 * An abstract implementation of the Superimposition interface.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class      AbstractSuperimposition 
                extends    AbstractFrameOp
                implements Superimposition
{
    private int             position;

    
    /**
     * Explicit Value Constructor
     *
     * @param first     The first frame
     * @param duration  The duration (in frames)
     * @param position  The position
     */
    public AbstractSuperimposition(int first, 
                                   int duration, 
                                   int position)
    {
       super(first, duration);

       this.position = SwingConstants.SOUTH_EAST;
       if ((position == SwingConstants.NORTH)      ||
           (position == SwingConstants.NORTH_EAST) ||
           (position == SwingConstants.EAST)       ||
           (position == SwingConstants.SOUTH_EAST) ||
           (position == SwingConstants.SOUTH)      ||
           (position == SwingConstants.SOUTH_WEST) ||
           (position == SwingConstants.WEST)       ||
           (position == SwingConstants.NORTH_WEST) ||
           (position == SwingConstants.CENTER    )    )
       {
          this.position = position;
       }
    }

    /**
     * Calculate the registration point for the superimposition
     * based on its size, the frame size, and the desired position
     *
     * @param frameWidth    The width of the frame
     * @param frameHeight   The height of the frame
     * @param siWidth       The width of the superimposition
     * @param siHeight      The height of the superimposition
     */
    protected Point2D calculateRegistrationPoint(double frameWidth, 
                                                 double frameHeight,
                                                 double siWidth,
                                                 double siHeight)
    {
       double         left, top;
      
       top  = 0.0;
       left = 0.0;
       if       (position == SwingConstants.NORTH)
       {
          top  = siHeight;
          left = frameWidth/2.0 - siWidth/2.0;
       }
       else if  (position == SwingConstants.NORTH_EAST)
       {
          top  = siHeight;
          left = frameWidth - siWidth - 1;
       }
       else if  (position == SwingConstants.EAST)
       {
          top  = frameHeight/2.0 - siHeight/2.0;
          left = frameWidth - siWidth - 1;
       }
       else if  (position == SwingConstants.SOUTH_EAST)
       {
          top  = frameHeight - siHeight - 1;
          left = frameWidth - siWidth - 1;
       }
       else if  (position == SwingConstants.SOUTH)
       {
          top  = frameHeight - siHeight - 1;
          left = frameWidth/2.0 - siWidth/2.0;
       }
       else if  (position == SwingConstants.SOUTH_WEST)
       {
          top  = frameHeight - siHeight - 1;
          left = 0.0;
       }
       else if  (position == SwingConstants.WEST)
       {
          top  = frameHeight/2.0 - siHeight/2.0;
          left = 0.0;
       }
       else if  (position == SwingConstants.NORTH_WEST)
       {
          top  = siHeight;
          left = 0.0;
       }
       else if  (position == SwingConstants.CENTER)
       {
          top  = frameHeight/2.0 - siHeight/2.0;
          left = frameWidth/2.0 - siWidth/2.0;
       }

       return new Point2D.Double(left, top);       
    }

    /**
     * Get the position
     * 
     * Possible values: javax.SwingConstants.NORTH, NORTH_EAST,
     * EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NORTH_WEST, or CENTER)
     * 
     * @return     The position
     */
    public int getPosition()
    {
       return position;
    }
    

    /**
     * Apply the post-rendering portion of
     * this Superimposition
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void postRendering(Graphics g, int frame);


    /**
     * Apply the pre-rendering portion of
     * this Superimposition
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void preRendering(Graphics g, int frame);

}
        
Operating on Individual Frames (cont.)

A TransformableContentSuperimposition Class

javaexamples/visual/dynamic/sampled/TransformableContentSuperimposition.java (Fragment: constructor)
            
    /**
     * Explicit Value Constructor
     *
     * @param content     The visual content to use
     * @param first       The first frame
     * @param duration    The duration (in frames)
     * @param position    The position (SwingConstants.NORTH, ...)
     */
    public TransformableContentSuperimposition(
                               TransformableContent content, 
                               int first, int duration, 
                               int position)
    {
       super(first, duration, position);
       
       this.content = content;
    }
        
javaexamples/visual/dynamic/sampled/TransformableContentSuperimposition.java (Fragment: postRendering)
        
          g2 = (Graphics2D)g;       
          
          // Transform the TransformableContent so that 
          // it is positioned properly
          frameBounds   = g2.getClipBounds();
          frameWidth    = (double)frameBounds.width;
          frameHeight   = (double)frameBounds.height;
          
          contentBounds = content.getBounds2D(false);
          contentWidth  = contentBounds.getWidth();
          contentHeight = contentBounds.getHeight();
          
          
          rp = calculateRegistrationPoint(frameWidth, 
                                          frameHeight,
                                          contentWidth, 
                                          contentHeight);
          
          content.setLocation(rp.getX(), rp.getY());
          content.render(g);
        
Design of a Sampled Dynamic Content System
Design of a Sampled Dynamic Content System (cont.)
images/sampled-dynamics_ops_design1.gif
Design of a Sampled Dynamic Content System (cont.)
images/sampled-dynamics_ops_design2.gif
Design of a Sampled Dynamic Content System (cont.)
images/sampled-dynamics_ops_design3.gif
Design of a Sampled Dynamic Content System (cont.)
images/sampled-dynamics_ops.gif
Design of a Sampled Dynamic Content System (cont.)

Common Requirements

javaexamples/visual/dynamic/sampled/FrameOp.java
        package visual.dynamic.sampled;

import java.awt.Graphics;

/**
 * The requirements of all operations on frames of sampled dyanmic
 * content (individual and multiple-frame operations)
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public interface FrameOp
{

    /**
     * Get the index of the first frame of this FrameOp
     *
     * @return  The index of the first frame
     */
    public abstract int getFirstFrame();

    
    /**
     * Get the index of the last frame of this FrameOp
     *
     * @return  The index of the last frame
     */
     public abstract int getLastFrame();


    /**
     * Apply the post-rendering portion of
     * this Transition
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void postRendering(Graphics g, int frame);


    /**
     * Apply the pre-rendering portion of
     * this Transition
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void preRendering(Graphics g, int frame);

}
        
Design (cont.)

Abstract Implementation

javaexamples/visual/dynamic/sampled/AbstractFrameOp.java
        package visual.dynamic.sampled;

import java.awt.Graphics;


/*
 * An abstract implementation of the FrameOp interface.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class      AbstractFrameOp 
                implements FrameOp
{
    protected int             duration, first;

    
    /**
     * Explicit Value Constructor
     *
     * @param first     The first frame
     * @param duration  The duration (in frames)
     */
    public AbstractFrameOp(int first, int duration)
    {
       this.first    = first;       
       this.duration = 0;
       if (duration > 0) this.duration = duration;
    }

    /**
     * Get the index of the first frame of this FrameOp
     *
     * @return  The index of the first frame
     */
    public int getFirstFrame()
    {
       return first;       
    }
    

    /**
     * Get the index of the last frame of this FrameOp
     *
     * @return  The index of the last frame
     */
    public int getLastFrame()
    {
       return first+duration;       
    }
    

    /**
     * Has this FrameOp finished at the given frame?
     *
     * @return true if finished; false otherwise
     */
    protected boolean hasFinishedAt(int frame)
    {
       return (frame >= (first+duration-1));       
    }
    
    
    

    /**
     * Apply the post-rendering portion of
     * this FrameOp
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void postRendering(Graphics g, int frame);


    /**
     * Apply the pre-rendering portion of
     * this FrameOp
     *
     * @param g      The rendering engine
     * @param frame  The current frame number
     */
    public abstract void preRendering(Graphics g, int frame);



    /**
     * Should this FrameOp be applied at the given frame
     *
     * @return true if yes; false otherwise
     */
    protected boolean shouldApplyAt(int frame)
    {
       return ((frame >= first) && (frame <= (first+duration-1)));       
    }
    
}
        
Implementation of the Design

The Screen Class

javaexamples/visual/dynamic/sampled/Screen.java (Fragment: transition1)
        
    // Attributes used for transitions
    private IntervalIndexedCollection<Transition> transitions;
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: superimposition1)
        
    // Attributes used for superimpositions
    private IntervalIndexedCollection<Superimposition> superimpositions;
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: transition3)
        
    /**
     * Add a Transition
     *
     * Note: This method does not ensure that 
     * the order is correct
     *
     * @param t   The Transition to add
     */
    public void addTransition(Transition t)
    {
       transitions.add(t, t.getFirstFrame(), t.getLastFrame());       
    }
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: transition4)
        
    /**
     * Get the current transitions (if any)
     *
     * @return   The current transitions
     */
    public Iterator<Transition> getTransitions()
    {
       Iterator<Transition>    result;
       
       result = null;
       if (frameNumber >= 0) result = transitions.iterator(frameNumber);

       return result;
    }
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: superimposition3)
        
    /**
     * Add a Superimposition
     *
     * Note: This method does not ensure that 
     * the order is correct
     *
     * @param si      The Superimposition to add
     */
    public void addSuperimposition(Superimposition si)
    {
       superimpositions.add(si, si.getFirstFrame(), si.getLastFrame());
    }
        
javaexamples/visual/dynamic/sampled/Screen.java (Fragment: superimposition4)
        
    /**
     * Get the current superimpositions (if any)
     *
     * @return   The current superimpositions
     */
    public Iterator<Superimposition> getSuperimpositions()
    {
       Iterator<Superimposition>    result;
       
       result = null;
       if (frameNumber >= 0) result = superimpositions.iterator(frameNumber);

       return result;
    }
        
Implementation of the Design (cont.)

The ScreenRenderer Class

javaexamples/visual/dynamic/sampled/ScreenRenderer.java (Fragment: preRendering)
        
    /**
     * Operations to perform before rendering
     *
     * @param g      The rendering engine
     * @param model  The Visualization containing the content
     * @param view   The component presenting the content
     */
    public void preRendering(Graphics          g,
                             Visualization     model,
                             VisualizationView view)
    {
       Graphics2D            g2;       
       int                   frameNumber;       
       Screen                smodel;       
       Iterator<Transition>  transitions;
       Iterator<Superimposition>  superimpositions;
       

       g2 = (Graphics2D)g;       
       oldComposite = g2.getComposite();       
       view.setDoubleBuffered(true);

       // Get information from the model
       smodel           = (Screen)model;
       transitions      = smodel.getTransitions();
       superimpositions = smodel.getSuperimpositions();
       frameNumber      = smodel.getFrameNumber();

       // Apply the transitions
       if (transitions != null)
       {
          while (transitions.hasNext())
          {
             transitions.next().preRendering(g, frameNumber);           
          }          
       }
       

       // Apply the superimpositions
       if (superimpositions != null)
       {
          while (superimpositions.hasNext())
          {
             superimpositions.next().preRendering(g, frameNumber);           
          }
       }
    }
        
javaexamples/visual/dynamic/sampled/ScreenRenderer.java (Fragment: postRendering)
        
    /**
     * Operations to perform after rendering
     *
     * @param g      The rendering engine
     * @param model  The Visualization containing the content
     * @param view   The component presenting the content
     */
    public void postRendering(Graphics          g,
                              Visualization     model,
                              VisualizationView view)
    {
       Graphics2D                g2;       
       int                       frameNumber;       
       Screen                    smodel;       
       Iterator<Transition>      transitions;
       Iterator<Superimposition> superimpositions;
       
       
       g2 = (Graphics2D)g;       
       g2.setComposite(oldComposite);       
       view.setDoubleBuffered(true);

       // Get information from the model
       smodel           = (Screen)model;
       frameNumber      = smodel.getFrameNumber();
       transitions      = smodel.getTransitions();
       superimpositions = smodel.getSuperimpositions();
       

       // Apply the transitions
       if (transitions != null)
       {
          while (transitions.hasNext())
          {
             transitions.next().postRendering(g, frameNumber);           
          }          
       }
       

       // Apply the superimpositions
       if (superimpositions != null)
       {
          while (superimpositions.hasNext())
          {
             superimpositions.next().postRendering(g, frameNumber);           
          }
       }
    }
        
javaexamples/visual/dynamic/sampled/ScreenRenderer.java (Fragment: render)
        
    /**
     * Render the content contained in the model.
     *
     *
     * @param g      The rendering engine
     * @param model  The Visualization containing the content
     * @param view   The component presenting the content
     */
    public void render(Graphics          g,
                       Visualization     model,
                       VisualizationView view)
    {
       decorated.render(g, model, view);       
    }