Graphics2D clipping error


Exception in thread "main" java.lang.NullPointerException
        at java.awt.geom.Area.<init>(Area.java:54)
        at sun.java2d.SunGraphics2D.intersectByArea(SunGraphics2D.java:628)
        at sun.java2d.SunGraphics2D.intersectShapes(SunGraphics2D.java:553)
        at sun.java2d.SunGraphics2D.clip(SunGraphics2D.java:2004)
        at Tracker.drawClippedImage(Tracker.java:475)
        at Tracker.render(Tracker.java:58)
        at JavaTactics.main_loop(JavaTactics.java:855)
        at JavaTactics.main(JavaTactics.java:87)

and my drawClippedImage looks like this:


public void drawClippedImage(Graphics2D g, String sck, int Xpx, int Ypx, int mapY) { 
            g.clip(clips[mapY]);//THIS IS AN AREA
            g.drawImage(j.sc.getImage(sck), Xpx, Ypx, null);
            g.clip(null); 
      }

here are some screenshots of the clip images: (areas are just filled and rendered to the screen right now)

http://members.gamedev.net/hops/Pics/Java_Tactics_Java2D/screenshot_29.png

http://members.gamedev.net/hops/Pics/Java_Tactics_Java2D/screenshot_30.png

My only guess is that the areas (created by area.add(tile.area)) are having some problems with clipping. I can make a clip with a normal rectangle…

Any ideas?

umm… nevermind fixed it somehow… not sure how, but its working now!

you’re not accessing the graphics object from different threads, are you?

No. Instead I have some 3 rendering methods.
1: Do nothing,
2: ReRender the Actor Sprites
3: Render the Background image, and generate the clips

Then based on the return of my update() method run the the correct rendering…

Working great so far except one little problem: I can’t seem to make areas have exact pixel values without having antialiased edges. I think that it might be caused by the internal storarage of the coorinates being double…

I keep having the problem of not being able to get an area to cover by a per pixel basis. There are always antialiasing:

http://members.gamedev.net/hops/Pics/Java_Tactics_Java2D/screenshot_31.png

This is the basic tile:
http://members.gamedev.net/hops/Pics/Java_Tactics_Java2D/tile_grass_01.png

Any ideas on how to make it not blur those edges? I’ve tried using rendering hints to turn off antialiasing, but no difference…

I think that there is a way to dynamically gererate an area based on the transparency of a graphic with PixelGrabber… any help on how to change a BufferedImage to a area based on whether on not the pixels are transparent?

Thanks!

why do you need to set clips at all? Why can’t you just draw the tiles?

This is how I’m working it:
This is a Final Fantasy Tactics/Tactics Ogre clone. Tiles sit on top of blocks.
When you go to draw actors, they have to be behind any blocks that are in front of him.

So, I render everything in the Tile format, and make a new Area for every Y. Then, when I go to render a actor, I create a new area the size of the screen and subtract any areas that have a greater Y then the actors.

When I do that, I get a clipped area so that it appears that the acctor is behind the blocking tiles. This prevents me from having to render the entire image, and allows me to draw just the Actors.

With my current engine without clipping it looks like this:

http://members.gamedev.net/hops/Pics/Java_Tactics_Java2D/screenshot_22.png

that looks very nice. if you are able, i’d really like to have a look at the whole source… also, what’s the problem with the anti-aliasing? is it slow or is it making the edges look funny when in front of the actor?

Its making the edges look funny. I found out that it is caused by Java2D storing the polygon as floating point coordinates. To get around this I started using the Rectangle class, but this is taking to long… I really need a way to use PixelGrabber to create an Area based off of an image’s alpha channel.

Also, is there a way to translate an area?

Juddman: send me an email at: [backwards]moc.liamG AT snikpoh.m.ffej[/backwards] and I’ll email you the source…

well, I would not use PixelGrabber since it destroys performance more or less…

But I wouldn’t be using it every frame. Once I created the area at startup, I could just store it and translate it when needed.

Re: anti-aliasing…

