How can I create a Rectangle with a blend mode using a Graphics2D object in Java?

Ben Myers :

I am attempting to create a day/night cycle in a simple RPG-style game with Java. I have reached a point where I have included a low-alpha color overlay will change hue over time to simulate this:

// Render the overlay rectangle.
public void render(Graphics2D g) {

    // Set the color to yellow with ~50% opacity. 
    g.setColor(new Color(255, 255, 0, 125));

    // Draw the rectangle.
    g.fillRect(0, 0, handler.getWidth(), handler.getHeight());

    g.dispose();
}

While this works, I would like to introduce blending modes (i.e. add, subtract, screen, soft light) into my code to increase the day/night cycle's realism.

Here's what I have tried, but to no avail:

My desired code is something similar to what follows, but I will take what I can get.

public void render(Graphics2D g) {

    g.setColor(new Color(255, 255, 0, 125));

    g.setBlendMode(ADD);

    g.fillRect(0, 0, handler.getWidth(), handler.getHeight());

    g.dispose();

}
QuantumDeveloper :

One possibility to solve this would be to buffer your screen in a BufferedImage and then implement your own drawing methods(This definitely isn't a fast way to do this as it throws away all hardware-acceleration. If you need to render a big screen this can be laggy depending on your system and your implementation.):

class MyGraphics {
    public enum BlendingMode {
        NORMAL, ADD, …
    }
    public BufferedImage buffer;
    private BlendingMode bm = BlendingMode.NORMAL;
    private int color = 0;
    public MyGraphics(BufferedImage buf) {
        buffer = buf; // Initialize it with a bufferedImage of your panel size.
    }
    public void setBlendMode(BlendingMode b) {
        bm = b;
    }
    private int applyBlendingMode(int imgColor1, int newColor) {
        int rImg, rNew, gImg, gNew, bImg, bNew, alphaImg, alphaNew; // You can intialize those using bitshifts from the color integers.
        switch(bm) {
            // Implement all your blending modes here.
        }
        // And don't forget to return the result!
    }
    public void setColor(int c) {
        color = c;
    }
    public void fillRect(int x0, int y0, int width, int height) {
        for(int x = x0; x < x0+width; x++) {
            for(int y = y0; y < y0+height; y++) {
                buffer.setRGB(x, y, applyBlendingMode(buffer.getRGB(x, y), color));
            }
        }
    }
}

If the setRGB and getRGB are working to slow for you, you might speed it up by working directly on the BufferedImage's data array(see here for further info).

Also keep in mind, that if you want to use normal blending mode, you can still do it the normal way using buffer.getGraphics() to get your Graphics object. This should be faster in most cases.

After you are done with implementing your blending-modes and maybe some further functionality to draw more then a rectangle you can just simply draw the underlying BufferedImage on your screen using Graphics.drawImage(buffer, 0, 0);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=370689&siteId=1