Java Forum / First Aid / August 2005
Drawing translucent masks
Andreas Koch - 20 Jul 2005 21:33 GMT Hi all,
i am a absolute java beginner, so please forgive my errors :-)
I have a little working app that basically does the following :
1. Load a lot of ImageIcons 2. Create a BufferedImage
Loop 3. Draw all those ImageIcons on the BufferedImage's Graphics2D 4. Draw the BufferedImage on the paintComponents Graphics. /loop
This displays some sprites running over a scrolling map.
Now i'd like to add "light". A (variable sized) circular area around the sprites should be visible, at higher distances the map should become black.
I basically plan to create a second BufferedImage, consisting of a solid rectangle with a transparent hole:
lightmap = (BufferedImage)(this.createImage(w, h));
Graphics gi = lightmap.getGraphics();
gi.setColor(new Color(0,0,0)); gi.fillRect(0,0,gameImage.getWidth(),gameImage.getHeight()); gi.setColor(new Color(255,255,255)); gi.fillOval(0,0,100,100); ... gc.drawImage(lightmap,0,0,null);
This works perfectly for creating a white hole, unfortunately i have no idea how to create a transparent hole instead.
Googling didn't reveal anything usefull, mostly problems on loading PNGs and GIFs. I can't just load an image because there is an infinite amount of possible light sizes.
From windows programming i'd say, i have to "AND" the lightmap and the target, but how?
Extra gimmick : Binary transparency would be ok, but gradual translucency (perhaps even per channel, to get for example warm red light for a fire) would be better :-)
Any suggestions? Using Java 1.5.0_03.
thanks, Andreas
Andrew Thompson - 20 Jul 2005 22:26 GMT > lightmap = (BufferedImage)(this.createImage(w, h)); > [quoted text clipped - 3 lines] > gi.fillRect(0,0,gameImage.getWidth(),gameImage.getHeight()); > gi.setColor(new Color(255,255,255)); gi.setColor(new Color(255,255,255, 50 ));
> gi.fillOval(0,0,100,100); > ... [quoted text clipped - 3 lines] > unfortunately i have no idea how to create a transparent hole > instead. Try that..
HTH
 Signature Andrew Thompson physci.org 1point1c.org javasaver.com lensescapes.com athompson.info Now Interactive! Joystick Controls Fry's Left Ear.