Have you tried setting rendering hints to force OFF anti-aliasing and perhaps LOWER render quality (use SPEED hints instead of QUALITY hints).

Just a shot in the dark…

Yup, both. No success. :frowning:

Thanks though!

anti-aliasing rendering hints do nothing for images. Those only affect Strokes or Shapes being drawn. What you want for your image to retain its anti-aliased quality is to save them as png’s with full translucency. If the space around the isometric tile has a 0 for it’s alpha value, you should never have any need for setting Clips or using Areas because when you draw with the tile, it should only use its colored portion.

I know that when I display my tiles that the alpha is… well alpha. And I know that when drawing without using clipping that it works fine.

What I want to do is make it so that if I want to display an Actor behind a tile that I don’t have to rerender the entire map (I can’t use the standard dirty rect logic because there are layering issues).

So in order to redraw an actor to the background I need to clip out of the actor’s graphic where the tiles are that are over the character. For instance if the character is half visible behind a low wall, you don’t want to render the entire actor, just his top half.

I fixed the antaliasing issue by resorting to a bunch of Rectangles (because they store their coords in int). But the issue with this is that it takes too much cpu to clip with an Area of 20 rectangles per tile.

The solution to my problem would be able to make a pixel acurate Area from a given png.

how bout you buffer layers? Have a BufferedImage for a layer, re-draw the ones you need to, and don’t ever worry about Areas and Clips? Then your render loop looks like this:


for (int i = 0; i < topLayer; i++) {
      layers[i].render(g2d);
      for (int j = 0; j < characters.length; j++)
            if (characters[i].layer == i)
                  characters[i].render(g2d);
}

That would work, right? You could even enhance it to know more about which layers have changed and perhaps combine buffered layers if possible so that fewer have to draw.

I’ve tried that also, the problem again is that because it is isometric the layers are in diagonal lines, causing the BufferedImage for each layer to be the size of the window. This gets increasingly more taxing on the system because you can’t just redraw one of those layers, you have to draw every layer above the one you want to redraw.

Lets say that I have an actor on Y:3. And lets also say that the screen is big enough to handle 20 Y. This means that in order to redraw Y:3 you also have to redraw (to the screen, not the actual tiles) everything between 3 and 20.

I found it more taxing on the system to redraw 17 buffered Images then to just redraw the entire thing tile by tile, actor by actor.

With doing it by clipping and Areas I can make it so that a minimal amount of drawing is going on no matter the screen size. It would all be based on how many actors were being refreshed.

ahh I wasn’t talking about y layers, I was talking z layers, so like in ff tactics the most buffers you would ever have would be perhaps 5 layers. I don’t know why your image shows areas so tall… but hey, it’s your game :wink: If you want to make it this intricate perhaps you could just use a better rendering engine like LWJGL.

Instead of using clipping, how about draw a separate alpha channel based on the foreground/background separation. Then when you blit your player, change the compositing rule to use the alpha that you created.

E.g.: Assuming you only blit one pass to draw the terrain.

  • Clear the screen so the screens alpha is 0
  • Blit background objects with compositing rules that copy the alpha channel to the background image.
  • Blit foreground objects such that the background alpha is left at 0
  • Blit the player so it only shows through where the dest alpha is 1

I’m not certain the rules on AlphaComposite cover all the needed cases… but it might be an approach that works out.

[quote]Instead of using clipping, how about draw a separate alpha channel based on the foreground/background separation.
[/quote]
The problem comes with actually generating the alpha channels… if I could generate seperate alpha channels I could just apply the clippings this way also…

Okay, I have a quick question that might solve all of this…

I have an object called a Sprite_Cache. His job is to store all the graphics as Images and provide keys in String format. In order to store these Images he uses a HashMap, and put()s the image in there…

This way when I want the Sprite named “Actor_001_d_1” I just go:
Image AnImage = (Image)sprites.get(“Actor_001_d_1”); Is this accelerated? Because I store my tiles in there, and for every tile being drawn it gets its image this way…