I'm sorry if I have not worded the question title to well, so let me explain.
I am creating a game, actually a few and I see that most of the time when painting ect I use a JPanel, so I went and found a good method of painting (i.e it has great performance when multiple sprites etc are being painted) see here: Java 2D game graphics. I implemented that into my own kind of GameJPanel which will allow me to always have performance when painting on my games JPanels. Now to that I have added the methods like setDoubleBuffered(true) and RenderHints on when drawing:
if (isTextRenderHintsOn()) {
bg.setRenderingHints(textRenderHints);
}
if (isImageRenderHintsOn()) {
bg.setRenderingHints(imageRenderHints);
}
if (isColorRenderHintsOn()) {
bg.setRenderingHints(colorRenderHints);
}
if (isInterpolationRenderHintsOn()) {
bg.setRenderingHints(iterpolationRenderHints);
}
if (isRenderHintsOn()) {
bg.setRenderingHints(renderHints);
}
now without going to other libraries etc what more can I do to adjust the quality and or performance of whats being drawn on the JPanels?
It might also help to know that I use the GraphicsEnviroment and set the JFrame with the JPanel to full screen to gain a hardware accelerated image via a Buffer Strategy (not the linked performance drawing in swing also used some great techniques as is) below is an example of my GameDrawLibrary which implements the Java2D game graphics links' method and the rendering hints, the FullScreen class will be used for setting to and from full screen mode and the Test driver is just that:) :
Test Driver:
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* Test Driver
*
* @author David
*/
public class PureSwingPaintingTest extends JFrame {
static GameDrawLibrary gdl;
static Image image;
static final FullScreen fs = new FullScreen();
static int width = fs.getWidth(), height = fs.getHeight();
public PureSwingPaintingTest() {
setSize(width, height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gdl.createPanel();//create the panel
JPanel panel = gdl.getPanel();
JButton button = new JButton("Exit");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
getContentPane().add(button, BorderLayout.SOUTH);
getContentPane().add(panel, BorderLayout.CENTER);
}
public static void main(String[] args) {
try {
image = ImageIO.read(new File("c:/chess.jpg")).getScaledInstance(width, height, Image.SCALE_SMOOTH);
} catch (IOException ex) {
ex.printStackTrace();
}
gdl = new GameDrawLibrary(width, height, true, true, true, true, true, true) {
@Override
void updateGame() {
//update logic here
}
@Override
void renderGame(Graphics2D g) {
g.drawImage(image, 0, 0, this);
}
};
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (fs.isSupported()) {
fs.setFullScreen(new PureSwingPaintingTest());
} else {
fs.emulateFullScreen(new PureSwingPaintingTest());
}
gdl.showPanel();
}
});
}
}
Game JPanel library of sorts:
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
abstract class GameDrawLibrary extends JPanel {
private int width;
private int height;
private int scale;
private boolean isRunning = true;
private Canvas canvas;
private BufferStrategy strategy;
private BufferedImage background;
private Graphics2D backgroundGraphics;
private Graphics2D graphics;
private GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
//graphics quaultiy settings
private boolean textRenderHintsOn;
private boolean imageRenderHintsOn;
private boolean colorRenderHintsOn;
private boolean interpolationRenderHintsOn;
private boolean renderHintsOn;
private RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private RenderingHints colorRenderHints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
private RenderingHints iterpolationRenderHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
private RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
public GameDrawLibrary() {
setIgnoreRepaint(true);
this.textRenderHintsOn = false;
this.imageRenderHintsOn = false;
this.colorRenderHintsOn = false;
this.interpolationRenderHintsOn = false;
this.renderHintsOn = false;
}
GameDrawLibrary(int width, int height) {
setIgnoreRepaint(true);
this.width = width;
this.height = height;
this.scale = 1;
this.textRenderHintsOn = false;
this.imageRenderHintsOn = false;
this.colorRenderHintsOn = false;
this.interpolationRenderHintsOn = false;
this.renderHintsOn = false;
}
GameDrawLibrary(int width, int height, int scale) {
setIgnoreRepaint(true);
this.width = width;
this.height = height;
this.scale = scale;
this.textRenderHintsOn = false;
this.imageRenderHintsOn = false;
this.colorRenderHintsOn = false;
this.interpolationRenderHintsOn = false;
this.renderHintsOn = false;
}
public GameDrawLibrary(int width, int height, boolean textRenderHintsOn, boolean imageRenderHintsOn, boolean colorRenderHintsOn, boolean interpolationRenderHintsOn, boolean renderHintsOn, boolean isDoubleBuffered) {
super(isDoubleBuffered);
setIgnoreRepaint(true);
this.width = width;
this.height = height;
this.scale = 1;
this.textRenderHintsOn = textRenderHintsOn;
this.imageRenderHintsOn = imageRenderHintsOn;
this.colorRenderHintsOn = colorRenderHintsOn;
this.interpolationRenderHintsOn = interpolationRenderHintsOn;
this.renderHintsOn = renderHintsOn;
}
public GameDrawLibrary(int width, int height, int scale, boolean textRenderHintsOn, boolean imageRenderHintsOn, boolean colorRenderHintsOn, boolean interpolationRenderHintsOn, boolean renderHintsOn, boolean isDoubleBuffered) {
super(isDoubleBuffered);
this.width = width;
this.height = height;
this.scale = scale;
this.textRenderHintsOn = textRenderHintsOn;
this.imageRenderHintsOn = imageRenderHintsOn;
this.colorRenderHintsOn = colorRenderHintsOn;
this.interpolationRenderHintsOn = interpolationRenderHintsOn;
this.renderHintsOn = renderHintsOn;
}
// Screen and buffer stuff
private Graphics2D getBuffer() {
if (graphics == null) {
try {
graphics = (Graphics2D) strategy.getDrawGraphics();
} catch (IllegalStateException e) {
return null;
}
}
return graphics;
}
private boolean updateScreen() {
graphics.dispose();
graphics = null;
try {
strategy.show();
Toolkit.getDefaultToolkit().sync();
return (!strategy.contentsLost());
} catch (NullPointerException | IllegalStateException e) {
return true;
}
}
// update game logic here
abstract void updateGame();
//paint stuff here
abstract void renderGame(Graphics2D g);
//create and return the already sized JFrame
public void createPanel() {
setSize(getRealWidth(), getRealHeight());
}
public void showPanel() {
// Canvas
canvas = new Canvas(config);
canvas.setSize(width * scale, height * scale);
add(canvas, 0);
// Background & Buffer
background = create(width, height, false);
canvas.createBufferStrategy(2);
do {
strategy = canvas.getBufferStrategy();
} while (strategy == null);
startThread();//start thread to draw to the canvas
}
private void startThread() {
new Thread(new Runnable() {
@Override
public void run() {
backgroundGraphics = (Graphics2D) background.getGraphics();
long fpsWait = (long) (1.0 / 30 * 1000);
main:
while (isRunning) {
long renderStart = System.nanoTime();
updateGame();
// Update Graphics
do {
Graphics2D bg = getBuffer();
if (isTextRenderHintsOn()) {
bg.setRenderingHints(textRenderHints);
}
if (isImageRenderHintsOn()) {
bg.setRenderingHints(imageRenderHints);
}
if (isColorRenderHintsOn()) {
bg.setRenderingHints(colorRenderHints);
}
if (isInterpolationRenderHintsOn()) {
bg.setRenderingHints(iterpolationRenderHints);
}
if (isRenderHintsOn()) {
bg.setRenderingHints(renderHints);
}
if (!isRunning) {
break main;
}
renderGame(backgroundGraphics); // this calls your draw method
// thingy
if (scale != 1) {
bg.drawImage(background, 0, 0, width * scale, height * scale, 0, 0, width, height, null);
} else {
bg.drawImage(background, 0, 0, null);
}
bg.dispose();
} while (!updateScreen());
// Better do some FPS limiting here
long renderTime = (System.nanoTime() - renderStart) / 1000000;
try {
Thread.sleep(Math.max(0, fpsWait - renderTime));
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
// renderTime = (System.nanoTime() - renderStart) / 1000000;
}
}
}).start();
}
public JPanel getPanel() {
return this;
}
// create a hardware accelerated image
public final BufferedImage create(final int width, final int height, final boolean alpha) {
return config.createCompatibleImage(width, height, alpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE);
}
public void setColorRenderHintsOn(boolean colorRenderHintsOn) {
this.colorRenderHintsOn = colorRenderHintsOn;
}
public void setRenderHintsOn(boolean renderHintsOn) {
this.renderHintsOn = renderHintsOn;
}
public void setInterpolationRenderHintsOn(boolean interpolationRenderHintsOn) {
this.interpolationRenderHintsOn = interpolationRenderHintsOn;
}
public void setImageRenderHintsOn(boolean imageRenderHintsOn) {
this.imageRenderHintsOn = imageRenderHintsOn;
}
public void setTextRenderHintsOn(boolean textRenderHintsOn) {
this.textRenderHintsOn = textRenderHintsOn;
}
public boolean isColorRenderHintsOn() {
return colorRenderHintsOn;
}
public boolean isInterpolationRenderHintsOn() {
return interpolationRenderHintsOn;
}
public boolean isTextRenderHintsOn() {
return textRenderHintsOn;
}
public boolean isImageRenderHintsOn() {
return imageRenderHintsOn;
}
public boolean isRenderHintsOn() {
return renderHintsOn;
}
public int getRealHeight() {
return height * scale;
}
public int getRealWidth() {
return width * scale;
}
@Override
public int getHeight() {
return height;
}
@Override
public int getWidth() {
return width;
}
public int getScale() {
return scale;
}
public void setHeight(int height) {
this.height = height;
}
public void setWidth(int width) {
this.width = width;
}
public void setScale(int scale) {
this.scale = scale;
}
}
Fullscreen class:
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import javax.swing.JFrame;
/**
*
* @author David
*/
public class FullScreen {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
Dimension screenSize;
public FullScreen() {
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
}
public void setFullScreen(JFrame frame) {
if (gs.getFullScreenWindow() == null) {
frame.dispose();
frame.setUndecorated(true);
gs.setFullScreenWindow(frame);
frame.setVisible(true);
} else {// back to windowed mode
emulateFullScreen(frame);
}
}
public void emulateFullScreen(JFrame frame) {
frame.dispose();
frame.setUndecorated(false);
gs.setFullScreenWindow(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(screenSize);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public int getWidth() {
return gs.getDisplayMode().getWidth();
}
public int getHeight() {
return gs.getDisplayMode().getHeight();
}
public boolean isSupported() {
return gs.isFullScreenSupported();
}
}

Imagefor now) but I'd like to know besides the techniques already used how else can quality be improved – David Kroukamp Aug 8 '12 at 14:22