Andreas Koch - 21 Jul 2005 17:50 GMT >> lightmap = (BufferedImage)(this.createImage(w, h)); >> Graphics gi = lightmap.getGraphics(); [quoted text clipped - 8 lines] >> gc.drawImage(Fullmap,0,0,null); >> gc.drawImage(lightmap,0,0,null); Thanks! Well, particular success. I perhaps should have added, that i draw the full picture first on gc, and then try to reduce visibility by drawing the lightmap above it.
This draws a 50% translucent white oval on the black rectangle. Unfortunately, gc.drawImage(lightmap doesn't seem to use the transparency, so all i get when drawing the lightmap on the level is a black rectangle witha grey oval ...
So, how to do a Graphics2D.drawImage(BufferedImage) with a BufferedImage that contains translucency (assuming that the fillOval created translucent pixels, not just gray)?
thanks a lot, Andreas
Andrew Thompson - 21 Jul 2005 18:01 GMT > Thanks! No worries..
> Well, particular success. I perhaps should have added, .. An SSCCE? <http://www.physci.org/codes/sscce.jsp>
 Signature Andrew Thompson physci.org 1point1c.org javasaver.com lensescapes.com athompson.info Mr Bender's Wardrobe By ROBOTANY 500
Andreas Koch - 21 Jul 2005 19:21 GMT >>Well, particular success. I perhaps should have added, .. > An SSCCE? <http://www.physci.org/codes/sscce.jsp> Ok. I'm not experienced enough to make that shorter than 86 lines. I ommited the lines that create the JFrame instance.
---- Start code ---- package peti; import javax.swing.JFrame; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.swing.*;
public class TMainWindow extends JFrame { static final long serialVersionUID = 422323L; game gameFace; public static void main(String[] args) { JFrame windo = new TMainWindow(); windo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); windo.setVisible(true); }//end main public TMainWindow() { Container content = this.getContentPane(); content.setLayout(new BorderLayout()); gameFace = new game(); content.add(gameFace, BorderLayout.CENTER); this.pack(); gameFace.start(); }//end constructor }//end class gameAnalogBuf class game extends JPanel { static final long serialVersionUID = 422324L; private static Image[] TileGfx; private BufferedImage gameImage,lightmap; private javax.swing.Timer t; private Graphics2D gc; public game() { this.setPreferredSize(new Dimension(694,612)); this.setBackground(Color.white); this.setForeground(Color.black); t = new javax.swing.Timer(10, new ActionListener() { public void actionPerformed(ActionEvent e) { update(); } }); TileGfx = new Image[1]; ClassLoader loader = this.getClass().getClassLoader(); // load a floor tile 32 x 32 pixelsj TileGfx[0] = new ImageIcon(loader.getResource("peti/images/0196.png")).getImage(); }//end constructor public void update() { this.repaint(); }//end update public void start() { t.start(); }//end start public void stop() { t.stop(); }//end stop public void paintComponent(Graphics g) { super.paintComponent(g); // paint background, borders Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int w = getWidth(); int h = getHeight(); if (gameImage == null || gameImage.getWidth() != w || gameImage.getHeight() != h) { gameImage = (BufferedImage)(this.createImage(w, h)); } if (gc == null) { gc = gameImage.createGraphics(); gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); lightmap = (BufferedImage)(this.createImage(w, h)); Graphics gi = lightmap.getGraphics(); gi.setColor(new Color(0,0,0)); gi.fillRect(0,0,gameImage.getWidth(),gameImage.getHeight()); gi.setColor(new Color(255,255,255,90)); gi.fillOval(0,0,100,100); } int x,y,ofs; for (x=0;x<15;x++) // draw tiles for (y=0;y<12;y++) gc.drawImage(TileGfx[0],18+x*32,8+(y*32),32,32,null); //gc.drawImage(lightmap,0,0,null); // mask with lightmap g2.drawImage(gameImage, null, 0, 0); // show result }//end paintComponent }//endclass game
--- end code --- This will show a map of 15*12 tiles (whatever 32x32 pixel 0196.png you provided).
If i uncomment the
//gc.drawImage(lightmap,0,0,null); // mask with lightmap
line,
it shows a black rectangle with a gray circle instead. What i want: A gray circle filled with tiles, everything out of that circle, black:
+--+--+--+
| | | | +--+--+--+
| | | | +--+--+--+
| | | | +--+--+--+
plus
########## ### ##### ## #### # ### # ### ## #### ### #####
should become
########## ###| ##### ##-+--#### # | |### #--+--+### ## | #### ###+-#####
Hope this makes things clear enough :-)
Any ideas, now?
thanks, Andreas
Knute Johnson - 22 Jul 2005 16:35 GMT >>> Well, particular success. I perhaps should have added, .. >> [quoted text clipped - 141 lines] > thanks, > Andreas Andreas:
Sorry I didn't look carefully at your post sooner. Here is a simple solution to what you want to do. Draw your background color, set the clip region to a Shape (ellipse in this case), and draw your image. The Grahpics2D classes have hundreds of very interesting methods for doing just this sort of work.
import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.*; import java.io.*; import javax.imageio.*;
public class test8 extends Canvas { BufferedImage image;
public test8() { try { image = ImageIO.read(new File("someimage.jpg")); setPreferredSize(new Dimension(image.getWidth(), image.getHeight())); } catch (IOException ioe) { System.out.println(ioe); System.exit(0); } }
public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.BLACK); g2d.fillRect(0,0,getWidth(),getHeight()); g2d.clip(new Ellipse2D.Double(200.0,100.0,200.0,200.0)); g2d.drawImage(image,0,0,this); }
public static void main(String[] args) { Frame f = new Frame(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } }); test8 t8 = new test8(); f.add(t8,BorderLayout.CENTER); f.pack(); f.setVisible(true); } }
 Signature Knute Johnson email s/nospam/knute/
