Path: blob/master/src/demo/share/jfc/J2Ddemo/java2d/Surface.java
41154 views
/*1*2* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7*8* - Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10*11* - Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* - Neither the name of Oracle nor the names of its16* contributors may be used to endorse or promote products derived17* from this software without specific prior written permission.18*19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS20* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,21* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR22* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR23* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,24* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,25* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR26* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF27* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING28* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS29* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/31package java2d;323334import static java.awt.RenderingHints.KEY_ANTIALIASING;35import static java.awt.RenderingHints.KEY_RENDERING;36import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;37import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;38import static java.awt.RenderingHints.VALUE_RENDER_QUALITY;39import static java.awt.RenderingHints.VALUE_RENDER_SPEED;40import java.awt.AlphaComposite;41import java.awt.Color;42import java.awt.Dimension;43import java.awt.Font;44import java.awt.Frame;45import java.awt.GradientPaint;46import java.awt.Graphics;47import java.awt.Graphics2D;48import java.awt.Image;49import java.awt.Paint;50import java.awt.Toolkit;51import java.awt.event.WindowAdapter;52import java.awt.event.WindowEvent;53import java.awt.image.BufferedImage;54import java.awt.image.DataBuffer;55import java.awt.image.DataBufferByte;56import java.awt.image.DataBufferInt;57import java.awt.image.DataBufferUShort;58import java.awt.image.DirectColorModel;59import java.awt.image.IndexColorModel;60import java.awt.image.Raster;61import java.awt.image.WritableRaster;62import java.awt.print.PageFormat;63import java.awt.print.Printable;64import java.awt.print.PrinterException;65import java.util.logging.Level;66import java.util.logging.Logger;67import javax.swing.JPanel;68import javax.swing.RepaintManager;697071/**72* Surface is the base class for the 2d rendering demos. Demos must73* implement the render() method. Subclasses for Surface are74* AnimatingSurface, ControlsSurface and AnimatingControlsSurface.75*/76@SuppressWarnings("serial")77public abstract class Surface extends JPanel implements Printable {7879public Object AntiAlias = VALUE_ANTIALIAS_ON;80public Object Rendering = VALUE_RENDER_SPEED;81public AlphaComposite composite;82public Paint texture;83public String perfStr; // PerformanceMonitor84public BufferedImage bimg;85public int imageType;86public String name;87public boolean clearSurface = true;88// Demos using animated gif's that implement ImageObserver set dontThread.89public boolean dontThread;90public AnimatingSurface animating;91protected long sleepAmount = 50;92private long orig, start, frame;93private Toolkit toolkit;94private boolean perfMonitor, outputPerf;95private int biw, bih;96private boolean clearOnce;97private boolean toBeInitialized = true;9899public Surface() {100setDoubleBuffered(this instanceof AnimatingSurface);101toolkit = getToolkit();102name = this.getClass().getSimpleName();103setImageType(0);104105// To launch an individual demo with the performance str output :106// java -Dj2ddemo.perf= -cp J2Ddemo.jar demos.Clipping.ClipAnim107try {108if (System.getProperty("j2ddemo.perf") != null) {109perfMonitor = outputPerf = true;110}111} catch (Exception ex) {112}113if (this instanceof AnimatingSurface) {114animating = (AnimatingSurface) this;115}116}117118protected Image getImage(String name) {119return DemoImages.getImage(name, this);120}121122protected Font getFont(String name) {123return DemoFonts.getFont(name);124}125126public int getImageType() {127return imageType;128}129130public final void setImageType(int imgType) {131if (imgType == 0) {132imageType = 1;133} else {134imageType = imgType;135}136bimg = null;137}138139public void setAntiAlias(boolean aa) {140AntiAlias = aa ? VALUE_ANTIALIAS_ON : VALUE_ANTIALIAS_OFF;141}142143public void setRendering(boolean rd) {144Rendering = rd ? VALUE_RENDER_QUALITY : VALUE_RENDER_SPEED;145}146147public void setTexture(Object obj) {148if (obj instanceof GradientPaint) {149texture = new GradientPaint(0, 0, Color.white,150getSize().width * 2, 0, Color.green);151} else {152texture = (Paint) obj;153}154}155156public void setComposite(boolean cp) {157composite = cp158? AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)159: null;160}161162public void setMonitor(boolean pm) {163perfMonitor = pm;164}165166public void setSleepAmount(long amount) {167sleepAmount = amount;168}169170public long getSleepAmount() {171return sleepAmount;172}173174public BufferedImage createBufferedImage(Graphics2D g2,175int w,176int h,177int imgType) {178BufferedImage bi = null;179if (imgType == 0) {180bi = g2.getDeviceConfiguration().181createCompatibleImage(w, h);182} else if (imgType > 0 && imgType < 14) {183bi = new BufferedImage(w, h, imgType);184} else if (imgType == 14) {185bi = createBinaryImage(w, h, 2);186} else if (imgType == 15) {187bi = createBinaryImage(w, h, 4);188} else if (imgType == 16) {189bi = createSGISurface(w, h, 32);190} else if (imgType == 17) {191bi = createSGISurface(w, h, 16);192}193return bi;194}195// Lookup tables for BYTE_BINARY 1, 2 and 4 bits.196private static final byte[] lut1Arr = new byte[] { 0, (byte) 255 };197private static final byte[] lut2Arr = new byte[] { 0, (byte) 85, (byte) 170, (byte) 255 };198private static final byte[] lut4Arr = new byte[] { 0, (byte) 17, (byte) 34, (byte) 51,199(byte) 68, (byte) 85, (byte) 102, (byte) 119,200(byte) 136, (byte) 153, (byte) 170, (byte) 187,201(byte) 204, (byte) 221, (byte) 238, (byte) 255 };202203private BufferedImage createBinaryImage(int w, int h, int pixelBits) {204int bytesPerRow = w * pixelBits / 8;205if (w * pixelBits % 8 != 0) {206bytesPerRow++;207}208byte[] imageData = new byte[h * bytesPerRow];209IndexColorModel cm = null;210switch (pixelBits) {211case 1:212cm = new IndexColorModel(pixelBits, lut1Arr.length,213lut1Arr, lut1Arr, lut1Arr);214break;215case 2:216cm = new IndexColorModel(pixelBits, lut2Arr.length,217lut2Arr, lut2Arr, lut2Arr);218break;219case 4:220cm = new IndexColorModel(pixelBits, lut4Arr.length,221lut4Arr, lut4Arr, lut4Arr);222break;223default:224Logger.getLogger(Surface.class.getName()).log(Level.SEVERE,225null, new Exception("Invalid # of bit per pixel"));226}227228DataBuffer db = new DataBufferByte(imageData, imageData.length);229WritableRaster r = Raster.createPackedRaster(db, w, h, pixelBits, null);230return new BufferedImage(cm, r, false, null);231}232233private BufferedImage createSGISurface(int w, int h, int pixelBits) {234int rMask32 = 0xFF000000;235int rMask16 = 0xF800;236int gMask32 = 0x00FF0000;237int gMask16 = 0x07C0;238int bMask32 = 0x0000FF00;239int bMask16 = 0x003E;240241DirectColorModel dcm = null;242DataBuffer db = null;243WritableRaster wr = null;244switch (pixelBits) {245case 16:246short[] imageDataUShort = new short[w * h];247dcm = new DirectColorModel(16, rMask16, gMask16, bMask16);248db = new DataBufferUShort(imageDataUShort,249imageDataUShort.length);250wr = Raster.createPackedRaster(db, w, h, w,251new int[] { rMask16, gMask16, bMask16 },252null);253break;254case 32:255int[] imageDataInt = new int[w * h];256dcm = new DirectColorModel(32, rMask32, gMask32, bMask32);257db = new DataBufferInt(imageDataInt, imageDataInt.length);258wr = Raster.createPackedRaster(db, w, h, w,259new int[] { rMask32, gMask32, bMask32 },260null);261break;262default:263Logger.getLogger(Surface.class.getName()).log(Level.SEVERE,264null, new Exception("Invalid # of bit per pixel"));265}266267return new BufferedImage(dcm, wr, false, null);268}269270public Graphics2D createGraphics2D(int width,271int height,272BufferedImage bi,273Graphics g) {274275Graphics2D g2 = null;276277if (bi != null) {278g2 = bi.createGraphics();279} else {280g2 = (Graphics2D) g;281}282283g2.setBackground(getBackground());284g2.setRenderingHint(KEY_ANTIALIASING, AntiAlias);285g2.setRenderingHint(KEY_RENDERING, Rendering);286287if (clearSurface || clearOnce) {288g2.clearRect(0, 0, width, height);289clearOnce = false;290}291292if (texture != null) {293// set composite to opaque for texture fills294g2.setComposite(AlphaComposite.SrcOver);295g2.setPaint(texture);296g2.fillRect(0, 0, width, height);297}298299if (composite != null) {300g2.setComposite(composite);301}302303return g2;304}305306// ...demos that extend Surface must implement this routine...307public abstract void render(int w, int h, Graphics2D g2);308309/**310* It's possible to turn off double-buffering for just the repaint311* calls invoked directly on the non double buffered component.312* This can be done by overriding paintImmediately() (which is called313* as a result of repaint) and getting the current RepaintManager and314* turning off double buffering in the RepaintManager before calling315* super.paintImmediately(g).316*/317@Override318public void paintImmediately(int x, int y, int w, int h) {319RepaintManager repaintManager = null;320boolean save = true;321if (!isDoubleBuffered()) {322repaintManager = RepaintManager.currentManager(this);323save = repaintManager.isDoubleBufferingEnabled();324repaintManager.setDoubleBufferingEnabled(false);325}326super.paintImmediately(x, y, w, h);327328if (repaintManager != null) {329repaintManager.setDoubleBufferingEnabled(save);330}331}332333@Override334public void paint(Graphics g) {335336super.paint(g);337338Dimension d = getSize();339340if (biw != d.width || bih != d.height) {341toBeInitialized = true;342biw = d.width;343bih = d.height;344}345346if (imageType == 1) {347bimg = null;348} else if (bimg == null || toBeInitialized) {349bimg = createBufferedImage((Graphics2D) g,350d.width, d.height, imageType - 2);351clearOnce = true;352}353354if (toBeInitialized) {355if (animating != null) {356animating.reset(d.width, d.height);357}358toBeInitialized = false;359startClock();360}361362if (animating != null && animating.running()) {363animating.step(d.width, d.height);364}365Graphics2D g2 = createGraphics2D(d.width, d.height, bimg, g);366render(d.width, d.height, g2);367g2.dispose();368369if (bimg != null) {370g.drawImage(bimg, 0, 0, null);371toolkit.sync();372}373374if (perfMonitor) {375LogPerformance();376}377}378379@Override380public int print(Graphics g, PageFormat pf, int pi) throws PrinterException {381if (pi >= 1) {382return Printable.NO_SUCH_PAGE;383}384385Graphics2D g2d = (Graphics2D) g;386g2d.translate(pf.getImageableX(), pf.getImageableY());387g2d.translate(pf.getImageableWidth() / 2,388pf.getImageableHeight() / 2);389390Dimension d = getSize();391392double scale = Math.min(pf.getImageableWidth() / d.width,393pf.getImageableHeight() / d.height);394if (scale < 1.0) {395g2d.scale(scale, scale);396}397398g2d.translate(-d.width / 2.0, -d.height / 2.0);399400if (bimg == null) {401Graphics2D g2 = createGraphics2D(d.width, d.height, null, g2d);402render(d.width, d.height, g2);403g2.dispose();404} else {405g2d.drawImage(bimg, 0, 0, this);406}407408return Printable.PAGE_EXISTS;409}410411public void startClock() {412orig = System.currentTimeMillis();413start = orig;414frame = 0;415}416private static final int REPORTFRAMES = 30;417418private void LogPerformance() {419if ((frame % REPORTFRAMES) == 0) {420long end = System.currentTimeMillis();421long rel = (end - start);422if (frame == 0) {423perfStr = name + " " + rel + " ms";424if (animating == null || !animating.running()) {425frame = -1;426}427} else {428String s1 = Float.toString((REPORTFRAMES / (rel / 1000.0f)));429s1 = (s1.length() < 4) ? s1.substring(0, s1.length()) : s1.430substring(0, 4);431perfStr = name + " " + s1 + " fps";432}433if (outputPerf) {434System.out.println(perfStr);435}436start = end;437}438++frame;439}440441// System.out graphics state information.442public void verbose(GlobalControls controls) {443String str = " " + name + " ";444if (animating != null && animating.running()) {445str = str.concat(" Running");446} else if (this instanceof AnimatingSurface) {447str = str.concat(" Stopped");448}449450if (controls != null) {451str = str.concat(" " + controls.screenCombo.getSelectedItem());452}453454str.concat((AntiAlias == VALUE_ANTIALIAS_ON) ? " ANTIALIAS_ON "455: " ANTIALIAS_OFF ");456str.concat((Rendering == VALUE_RENDER_QUALITY) ? "RENDER_QUALITY "457: "RENDER_SPEED ");458459if (texture != null) {460str = str.concat("Texture ");461}462463if (composite != null) {464str = str.concat("Composite=" + composite.getAlpha() + " ");465}466467Runtime r = Runtime.getRuntime();468r.gc();469float freeMemory = r.freeMemory();470float totalMemory = r.totalMemory();471str = str.concat(((totalMemory - freeMemory) / 1024) + "K used");472System.out.println(str);473}474475public static void createDemoFrame(Surface surface) {476final DemoPanel dp = new DemoPanel(surface, new DemoInstVarsAccessorImplBase());477Frame f = new Frame("J2D Demo - " + surface.name);478f.addWindowListener(new WindowAdapter() {479480@Override481public void windowClosing(WindowEvent e) {482System.exit(0);483}484485@Override486public void windowDeiconified(WindowEvent e) {487dp.start();488}489490@Override491public void windowIconified(WindowEvent e) {492dp.stop();493}494});495f.add("Center", dp);496f.pack();497f.setSize(new Dimension(500, 300));498f.setVisible(true);499if (surface.animating != null) {500surface.animating.start();501}502}503}504505506