1

I am creating a cricle gradient using RadialGradientPaint, putting that on a BufferedImage and rendering the Image on top of my 2d game screen, creating a nice light-in-the-dark effect. I would, however, like to create more light sources, but creating and rendering a new BufferedImage for each light doesn't do the job (usually just the last light is seen, everything else is black). Is it possible to bake a few RadialGradientPaints into one BufferedImage or achieve the multiple lights effect in some other way?

Attached you can find the image of how one light looks like. It is a black BufferedImage with a RadialGradientPaint applied rendered on top of the screen. I would like to add more of these somehow.

Single light

Jack
  • 16,506
  • 19
  • 100
  • 167
Myzreal
  • 351
  • 4
  • 16
  • 1
    Add the masks from different light sources together, clip at [255] (not very realistic but it helps things), multiply by the map. Not sure how to do it in Slick, though. – John Dvorak Nov 18 '12 at 13:55
  • The only thing that slick does here is transform a BufferedImage into it's own Image class and call that Image's draw() function. So if you can provide me some example code on how to do that I would be able to render the output BufferedImage with slick somehow. – Myzreal Nov 18 '12 at 14:05
  • 1
    See [Java - Merging two images](http://stackoverflow.com/questions/2318020/merging-two-images). You should be able to paint several white-transparent gradients on a black canvas, convert from black-white to black-transparent and paint over the map. – John Dvorak Nov 18 '12 at 14:18
  • @JanDvorak Your hint works, however adding a new light always produces a small lag. I think it is connected with the BufferedImage -> Slick transformation. It makes it quite hard for me to make mobile lights :/ Is there any way to draw a BufferedImage on screen without a JComponent? Or maybe any other solution for baking mobile lights into an on-screen mask? I can't even make a thread to handle the transformation to avoid lag because Slick is basically openGL and that's single-threaded, won't allow me to do that in a thread other than the main thread. – Myzreal Nov 20 '12 at 13:51

2 Answers2

2

Solution to this problem is using this (as pointed in the comment by @JanDvorak : Merging two images

The exact code I use is this:

public static BufferedImage mergeImages2(BufferedImage base, Collection<Light> images) {
    BufferedImage output = new BufferedImage(base.getWidth(), base.getHeight(), BufferedImage.TYPE_INT_ARGB);

    Graphics2D g = output.createGraphics();
    g.drawImage(base, 0, 0, null);
    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 1.0f));
    for (Light l : images) {
        g.drawImage(l.LIGHT_IMAGE, l.x, l.y, null);
        l.LIGHT_IMAGE.flush();
    }
    g.dispose();
    output.flush();
    return output;
}

NOTE: This solves the problem but produces memory leaks, which I have described hoping for some help here: BufferedImage.createGraphics() memory leak

Community
  • 1
  • 1
Myzreal
  • 351
  • 4
  • 16
0

Another way to do that is to blend your image differently, with two pass. First pass, you just add mutliple radiant point on a Black rectangle, from White-Green-Transparency.

Then, in the same point, you dug your first image from step 1 with an XOR blending.

Result:

http://img11.imageshack.us/img11/7066/step3yr.png

The code:

public void creerLightMap(){
        lightMap = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = lightMap.createGraphics();
         g.setColor(Color.BLACK);
         g.fillRect(0, 0, this.getWidth(), this.getHeight());
         float radius = 100;
         //create color circle
         for(int i=0; i<lumiere.size(); i++){
            Point2D center = lumiere.get(i);
            float[] dist = {0.0f, 0.5f, 1.0f};
            Color[] colors = {new Color( 1.0f , 1.0f , 1.0f , 1.0f), new Color( 0.0f , 1.0f , 0.0f , 0.5f) , new Color( 0.0f , 1.0f , 0.0f , 0.0f)};
            RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
            g.setPaint(p);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
        }

         //add an alpha into theses same circle
         for(int i=0; i<lumiere.size(); i++){
            Point2D center = lumiere.get(i);
            float[] dist = {0.0f, 1.0f};
            Color[] colors = {new Color( 1.0f , 1.0f , 1.0f , 1.0f) , new Color( 1.0f , 1.0f , 1.0f , 0.0f)};
            RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, 1.0f));
            g.setPaint(p);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
         }
         g.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawImage(this.lightMap, 0, 0, null);
    }
Froll
  • 11
  • 1