Search code examples
javarenderinggame-enginebufferedimagerectangles

Rendering section of a BufferedImage within a Rectangle


I am currently trying to draw just a section of a BufferedImage that is within the bounds of a Rectangle on the fly. The image gets moved, and thus the size of the image in the rectangle changes.

Visual depiction:

enter image description here

Currently, this is what I have and it works great with a low res image. But if I scale the minimap up, this becomes very inefficient and causes lag

private BufferedImage extractPixels() {
    int[] imagePixels = new int[scaledImage.getWidth() * scaledImage.getHeight()];
    scaledImage.getRGB(0, 0, scaledImage.getWidth(), scaledImage.getHeight(), imagePixels,
            0, scaledImage.getWidth());
    int maxX = 0, maxY = 0;
    boolean first = false;
    for (int y = 0; y < scaledImage.getHeight(); y++) {
        for (int x = 0; x < scaledImage.getWidth(); x++) {
            int px = (int)(this.x + x);
            int py = (int)(this.y + y);
            if (viewingArea.contains(px, py)) {
                if (x > maxX) maxX = x;
                if (y > maxY) maxY = y;
                if (!first) {
                    imageX = x;
                    imageY = y;
                    first = true;
                }
            }
        }
    }
    int xCount = maxX - imageX;
    int yCount = maxY - imageY;
    if (imageX < 0 || imageX > scaledImage.getWidth() || imageX + xCount > scaledImage.getWidth()) return null;
    if (imageY < 0 || imageY > scaledImage.getHeight() || imageY + yCount > scaledImage.getHeight()) return null;
    return scaledImage.getSubimage(imageX, imageY, xCount, yCount);
}

In Render loop:

public void Render(PixelRenderer renderer) {
    BufferedImage image = extractPixels();
    if (image != null) renderer.renderImage(image, x + imageX, y + imageY);
}

Is there a way to do this more efficiently, so that re-scaling has less of an effect on performance?


Solution

  • Fixed by calculating where the image should subimage from, and the size of the subimage dependent on the position of the main image.

    private BufferedImage extractPixels() {
        double xp = viewingArea.x - this.x;
        double yp = viewingArea.y - this.y;
        double iw = viewingArea.width;
        double ih = viewingArea.height;
    
        int rightBound = scaledImage.getWidth() - viewingArea.width;
        int bottomBound = scaledImage.getHeight() - viewingArea.height;
    
        if (xp < 0) {
            xp = 0;
            iw = viewingArea.width - (this.x - viewingArea.x);
            imageX = viewingArea.x + (viewingArea.width - (int)iw);
        } else if (xp >= 0 && xp < rightBound) {
            xp -= dx;
            iw -= dx;
            imageX = viewingArea.x;
        }
        if (xp >= rightBound) {
            iw = viewingArea.width - ((int)xp - (scaledImage.getWidth() - viewingArea.width));
            imageX = viewingArea.x;
        }
    
        if (yp < 0) {
            yp = 0;
            ih = viewingArea.height - (this.y - viewingArea.y);
            imageY = viewingArea.x + (viewingArea.height - (int)ih);
        } else if (yp >= 0 && yp < bottomBound) {
            yp -= dy;
            ih -= dy;
            imageY = viewingArea.y;
        }
        if (yp >= bottomBound) {
            ih = viewingArea.height - ((int)yp - (scaledImage.getHeight() - viewingArea.height));
            imageY = viewingArea.y;
        }
    
        if (iw < 0) iw = Math.abs(iw);
        if (ih < 0) ih = Math.abs(ih);
        if (xp < 0) xp = Math.abs(xp);
        if (yp < 0) yp = Math.abs(yp);
    
        BufferedImage result = new BufferedImage((int)iw, (int)ih, BufferedImage.TYPE_INT_RGB);
    
        try {
            result = scaledImage.getSubimage((int)xp, (int)yp, (int)iw, (int)ih);
        } catch (Exception e) {
            //TODO: Log to game engine something bad has happened
            e.printStackTrace();
        }
    
        return result;
    }