Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » java - additive color blender

Credits go to Archon and Hard Rock for helping out!
This thread is locked; no one can reply to it. rss feed Print
java - additive color blender
Matthew Leverton
Supreme Loser
January 1999
avatar

I have to give a presentation for a Java class, and I'm thinking about changing my topic last minute since somebody else who goes before me decided to speak on the same topic I chose.

A long time ago I ported Shawn's SPEED game to a Java applet. I didn't really know much about Java then (and I still don't :P) so it was quite basic. Now I'm thinking about updating its graphics to be on par with the Allegro version.

The problem is I don't know how to do anything other than solid color drawing. I'm looking for a simple way to essentially duplicate this Allegro functionality (additive color blending), preferably just using regular Graphics2D in a JPanel:

1/* 24 bit additive color blender */
2static unsigned long add_blender24(unsigned long x, unsigned long y, unsigned long n)
3{
4 int r = getr24(x) + getr24(y);
5 int g = getg24(x) + getg24(y);
6 int b = getb24(x) + getb24(y);
7 
8 r = MIN(r, 255);
9 g = MIN(g, 255);
10 b = MIN(b, 255);
11 
12 return makecol24(r, g, b);
13}
14 
15set_blender_mode(add_blender15, add_blender16, add_blender24, 0, 0, 0, 0);
16 
17drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);

E.g., the green grid lines are RGB(0,51,0), so when they intersect, they should be RGB(0,102,0).

Hard Rock
Member #1,547
September 2001
avatar

You'll want to be using AlphaComposite to do the effects. I'm not sure if it does everything Allegro does out of the box, but a quick google finds this library:

http://www.jroller.com/gfx/entry/new_blendings_modes_for_java2d

Which will do all the allegro blending modes. As a bonus it works exactly like AlphaComposite, so you just do

1 // Cast to Graphics2D so we can set composite information.
2 Graphics2D g2d = (Graphics2D)g;
3 
4 // Save the original composite.
5 Composite oldComp = g2d.getComposite();
6 
7 // Create an AlphaComposite with 50% translucency.
8 Composite alphaComp = AlphaComposite.getInstance(
9 AlphaComposite.SRC_OVER, 0.5f);
10 
11 // Set the composite on the Graphics2D object.
12 g2d.setComposite(alphaComp);
13 
14 // Invoke arbitrary paint methods, which will paint
15 // with 50% translucency.
16 g2d.somePaintMethods();
17 
18 // Restore the old composite.
19 g2d.setComposite(oldComp);

(credit to above code from: http://java.sun.com/products/jfc/tsc/articles/swing2d/index.html)

But replace alphacomposite with blendcomposite from the link I gave earlier and specify your blending mode. (It's BSD so no license issues).

May be a bit slow, but since you're just drawing lines it should run just fine.

[edit]
The link I sent you has an app so you can test all the modes supported by Java out of the box, and decide whether you need the extra library support. The library also has a sample app which does the same.

_________________________________________________
Hard Rock
[ Stars Dev Company ][ Twitter ][Global Warming: ARA My TINS 07 Entry][Pong Ultra Website][GifAllegS Ver 1.07]
"Well there's also coolwebsearch but we'll let that be an IE exclusive feature" - arielb on the New Browser Plugins "What's better, HTML or Variables?"

Matthew Leverton
Supreme Loser
January 1999
avatar

I trimmed down the example to just:

1class BlendComposite implements Composite
2{
3 public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
4 return new BlendingContext(this);
5 }
6}
7 
8class BlendingContext implements CompositeContext
9{
10 Composite composite;
11
12 public BlendingContext(BlendComposite composite)
13 {
14 this.composite = composite;
15 }
16
17 public int[] blend(int[] src, int[] dst) {
18 return new int[] {
19 Math.min(255, src[0] + dst[0]),
20 Math.min(255, src[1] + dst[1]),
21 Math.min(255, src[2] + dst[2]),
22 Math.min(255, src[3] + dst[3])
23 };
24 }
25
26 public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
27 {
28 if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
29 dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
30 dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
31 throw new IllegalStateException(
32 "Source and destination must store pixels as INT.");
33 }
34 
35 int width = Math.min(src.getWidth(), dstIn.getWidth());
36 int height = Math.min(src.getHeight(), dstIn.getHeight());
37 
38 float alpha = 1.0f; // composite.getAlpha();
39 
40 int[] srcPixel = new int[4];
41 int[] dstPixel = new int[4];
42 int[] srcPixels = new int[width];
43 int[] dstPixels = new int[width];
44 
45 for (int y = 0; y < height; y++) {
46 src.getDataElements(0, y, width, 1, srcPixels);
47 dstIn.getDataElements(0, y, width, 1, dstPixels);
48 for (int x = 0; x < width; x++) {
49 // pixels are stored as INT_ARGB
50 // our arrays are [R, G, B, A]
51 int pixel = srcPixels[x];
52 srcPixel[0] = (pixel >> 16) & 0xFF;
53 srcPixel[1] = (pixel >> 8) & 0xFF;
54 srcPixel[2] = (pixel ) & 0xFF;
55 srcPixel[3] = (pixel >> 24) & 0xFF;
56 
57 pixel = dstPixels[x];
58 dstPixel[0] = (pixel >> 16) & 0xFF;
59 dstPixel[1] = (pixel >> 8) & 0xFF;
60 dstPixel[2] = (pixel ) & 0xFF;
61 dstPixel[3] = (pixel >> 24) & 0xFF;
62 
63 int[] result = blend(srcPixel, dstPixel);
64 
65 // mixes the result with the opacity
66 dstPixels[x] = ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
67 ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 |
68 ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 |
69 (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;
70 }
71 dstOut.setDataElements(0, y, width, 1, dstPixels);
72 }
73 }
74
75 public void dispose()
76 {
77 }
78}

So basically:

g.setComposite(new BlendComposite());

And my additive blending works as expected. But there's one big problem. It's horribly slow. :(

Just drawing a few lines is enough to bring it crawling to its knees. Is it because I'm drawing straight to a JPanel? I thought those were double buffered automatically. I can make the above code more efficient, but I don't want to be going down a dead end lane...

Update:

I switched to drawing to a BufferedImage and it's much faster now. Hopefully it's fast enough to get 30fps.

Archon
Member #4,195
January 2004
avatar

Quote:

Just drawing a few lines is enough to bring it crawling to its knees. Is it because I'm drawing straight to a JPanel? I thought those were double buffered automatically.

In my drawing applet, I draw to a BufferedImage object and in the paint method, I draw that BufferedImage to the JPanel. It runs fine.

Quote:

I switched to drawing to a BufferedImage and it's much faster now. Hopefully it's fast enough to get 30fps.

I wrote the above before I read this quote ::)

Matthew Leverton
Supreme Loser
January 1999
avatar

I've got four simultaneously displayed projections (just the grids) being drawn via the additive blender and it is running fast enough for demonstration purposes.

The bad guys might slow it down some since they are filled polygons, but I can just limit their numbers if it is a problem.

Go to: