I'm developing a physics sandbox game. I can easily fill the whole screen with rotated, scaled, textured boxes without noticing any FPS drops or excessive CPU usage, and drawing the character without a rotate transformation is fast.
However, if I rotate the character image, or scale it, CPU usage goes through the roof and there is a small but noticable FPS decrease. Using a profiler, I determined that drawImage() was the problem. As far as I can tell the character and texture images are being drawn the same way... It's really confounding.
From the character:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private VolatileImage character = Util.getGraphicsConfiguration().createCompatibleVolatileImage(200, 200, Transparency.BITMASK); [...] public void draw(Graphics g) throws BuildismException { updateImage(); Vec2D pos = getPart().getPosition().worldToScreen(Main.getView()); int w = (int) (200*(Main.getView().scaleFactor/8)); int h = (int) (200*(Main.getView().scaleFactor/8)); int imgX = (int) pos.getX() - w/2; int imgY = (int) pos.getY() - h/2; AffineTransform orig = ((Graphics2D)g).getTransform(); AffineTransform rotate = AffineTransform.getRotateInstance(-Math.toRadians(getPart().getRotation()), pos.getX(), pos.getY()); ((Graphics2D)g).setTransform(rotate); g.drawImage(character, imgX, imgY, w, h, null); ((Graphics2D)g).setTransform(orig); } |
For textured boxes (yes, I know this code is messy and unoptimized... but it works faster than the much simpler code for drawing a character!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public void setTexture(BufferedImage t) { if(t != null) { VolatileImage i = Util.getGraphicsConfiguration().createCompatibleVolatileImage(t.getWidth(), t.getHeight(), Transparency.TRANSLUCENT); Graphics2D g2 = (Graphics2D) i.getGraphics(); Composite old = g2.getComposite(); g2.setColor(transparent); g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT)); g2.fillRect(0, 0, t.getWidth(), t.getHeight()); g2.setComposite(old); g2.drawImage(t, 0, 0, null); texture = i; } else texture = null; }
[...]
Graphics2D g2 = (Graphics2D) g; Vec2D worldPos = new Vec2D(body.getPosition()); Vec2D imgPos = worldPos.add(new Vec2D(-getVec2DProp("Size").getX(), getVec2DProp("Size").getY()).mul(0.5)).worldToScreen(Main.getView()); Vec2D rotateCenter = worldPos.worldToScreen(Main.getView()); AffineTransform original = g2.getTransform(); AffineTransform scale = AffineTransform.getScaleInstance(scaleDimensionForScreen(texture.getWidth(), getVec2DProp("Size").getX()), scaleDimensionForScreen(texture.getHeight(), getVec2DProp("Size").getY())); AffineTransform rotate = AffineTransform.getRotateInstance(-body.getAngle(), rotateCenter.getX(), rotateCenter.getY()); g2.setTransform(rotate); g2.transform(scale); g2.drawImage(texture, (int) (imgPos.getX() / ((Main.getView().scaleFactor * getVec2DProp("Size").getX())/texture.getWidth())), (int) (imgPos.getY() / ((Main.getView().scaleFactor * getVec2DProp("Size").getY())/texture.getHeight())), null); g2.setTransform(original); |
Does anyone see a problem?