Andreas Koch - 24 Jul 2005 10:09 GMT Hi Knute,
thanks a lot for that example. This allows a first minimalistic way to solve the issue.
Problems i still have:
1) The real game will have many light sources (circles) I could draw them all by setting the clipping ellipse (via SetClip) for each light source, draw the map through it, repeat. I expect this to be pretty slow, and i want the game to be usable on slow computers.
2) I could probably use Area-clipping for doing all circles at once instead, but i found now way to add Ellipse2D's to Area's.
3) While clipping is better than nothing, anything that would allow me translucency (e.g. soft borders) or perhaps colored translucency (for differenct light colors) would look much better :-) Is there ANY way of doing this? Can i (do i have to...) access the images at byte level and manually do the calculations?
thanks, Andreas
Knute Johnson - 24 Jul 2005 16:54 GMT > Hi Knute, > [quoted text clipped - 8 lines] > it, repeat. I expect this to be pretty slow, and i want > the game to be usable on slow computers. It really depends on how many you want to draw and how fast. Do you need to redraw all of the circles every time?
> 2) I could probably use Area-clipping for doing all > circles at once instead, but i found now way to add > Ellipse2D's to Area's. I don't think there is a way to do that.
> 3) While clipping is better than nothing, anything that > would allow me translucency (e.g. soft borders) or perhaps > colored translucency (for differenct light colors) would > look much better :-) Is there ANY way of doing this? > Can i (do i have to...) access the images at byte level > and manually do the calculations? public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.BLACK); g2d.fillRect(0,0,getWidth(),getHeight()); g2d.clip(new Ellipse2D.Double(200.0,100.0,200.0,200.0)); g2d.drawImage(image,0,0,this); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,.5f)); g2d.setColor(Color.RED); g2d.fillRect(0,0,getWidth(),getHeight()); }
This adds a red overlay to the image. You could also draw a color underneath and AlphaComposite the drawing of the image.
> thanks, > Andreas
 Signature Knute Johnson email s/nospam/knute/
Andreas Koch - 24 Jul 2005 17:40 GMT Hi Knute,
>> 1) The real game will have many light sources (circles) >> I could draw them all by setting the clipping ellipse [quoted text clipped - 4 lines] > It really depends on how many you want to draw and how fast. Do you > need to redraw all of the circles every time? I will have a map (of which a part will be visible inside the light circles) which i want to update as fast as possible, at least 20 times per second.
Then i have the lightmap which specifies which parts of the map are visible and which parts have to be "clipped". That would only have to change when a light moves (which could be between once every map update or never, depending on what game objects are moving...)
With my simple, scrolling, unmasked map i get ~100 fps. Oh, just did a little testing. The performance hit is measureable, but not as bad as i expected:
100x100 ellipses fps 1 99 2 99 3 99 4 99 5 91 (! nice jump...) 10 69 20 45 50 23 100 13
> public void paint(Graphics g) { > Graphics2D g2d = (Graphics2D)g; [quoted text clipped - 10 lines] > This adds a red overlay to the image. You could also draw a color > underneath and AlphaComposite the drawing of the image. Ahhh, that looks nice... BUT drops my framerate for a single 100x100 light from 100 fps to 53 fps (33 fps for 5 lights)
Plus, to get "soft" borders i would have to draw multiple ellipses per light source :-/
Knute Johnson - 24 Jul 2005 18:49 GMT > Hi Knute, > [quoted text clipped - 53 lines] > Plus, to get "soft" borders i would have to draw multiple ellipses > per light source :-/ You can increase the speed of some of this by using VolatileImages. If you want a fuzzy border, create an image to use as your overlay with varying alpha and draw that on top instead of the fillRect. Don't repaint what you don't absolutely have to repaint.
 Signature Knute Johnson email s/nospam/knute/
Sathish Kumar Raju - 01 Aug 2005 10:22 GMT Hi All, Iam new to this group and i know only basic fundas of Java. Iam writing an java applet which connects to the database and retrieves data. It runs when iam running from jdeveloper ..but when run thru a browser it is giving the following exception.
java.security.AccessControlException: access denied (java.net.SocketPermission ab123x1.us.xyz.com resolve)
And also Iam using File IO...i hope it will also won't work since there is security issues..and the file is in the CLIENT side..
Please help me in this issue.
thnx, Sathish
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|