blob: 4d690d3a04ab08c79f519f85d81a761d0268ebfc [file] [log] [blame]
/*
*
* 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();
}
}
}