Re: thread-safe graphics access
 
In article <4a3f904c$0$23641$b9f67a60@news.newsdemon.com>,
 Knute Johnson <nospam@rabbitbrush.frazmtn.com> wrote:
[...]
Video performance depends on so many different things it 
is often very difficult to tell where the bottle neck is.
Thanks for this interesting example. I was intrigued by the variability 
in frame rate as a function of angle and size, which your approach 
highlights. For comparison, I tried transforming a Polygon, translating, 
scaling and rotating as the panel's size changes:
<code>
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.lang.reflect.*;
import javax.swing.*;
public class Rotate extends JPanel implements Runnable {
    private volatile BufferedImage bi;
    private volatile long then;
    private Thread thread;
    private double angle;
    private int n;
    private double rate;
    private static final AffineTransform at = new AffineTransform();
    private static final Polygon poly = new Polygon();
    static {
        poly.addPoint( 1, -1);
        poly.addPoint( 1,  1);
        poly.addPoint(-1,  1);
        poly.addPoint(-1, -1);
    }
    public Rotate() {
        setPreferredSize(new Dimension(400, 400));
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent ce) {
                GraphicsConfiguration gc = getGraphicsConfiguration();
                bi = gc.createCompatibleImage(
                    getWidth(), getHeight(), BufferedImage.OPAQUE);
            }
        });
    }
    public void start() {
        then = System.nanoTime();
        thread = new Thread(this);
        thread.start();
    }
    public void stop() {
        thread.interrupt();
    }
    public void run() {
        try {
            while (true) {
                render();
                try {
                    EventQueue.invokeAndWait(new Runnable() {
                        public void run() {
                            paintImmediately(getBounds());
                        }
                    });
                } catch (InvocationTargetException ite) {
                    System.out.println(ite);
                }
            }
        } catch (InterruptedException ie) {
            System.out.println(ie);
        }
    }
    private void render() {
        int w = getWidth();
        int h = getHeight();
        Graphics2D g = bi.createGraphics();
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, w, h);
        g.setColor(Color.RED);
        g.drawString(String.format("%5.1f", rate), 5, 12);
        angle += 0.001;
        at.setToIdentity();
        at.translate(w/2, h/2);
        at.scale(w/3, h/3);
        at.rotate(angle);
        g.setColor(Color.BLUE);
        g.fill(at.createTransformedShape(poly));
        if (++n % 100 == 0) {
            long now = System.nanoTime();
            rate = 100000000000.0 / (now - then);
            then = now;
        }
        g.dispose();
    }
    public void paintComponent(Graphics g) {
        g.drawImage(bi, 0, 0, null);
    }
    public static void main(String[] args) {
        final Rotate rotate = new Rotate();
        final JFrame f = new JFrame();
        f.addWindowListener(new WindowAdapter() {
            public void windowOpened(WindowEvent we) {
                rotate.start();
            }
            public void windowClosing(WindowEvent we) {
                rotate.stop();
                f.dispose();
            }
        });
        f.add(rotate, BorderLayout.CENTER);
        f.pack();
        f.setVisible(true);
    }
}
</code>
-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>