There are several problems with your image generator:
- Since the bounds of the image is modified by the rotation, when you call drawImage(source, 0, 0, null) for instance, you can no longer expect the top-left corner of the rotated source image to be at (0, 0) on the destination. Imagine it this way: A plain rectangle image stamped at (20, 0) and then rotated 45 degrees - you get an image whose minimum bounds are less than (20, 0).
Workaround:
Draw the current rotation onto an intermediate image first, then stamp that where you want it to be on the destination.
Example:
public BufferedImage generateRotatedImages(BufferedImage sourceImage, int numFrames)
{
// TODO Add support for arbitrary alpha values when Java gets fast enough.
BufferedImage image = graphicsConfiguration.createCompatibleImage(sourceImage.getWidth()
* numFrames, sourceImage.getHeight(), Transparency.BITMASK);
// An intermediate image to draw a rotated instance of the source image
BufferedImage rotatedSource = graphicsConfiguration.createCompatibleImage(sourceImage.getWidth(),
sourceImage.getHeight(), sourceImage.getColorModel().getTransparency());
Graphics2D g2d = image.createGraphics();
g2d.setComposite(AlphaComposite.Src);
// Generate the rotated images.
int sourceWidth = sourceImage.getWidth();
int sourceHeight = sourceImage.getHeight();
double angleBetweenFrames = 2 * Math.PI / numFrames;
int imageIndex = 0; // the current rotated image index
for (double a = 0; a < 2 * Math.PI; a += angleBetweenFrames)
{
Graphics2D rsG = rotatedSource.createGraphics();
rsG.rotate(a, rotatedSource.getWidth()/2, rotatedSource.getHeight()/2); // set rotation
rsG.drawImage(sourceImage, (rotatedSource.getWidth() - sourceWidth)/2, (rotatedSource.getHeight() - sourceHeight)/2, null);
g2d.drawImage(rotatedSource, imageIndex * sourceWidth, 0, null); // draw at specified coords
rsG.setComposite(AlphaComposite.Clear); // clear the image for use in the next iteration
rsG.fillRect(0, 0, rotatedSource.getWidth(), rotatedSource.getHeight());
rsG.dispose();
imageIndex++; // increment the image index
}
g2d.dispose();
return image;
}
- You would still get clipping when the square image is rotated and drawn onto a BufferedImage that is smaller than the size of the rotated image. Imagine a square image that is again rotated 45 degrees (to form a diamond shape) - the bounds of that rotated image is larger than the original, and when drawn onto a destination which is the same size as the square before rotation would result in clipping.
Workaround:
Add a bit of transparent buffer around your sprite image so that the sprite graphic you’re interested in doesn’t get clipped.
- You can also consider calling repaint() (as well as revalidate()) on your ImageCanvas whenever the frames are generated. Currently, for 1-4 frames of animation, the ImageCanvas is not updated to draw the generated image.