package org.phylowidget.render; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import org.andrewberman.ui.UIUtils; import org.phylowidget.PWPlatform; import processing.core.PGraphics; import processing.core.PGraphicsJava2D; public class DoubleBuffer implements Runnable { private PGraphicsJava2D dummyGraphics; private BufferedImage offscreen; private BufferedImage onscreen; private Graphics2D offscreenG; private Graphics2D onscreenG; // private PGraphics offscreen; // private PGraphics onscreen; Rectangle2D.Float onscreenRect; boolean shouldRepaint; protected boolean shouldTriggerRepaint = false; Thread repaintThread; public DoubleBuffer() { dummyGraphics = new PGraphicsJava2D(); dummyGraphics.setParent(PWPlatform.getInstance().getThisAppContext().getPW()); repaintThread = new Thread(this, "DoubleBuffer"); // repaintThread.setPriority(Thread.MIN_PRIORITY); repaintThread.start(); shouldTriggerRepaint = true; // dummyGraphics.g2.dispose(); // dummyGraphics.smooth(); } synchronized void triggerRepaint() { synchronized (this) { shouldRepaint = true; notifyAll(); } } private synchronized void allocateBuffers(PGraphics canvas) { if (offscreen != null) offscreen.flush(); if (onscreen != null) onscreen.flush(); count++; offscreen = new BufferedImage(canvas.width, canvas.height, BufferedImage.TYPE_INT_ARGB); onscreen = new BufferedImage(canvas.width, canvas.height, BufferedImage.TYPE_INT_ARGB); offscreenG = offscreen.createGraphics(); onscreenG = onscreen.createGraphics(); UIUtils.setRenderingHints(offscreenG); UIUtils.setRenderingHints(onscreenG); dummyGraphics.width = canvas.width; dummyGraphics.height = canvas.height; // dummyGraphics.smooth(); // UIUtils.setRenderingHints(offscreen); // UIUtils.setRenderingHints(onscreen); // onscreen.loadPixels(); // offscreen = canvas.parent.createGraphics(canvas.width, canvas.height, PGraphics.JAVA2D); // onscreen = canvas.parent.createGraphics(canvas.width, canvas.height, PGraphics.JAVA2D); } public void drawDoubleBuffered(PGraphics canvas) { if (offscreen == null || offscreen.getWidth() != canvas.width || offscreen.getHeight() != canvas.height) { /* * We have to re-allocate the offscreen image. */ allocateBuffers(canvas); } /* * Trigger a repaint in the double-buffering thread. */ if (shouldTriggerRepaint) { triggerRepaint(); } synchronized (onscreen) { /* * Blit the onscreen buffer onto the current canvas. */ canvas.loadPixels(); // Graphics2D g2 = (Graphics2D) canvas.getImage().getGraphics(); BufferedImage bi = (BufferedImage) canvas.image; // BufferedImage bi = (BufferedImage) canvas.getImage(); Graphics2D g2 = bi.createGraphics(); g2.drawImage(onscreen, 0, 0, null); g2.dispose(); } } public void drawToBuffer(PGraphics g) { // System.out.println("Draw" + System.currentTimeMillis()); } public void run() { while (true) { if (stopRunning) break; if (shouldRepaint) { synchronized (this) { dummyGraphics.image = offscreen; dummyGraphics.g2 = offscreenG; try { drawToBuffer(dummyGraphics); } catch (Exception e) { e.printStackTrace(); } /* * These lines are important for garbage collection!!! */ dummyGraphics.image = null; dummyGraphics.g2 = null; } synchronized (onscreen) { /* * Switch the offscreen and onscreen buffers. */ BufferedImage temp = offscreen; Graphics2D tempG = offscreenG; offscreen = onscreen; offscreenG = onscreenG; onscreen = temp; onscreenG = tempG; } } if (stopRunning) break; try { synchronized (this) { wait(); } } catch (InterruptedException e) { e.printStackTrace(); continue; } } dummyGraphics = null; offscreen = null; onscreen = null; offscreenG = null; onscreenG = null; onscreenRect = null; repaintThread = null; } static int count = 0; private boolean stopRunning = false; public synchronized void dispose() { stopRunning = true; this.notifyAll(); } }