Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (581)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Alpha / Additive blending with Composide and Graphics2D  (Read 3579 times)
0 Members and 1 Guest are viewing this topic.
Offline Dreamcatchermatt

Junior Member





« Posted 2010-05-24 04:59:48 »

My current project uses Graphics2D for rendering.

I've been thinking about how to add Additive blending to this, and after some reading up around the internets it seems this is not possible.

I've read the java doc's for AlphaComposite, and I'm thinking that it would be possible with some maths and bashing my head against the keyboard to create a new AdditiveComposite class that can be used in much the same way for blending additively with Graphics2D.

On top of this, it would be possible to create any type of blending required (I'm thinking Photoshop - such as Overlay and Liniar Burn, etc.

I wanted to have a discussion on this topic, to see if this has been done before, found to be impossible or if theres a better way to go about this.

A caveat would be that any blending would have to be used in a Update/Render game loop, and therefor be as fast as possible.

So, any thoughts?

EDIT: Ohh yeh, my current project is to create a game engine from scratch, mainly as a learning experience, and also becasue I would like to have an end-product that I fully understand the inner workings of. I'd rather go the long way with this rather than 'Go use XYZ Library, as it will do everything you need.'  Grin
Offline JuddMan

Senior Member


Medals: 1


Your Ad Here


« Reply #1 - Posted 2010-06-05 12:22:46 »

It is quite possible, but i dont think it'd be accellerated.

This post got me interested, and i hacked up a bit of a test.
It's not very fast, and I just guessed the math, so can't guarantee that it's fully correct.

AdditiveComposite.java:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
import java.awt.*;
import java.awt.image.*;
public class AdditiveComposite implements Composite
{
  public AdditiveComposite()
  {
    super();
  }
  public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints)
  {
    return new AdditiveCompositeContext();
  }
}


AdditiveCompositeContext.java:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
import java.awt.*;
import java.awt.image.*;

public class AdditiveCompositeContext implements CompositeContext
{
  public AdditiveCompositeContext(){};
  public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
  {
    int w1    = src.getWidth();
    int h1    = src.getHeight();
    int chan1 = src.getNumBands();
    int w2    = dstIn.getWidth();
    int h2    = dstIn.getHeight();
    int chan2 = dstIn.getNumBands();
   
    int minw  = Math.min(w1, w2);
    int minh  = Math.min(h1, h2);
    int minCh = Math.min(chan1, chan2);
   
    //This bit is horribly inefficient,
   //getting individual pixels rather than all at once.
   for(int x = 0; x < dstIn.getWidth(); x++) {
      for(int y = 0; y < dstIn.getHeight(); y++) {
        float[] pxSrc = null;
        pxSrc = src.getPixel(x, y, pxSrc);
        float[] pxDst = null;
        pxDst = dstIn.getPixel(x, y, pxDst);
       
        float alpha = 255;
        if(pxSrc.length > 3) {
          alpha = pxSrc[3];
        }
       
        for(int i = 0; i < 3 && i < minCh; i++) {
          pxDst[i] = Math.min(255, (pxSrc[i] * (alpha / 255)) + (pxDst[i]));
          dstOut.setPixel(x, y, pxDst);
        }
      }
    }
  }
 
  public void dispose(){}
}



Prog.java sets up a simple JFrame with a custom JPanel that draws wandering spotlights:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
import java.awt.*;
import javax.swing.*;
import java.awt.image.*;

public class Prog
{
  public static void main(String[] a) {
    JFrame frame = new JFrame();
    MyPanel cp = new MyPanel();
   
    frame.setContentPane(cp);
    frame.setSize(400, 400);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
    while(true) {
      cp.moveSpots();
      frame.repaint();
      try {
        Thread.sleep(50);
      } catch(Exception e) {
        break;
      }
    }
  }
}

class Spotlight {
  float x, y, vx, vy;
  int w, h;
  Color c;
 
  static Composite acomp = new AdditiveComposite();
 
  public Spotlight(Color colour, int xStart, int yStart, int width, int height)
  {
    c = colour;
    x = xStart;
    y = yStart;
    w = width;
    h = height;
  }
 
  public void paint(Graphics2D g) {
    Composite oldComp = g.getComposite();
    g.setComposite(acomp);   //comment out this line to see the difference
   g.setColor(c);
    g.fillOval((int)x+0, (int)y+0, w-10, h-10);
  }
 
