/* * * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java2d; import static java.awt.RenderingHints.KEY_ANTIALIASING; import static java.awt.RenderingHints.KEY_RENDERING; import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF; import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; import static java.awt.RenderingHints.VALUE_RENDER_QUALITY; import static java.awt.RenderingHints.VALUE_RENDER_SPEED; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Paint; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferUShort; import java.awt.image.DirectColorModel; import java.awt.image.IndexColorModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JPanel; import javax.swing.RepaintManager; /** * Surface is the base class for the 2d rendering demos. Demos must * implement the render() method. Subclasses for Surface are * AnimatingSurface, ControlsSurface and AnimatingControlsSurface. */ @SuppressWarnings("serial") public abstract class Surface extends JPanel implements Printable { public Object AntiAlias = VALUE_ANTIALIAS_ON; public Object Rendering = VALUE_RENDER_SPEED; public AlphaComposite composite; public Paint texture; public String perfStr; // PerformanceMonitor public BufferedImage bimg; public int imageType; public String name; public boolean clearSurface = true; // Demos using animated gif's that implement ImageObserver set dontThread. public boolean dontThread; public AnimatingSurface animating; protected long sleepAmount = 50; private long orig, start, frame; private Toolkit toolkit; private boolean perfMonitor, outputPerf; private int biw, bih; private boolean clearOnce; private boolean toBeInitialized = true; public Surface() { setDoubleBuffered(this instanceof AnimatingSurface); toolkit = getToolkit(); name = this.getClass().getSimpleName(); setImageType(0); // To launch an individual demo with the performance str output : // java -Dj2ddemo.perf= -cp J2Ddemo.jar demos.Clipping.ClipAnim try { if (System.getProperty("j2ddemo.perf") != null) { perfMonitor = outputPerf = true; } } catch (Exception ex) { } if (this instanceof AnimatingSurface) { animating = (AnimatingSurface) this; } } protected Image getImage(String name) { return DemoImages.getImage(name, this); } protected Font getFont(String name) { return DemoFonts.getFont(name); } public int getImageType() { return imageType; } public final void setImageType(int imgType) { if (imgType == 0) { imageType = 1; } else { imageType = imgType; } bimg = null; } public void setAntiAlias(boolean aa) { AntiAlias = aa ? VALUE_ANTIALIAS_ON : VALUE_ANTIALIAS_OFF; } public void setRendering(boolean rd) { Rendering = rd ? VALUE_RENDER_QUALITY : VALUE_RENDER_SPEED; } public void setTexture(Object obj) { if (obj instanceof GradientPaint) { texture = new GradientPaint(0, 0, Color.white, getSize().width * 2, 0, Color.green); } else { texture = (Paint) obj; } } public void setComposite(boolean cp) { composite = cp ? AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f) : null; } public void setMonitor(boolean pm) { perfMonitor = pm; } public void setSleepAmount(long amount) { sleepAmount = amount; } public long getSleepAmount() { return sleepAmount; } public BufferedImage createBufferedImage(Graphics2D g2, int w, int h, int imgType) { BufferedImage bi = null; if (imgType == 0) { bi = g2.getDeviceConfiguration(). createCompatibleImage(w, h); } else if (imgType > 0 && imgType < 14) { bi = new BufferedImage(w, h, imgType); } else if (imgType == 14) { bi = createBinaryImage(w, h, 2); } else if (imgType == 15) { bi = createBinaryImage(w, h, 4); } else if (imgType == 16) { bi = createSGISurface(w, h, 32); } else if (imgType == 17) { bi = createSGISurface(w, h, 16); } return bi; } // Lookup tables for BYTE_BINARY 1, 2 and 4 bits. private static final byte[] lut1Arr = new byte[] { 0, (byte) 255 }; private static final byte[] lut2Arr = new byte[] { 0, (byte) 85, (byte) 170, (byte) 255 }; private static final byte[] lut4Arr = new byte[] { 0, (byte) 17, (byte) 34, (byte) 51, (byte) 68, (byte) 85, (byte) 102, (byte) 119, (byte) 136, (byte) 153, (byte) 170, (byte) 187, (byte) 204, (byte) 221, (byte) 238, (byte) 255 }; private BufferedImage createBinaryImage(int w, int h, int pixelBits) { int bytesPerRow = w * pixelBits / 8; if (w * pixelBits % 8 != 0) { bytesPerRow++; } byte[] imageData = new byte[h * bytesPerRow]; IndexColorModel cm = null; switch (pixelBits) { case 1: cm = new IndexColorModel(pixelBits, lut1Arr.length, lut1Arr, lut1Arr, lut1Arr); break; case 2: cm = new IndexColorModel(pixelBits, lut2Arr.length, lut2Arr, lut2Arr, lut2Arr); break; case 4: cm = new IndexColorModel(pixelBits, lut4Arr.length, lut4Arr, lut4Arr, lut4Arr); break; default: Logger.getLogger(Surface.class.getName()).log(Level.SEVERE, null, new Exception("Invalid # of bit per pixel")); } DataBuffer db = new DataBufferByte(imageData, imageData.length); WritableRaster r = Raster.createPackedRaster(db, w, h, pixelBits, null); return new BufferedImage(cm, r, false, null); } private BufferedImage createSGISurface(int w, int h, int pixelBits) { int rMask32 = 0xFF000000; int rMask16 = 0xF800; int gMask32 = 0x00FF0000; int gMask16 = 0x07C0; int bMask32 = 0x0000FF00; int bMask16 = 0x003E; DirectColorModel dcm = null; DataBuffer db = null; WritableRaster wr = null; switch (pixelBits) { case 16: short[] imageDataUShort = new short[w * h]; dcm = new DirectColorModel(16, rMask16, gMask16, bMask16); db = new DataBufferUShort(imageDataUShort, imageDataUShort.length); wr = Raster.createPackedRaster(db, w, h, w, new int[] { rMask16, gMask16, bMask16 }, null); break; case 32: int[] imageDataInt = new int[w * h]; dcm = new DirectColorModel(32, rMask32, gMask32, bMask32); db = new DataBufferInt(imageDataInt, imageDataInt.length); wr = Raster.createPackedRaster(db, w, h, w, new int[] { rMask32, gMask32, bMask32 }, null); break; default: Logger.getLogger(Surface.class.getName()).log(Level.SEVERE, null, new Exception("Invalid # of bit per pixel")); } return new BufferedImage(dcm, wr, false, null); } public Graphics2D createGraphics2D(int width, int height, BufferedImage bi, Graphics g) { Graphics2D g2 = null; if (bi != null) { g2 = bi.createGraphics(); } else { g2 = (Graphics2D) g; } g2.setBackground(getBackground()); g2.setRenderingHint(KEY_ANTIALIASING, AntiAlias); g2.setRenderingHint(KEY_RENDERING, Rendering); if (clearSurface || clearOnce) { g2.clearRect(0, 0, width, height); clearOnce = false; } if (texture != null) { // set composite to opaque for texture fills g2.setComposite(AlphaComposite.SrcOver); g2.setPaint(texture); g2.fillRect(0, 0, width, height); } if (composite != null) { g2.setComposite(composite); } return g2; } // ...demos that extend Surface must implement this routine... public abstract void render(int w, int h, Graphics2D g2); /** * It's possible to turn off double-buffering for just the repaint * calls invoked directly on the non double buffered component. * This can be done by overriding paintImmediately() (which is called * as a result of repaint) and getting the current RepaintManager and * turning off double buffering in the RepaintManager before calling * super.paintImmediately(g). */ @Override public void paintImmediately(int x, int y, int w, int h) { RepaintManager repaintManager = null; boolean save = true; if (!isDoubleBuffered()) { repaintManager = RepaintManager.currentManager(this); save = repaintManager.isDoubleBufferingEnabled(); repaintManager.setDoubleBufferingEnabled(false); } super.paintImmediately(x, y, w, h); if (repaintManager != null) { repaintManager.setDoubleBufferingEnabled(save); } } @Override public void paint(Graphics g) { super.paint(g); Dimension d = getSize(); if (biw != d.width || bih != d.height) { toBeInitialized = true; biw = d.width; bih = d.height; } if (imageType == 1) { bimg = null; } else if (bimg == null || toBeInitialized) { bimg = createBufferedImage((Graphics2D) g, d.width, d.height, imageType - 2); clearOnce = true; } if (toBeInitialized) { if (animating != null) { animating.reset(d.width, d.height); } toBeInitialized = false; startClock(); } if (animating != null && animating.running()) { animating.step(d.width, d.height); } Graphics2D g2 = createGraphics2D(d.width, d.height, bimg, g); render(d.width, d.height, g2); g2.dispose(); if (bimg != null) { g.drawImage(bimg, 0, 0, null); toolkit.sync(); } if (perfMonitor) { LogPerformance(); } } @Override public int print(Graphics g, PageFormat pf, int pi) throws PrinterException { if (pi >= 1) { return Printable.NO_SUCH_PAGE; } Graphics2D g2d = (Graphics2D) g; g2d.translate(pf.getImageableX(), pf.getImageableY()); g2d.translate(pf.getImageableWidth() / 2, pf.getImageableHeight() / 2); Dimension d = getSize(); double scale = Math.min(pf.getImageableWidth() / d.width, pf.getImageableHeight() / d.height); if (scale < 1.0) { g2d.scale(scale, scale); } g2d.translate(-d.width / 2.0, -d.height / 2.0); if (bimg == null) { Graphics2D g2 = createGraphics2D(d.width, d.height, null, g2d); render(d.width, d.height, g2); g2.dispose(); } else { g2d.drawImage(bimg, 0, 0, this); } return Printable.PAGE_EXISTS; } public void startClock() { orig = System.currentTimeMillis(); start = orig; frame = 0; } private static final int REPORTFRAMES = 30; private void LogPerformance() { if ((frame % REPORTFRAMES) == 0) { long end = System.currentTimeMillis(); long rel = (end - start); if (frame == 0) { perfStr = name + " " + rel + " ms"; if (animating == null || !animating.running()) { frame = -1; } } else { String s1 = Float.toString((REPORTFRAMES / (rel / 1000.0f))); s1 = (s1.length() < 4) ? s1.substring(0, s1.length()) : s1. substring(0, 4); perfStr = name + " " + s1 + " fps"; } if (outputPerf) { System.out.println(perfStr); } start = end; } ++frame; } // System.out graphics state information. public void verbose(GlobalControls controls) { String str = " " + name + " "; if (animating != null && animating.running()) { str = str.concat(" Running"); } else if (this instanceof AnimatingSurface) { str = str.concat(" Stopped"); } if (controls != null) { str = str.concat(" " + controls.screenCombo.getSelectedItem()); } str.concat((AntiAlias == VALUE_ANTIALIAS_ON) ? " ANTIALIAS_ON " : " ANTIALIAS_OFF "); str.concat((Rendering == VALUE_RENDER_QUALITY) ? "RENDER_QUALITY " : "RENDER_SPEED "); if (texture != null) { str = str.concat("Texture "); } if (composite != null) { str = str.concat("Composite=" + composite.getAlpha() + " "); } Runtime r = Runtime.getRuntime(); r.gc(); float freeMemory = r.freeMemory(); float totalMemory = r.totalMemory(); str = str.concat(((totalMemory - freeMemory) / 1024) + "K used"); System.out.println(str); } public static void createDemoFrame(Surface surface) { final DemoPanel dp = new DemoPanel(surface, new DemoInstVarsAccessorImplBase()); Frame f = new Frame("J2D Demo - " + surface.name); f.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } @Override public void windowDeiconified(WindowEvent e) { dp.start(); } @Override public void windowIconified(WindowEvent e) { dp.stop(); } }); f.add("Center", dp); f.pack(); f.setSize(new Dimension(500, 300)); f.setVisible(true); if (surface.animating != null) { surface.animating.start(); } } }