Since it is my first post I would like to say hello everybody
The goal of my program is to test how many FPS I can get while consnstantly drawing on the screen.
I would really appreciate if you can point any bottlenecks or suggest improvements.
The problem is that on one machine I can get around 2700 FPS, on the other with similiar hardware setup (but different OS) I get like 60-70.
If you want to compile those codes just remember to set image paths.
First my interface and implementation of FPS counting.
public interface FPS {
int getFPSFrames();
void setFPSFrames(int value);
}
public class FPSTask extends TimerTask {
private FPS fps;
public FPSTask(FPS fps) {
this.fps = fps;
}
public void run() {
System.out.println("Last: " + System.currentTimeMillis() + " frames: " + fps.getFPSFrames());
fps.setFPSFrames(0);
}
}
Bitmap with Screen based on the Catacomb Snatch sources.
public class Bitmap {
protected int w, h;
protected int pixels[];
public Bitmap(int w, int h) {
this(w, h, true);
}
protected Bitmap(int w, int h, boolean createPixels) {
this.w = w;
this.h = h;
if (createPixels) {
pixels = new int[w * h];
}
}
public void blit(Bitmap bitmap, int x, int y) {
Rectangle blitArea = new Rectangle(x, y, x + bitmap.w, y + bitmap.h);
adjustBlitArea(blitArea);
int blitWidth = blitArea.x2 - blitArea.x1;
for (int yy = blitArea.y1; yy < blitArea.y2; yy++) {
int targetPixel = yy * w + blitArea.x1;
int sourcePixel = (yy - y) * bitmap.w + (blitArea.x1 - x);
targetPixel -= sourcePixel;
for (int xx = sourcePixel; xx < sourcePixel + blitWidth; xx++) {
int col = bitmap.pixels[xx];
int alpha = (col >> 24) & 0xff;
if (alpha == 0xff) {
pixels[targetPixel + xx] = col;
} else {
int bgCol = pixels[targetPixel + xx];
pixels[targetPixel + xx] = blendColors(bgCol, col);
}
}
}
}
private Rectangle adjustBlitArea(Rectangle blitArea) {
if (blitArea.x1 < 0) blitArea.x1 = 0;
if (blitArea.y1 < 0) blitArea.y1 = 0;
if (blitArea.x2 > w) blitArea.x2 = w;
if (blitArea.y2 > h) blitArea.y2 = h;
return blitArea;
}
public int getWidth() {
return w;
}
public int getHeight() {
return h;
}
public static Bitmap load(String filename) {
try {
BufferedImage bi = ImageIO.read(new File(filename));
int biWidth = bi.getWidth();
int biHeight = bi.getHeight();
Bitmap bitmap = new Bitmap(biWidth, biHeight);
bi.getRGB(0, 0, biWidth, biHeight, bitmap.pixels, 0, biWidth);
return bitmap;
} catch (IOException e) {
return null;
}
}
public static int blendColors(int backgroundColor, int colorToBlend) {
RGB bgRGB = new RGB(backgroundColor);
RGB pixelRGB = new RGB(colorToBlend);
int bgAlpha = 256 - pixelRGB.alpha;
int r = ((pixelRGB.r * pixelRGB.alpha + bgRGB.r * bgAlpha) >> 8) & 0xff0000;
int g = ((pixelRGB.g * pixelRGB.alpha + bgRGB.g * bgAlpha) >> 8) & 0xff00;
int b = ((pixelRGB.b * pixelRGB.alpha + bgRGB.b * bgAlpha) >> 8) & 0xff;
return 0xff000000 | r | g | b;
}
}
public class Screen extends Bitmap {
protected final BufferedImage image;
public Screen(int w, int h) {
super(w, h, false);
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
}
public Image getImage() {
return image;
}
}
Helper classes used in Bitmap.
public class Rectangle extends java.awt.Rectangle {
public int x1, y1, x2, y2;
public Rectangle(int x1, int y1, int x2, int y2) {
super(x1, y1, x2 - x1, y2 - y1);
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
public class RGB {
public int r, g, b;
public int alpha;
public RGB(int color) {
r = color & 0xff0000;
g = color & 0xff00;
b = color & 0xff;
alpha = color & 0xff000000;
}
}
And finally whole program (based on ra4king’s game skeleton):
public class TestJFrame extends JFrame implements FPS, Runnable {
public static final int MAX_OBJECTS = 500;
private int frames;
private Screen screen;
private Bitmap background;
private Bitmap object;
private Canvas canvas;
public TestJFrame() {
setSize(640, 480);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
setIgnoreRepaint(true);
screen = new Screen(getWidth(), getHeight());
canvas = new Canvas();
canvas.setSize(getWidth(), getHeight());
add(canvas);
pack();
background = Bitmap.load("your_path_to_any_background.png"); //TODO set path, my background was 640x480.
object = Bitmap.load("your_path_to_any_object"); //TODO set path, my object was 32x32.
}
public static void main(String[] args) {
TestJFrame testJFrame = new TestJFrame();
Thread t = new Thread(testJFrame);
t.start();
}
public void run() {
Timer timer = new Timer();
FPSTask fpsTask = new FPSTask(this);
timer.schedule(fpsTask, 0, 1000);
canvas.createBufferStrategy(2);
canvas.setIgnoreRepaint(true);
BufferStrategy bs = canvas.getBufferStrategy();
while (true) {
do {
do {
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
render(g);
g.dispose();
} while (bs.contentsRestored());
bs.show();
} while (bs.contentsLost());
frames++;
}
}
private void render(Graphics g) {
g.setColor(Color.black);
draw(MAX_OBJECTS);
g.drawImage(screen.getImage(), 0, 0, getWidth(), getHeight(), null);
}
private void draw(int objects) {
screen.blit(background, 0, 0);
for (int i = 0; i < MAX_OBJECTS; i++) {
screen.blit(object, (int) (Math.random() * 640), (int) (Math.random() * 480));
}
}
public int getFPSFrames() {
return frames;
}
public void setFPSFrames(int value) {
frames = value;
}
}