  public void moveRandom(int minX, int minY, int maxX, int maxY) {
   
    vx += 8 * (Math.random() * 0.2 - 0.1);
    vy += 8 * (Math.random() * 0.2 - 0.1);
   
    vx *= 0.98;
    vy *= 0.98;
   
    if(x > maxX - w) {
      vx = vx < 0 ? vx : -vx;
    }
    if(x < minX) {
      vx = vx > 0 ? vx : -vx;
    }
    if(y > maxY - h) {
      vy = vy < 0 ? vy : -vy;
    }
    if(y < minY) {
      vy = vy > 0 ? vy : -vy;
    }
   
    x += vx;
    y += vy;
   
  }
}

class MyPanel extends JPanel {
  Spotlight[] spots = null;
 
  public MyPanel() {
    spots = new Spotlight[6];
    spots[0] = new Spotlight(new Color(255, 0, 0, 128), 200, 0,   200, 200);
    spots[1] = new Spotlight(new Color(0, 255, 0, 128), 100, 200, 200, 200);
    spots[2] = new Spotlight(new Color(0, 0, 255, 128), 0,   0,   200, 200);
    spots[3] = new Spotlight(new Color(255, 0, 0, 128), 200, 0,   200, 200);
    spots[4] = new Spotlight(new Color(0, 255, 0, 128), 100, 200, 200, 200);
    spots[5] = new Spotlight(new Color(0, 0, 255, 128), 0,   0,   200, 200);
  }
 
  public void moveSpots() {
    if(spots == null) return;
    for(int i = 0; i < 6; i++) {
      if(spots[i] != null) {
        spots[i].moveRandom(0, 0, this.getWidth(), this.getHeight());
      } else {
        break;
      }
    }
  }
 
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;
   
    g.setColor(Color.black);
    g.fillRect(0, 0, this.getWidth(), this.getHeight());
   
    for(int i = 0; i < 6; i++) {
      if(spots[i] != null) {
        spots[i].paint(g2);
      } else {
        break;
      }
    }
  }
}


The graphics code seems pretty smart about providing the compose() function with only the area of interest, so i think if you use it for limited small effects, it might run OK.

I noticed that my compose() function was being given 64x64 tiles, rather than all the image at once. There's mention in the API of multithreading, but the result doesn't appear to use it.


Digging down into the java source code, i found their alphacomposite creates BufferedImages from the rasters, then calls a native function called Blit. I didn't look deeper than a quick glance at that file, didn't really understand it. There seems to be a ton of boilerplate in Java.
Online CommanderKeith
« Reply #2 - Posted 2010-06-21 17:40:22 »

Nice demo, works great - when all spotlights are on the same point it turns white.

There is a hw-accelerated API for this in project scenegraph (http://weblogs.java.net/blog/2008/02/01/effectuation-intro) but it seems to have been eaten by the JavaFX mess, but I know it is usable from plain old java and java2D.


Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Dreamcatchermatt

Junior Member





« Reply #3 - Posted 2010-07-20 20:17:50 »

Ahh, I see... interesting.

I've used a similar process in C# for applying things like edge-finding to CCTV images, but found it to be very slow. Then again, that was quite a heavy calculation per pixel, rather than just adding color values.

I'm not sure now the Composite/CompositeContext works - does it run in software, or instruct the graphics hardware to use that calculation? If this is handled at a pixel level in java, it would be very slow to execute in low-end systems right?

Sorry for not replying sooner,

Cheers,
Matt
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #4 - Posted 2010-07-21 10:57:58 »

Careful with AlphaComposite - you can't create and use custom AlphaComposites in the security sandbox (ie. applets), so you may find it better to just do the math on a BufferedImage / Raster directly.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (60 views)
2014-04-15 18:08:23

BurntPizza (58 views)
2014-04-15 03:46:01

UprightPath (71 views)
2014-04-14 17:39:50

UprightPath (54 views)
2014-04-14 17:35:47

Porlus (71 views)
2014-04-14 15:48:38

tom_mai78101 (97 views)
2014-04-10 04:04:31

BurntPizza (157 views)
2014-04-08 23:06:04

tom_mai78101 (252 views)
2014-04-05 13:34:39

trollwarrior1 (207 views)
2014-04-04 12:06:45

CJLetsGame (214 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!