Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (497)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  clip an image  (Read 8004 times)
0 Members and 1 Guest are viewing this topic.
Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Posted 2006-05-18 17:51:26 »

Lets say I am doing all of my drawing to a graphics contect g, If I wish to draw a portion of an image I do the following:
1  
2  
3  
4  
5  
g.setClip(0,0,someWidth, someHeight);
g.drawImage(someImage, x,y, this);
g.setClip(0,0,screenWidth, screenHeight);
 
//continue normal draw operations here


This is how I currently acheive this, but was wondering why is there not a g.drawImage(image, x,y, clipping area, this) method, or is there?

Kommi
Offline woogley
« Reply #1 - Posted 2006-05-18 17:54:04 »

there is: here

or, you can just create a permanent version of your clip with BufferedImage's getSubimage method
Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Reply #2 - Posted 2006-05-18 19:01:15 »

I looked at that, but all the drawImage methods seem to scale the image. A I missing something? Does one of the drawImage draws only a clipped portion of my Image? Which one is it?

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

Senior Member


Projects: 5
Exp: 15 years


2D Java games forever!


« Reply #3 - Posted 2006-05-18 19:33:07 »

Hi,
  You are trying to draw only the part of the image from (in image coords)
(0,0) to (someWidth -x , someHeight - y)

   You can use the method that woogley said.

1  
g.drawImage(someImage,x,y,someWidth, someHeight, 0,0,someWidth-x, someHeight-y,this);


  If the area of the destination rectangle is equal to the source rectangle, there is no scaling.
 
   Rafael.-

Offline woogley
« Reply #4 - Posted 2006-05-18 19:39:19 »

other than the clipping methods you're using with setClip and the drawImage method, the only other way to achieve the same effect is to use the getSubimage method in BufferedImage, which just crops the image.

I wrote an example of that here

however, it is best to use the clipping methods inside the Graphics2D class, since it allows you to clip any Shape rather than just silly rectangle Wink

in fact, a few years back (2003 i think), I made a lavalampy sort of thing with Graphics2D clips: here (sorry, its an applet, I used to be an applet activist... Wink)
Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Reply #5 - Posted 2006-05-18 20:11:50 »

Hi,
  You are trying to draw only the part of the image from (in image coords)
(0,0) to (someWidth -x , someHeight - y)

   You can use the method that woogley said.

1  
g.drawImage(someImage,x,y,someWidth, someHeight, 0,0,someWidth-x, someHeight-y,this);


  If the area of the destination rectangle is equal to the source rectangle, there is no scaling.
 
   Rafael.-



Ah ok I get it now.  What im trying to do is draw a frame out of my sprite sheet. Not sure if the best approach is the drawImage or getSubImage. Which one is better? My images are buffered.

Kommi
Offline woogley
« Reply #6 - Posted 2006-05-18 20:18:03 »

Ah ok I get it now.  What im trying to do is draw a frame out of my sprite sheet. Not sure if the best approach is the drawImage or getSubImage. Which one is better? My images are buffered.

well, it depends. in both examples I gave you in my last post, the clips were pretty much always moving. in that case, the getSubimage method and the drawImage method are practically the same.

drawImage will crop the section of the image every time you call it, so if your clip object is always in movement, that's fine. but if you're setting a permanent clip, I would use getSubimage to save the clip to another BufferedImage object and then you can just draw than whenever you want (so java only has to "crop" the image one time).

so, in both scenarious, getSubimage turns out to be equal and/or better than the drawImage method, so I would just stick with getSubimage.

when it comes to NON rectangular clips, the best way to go is with the Graphics2D clipping methods with the Shape class.. but that's more computationally expensive and it is computed on each rendering call.
Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Reply #7 - Posted 2006-05-18 20:26:10 »

I get it now, but the thing is is that I will have a different clip range every other frame, so as to get the full animation (using a sprite sheet). So I guess i will stcik with the drawImage, since I need to reclip the image constantly, and getting the subImage sounds like it would create a new mage every time.



Kommi
Offline woogley
« Reply #8 - Posted 2006-05-18 20:30:03 »

if the sprite animation isnt like massive.. why not just cache each individual frame into an image array? then you can access it with imgArray[frame] any time you want =o
Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Reply #9 - Posted 2006-05-18 20:57:09 »

Hehe, its pretty big, 5 unique directions, 10 frames per direction, plus 1 direction with about 5 frames Smiley

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

JGO Coder




Where's the Kaboom?


« Reply #10 - Posted 2006-05-19 00:11:23 »

Don't use getSubImage for your drawing routines...  make separate images from your sprite sheet and then draw with those images.  Just as Woogly says.. cache the individual frames.

Drawing a sub-image is not as fast.

Offline Kommi

Junior Member




All opinions will be lined up and shot!


« Reply #11 - Posted 2006-05-19 13:03:23 »

Is that really better than clipping the area of the sprite sheet? performance wise? Hum.. I guess switching from one reference to another would be faster than constantly re clipping the same sprite.

Kommi
Offline Anon666

Junior Member




aka Abuse/AbU5e/TehJumpingJawa


« Reply #12 - Posted 2006-05-20 00:41:24 »

From a performance perspective, why are you even considering this issue?

The calculations necessary in the underlying pipeline are identical when comparing a clipped blit Vs a subrectangle blit.

The only issue you should be considering, is whether your blit will be hardware accelerated, as this will give you performance gains of between 100times, to 1000times the speed. (that is 10000% to 100000% the speed of an unaccelerated blit)

From the perspective of design, you should completely ignore the 'subrectangle' caabilities that BufferedImage offer.
These api functions are not offered to give any kind of performance benefit, they are mearly convenience methods so that higher level programming need not concern itself with the complication of calculating the correct clip rectangle necessary to draw a particular sub-rectangle.
Use the clipping capabilities offered by the Graphics[2D] classes - thats what it is there for.
Offline woogley
« Reply #13 - Posted 2006-05-20 01:39:50 »

caching the results of a subimage from a BufferedImage means you only have to perform the operation that one time - which will always be faster than clipping it over and over on each render ..
Offline Anon666

Junior Member




aka Abuse/AbU5e/TehJumpingJawa


« Reply #14 - Posted 2006-05-20 10:11:02 »

You are talking about a difference of a handful of additions/subtractions.

I'd love to see a benchmark that demonstrated drawing a subrect was any faster than drawing the entire image with an equivalent clip.
Offline CommanderKeith
« Reply #15 - Posted 2006-05-20 15:03:19 »

I agree that caching multiple overlapping images on a single image will be faster than individually drawing the overlapping images (obviously).

caching the results of a subimage from a BufferedImage means you only have to perform the operation that one time - which will always be faster than clipping it over and over on each render ..


But if you are talking about painting part of a single image, then wouldn't sub-image & setting the clip be the same?  Remember there is always a clip applied to drawing anything on the screen - the device (screen rectangle) clip. 

If what you say is true, drawing an image that is bigger than the screen is quicker than drawing an image the same size... hmm shouldn't be too hard to make a bench-mark - I'll do it if I can find time.  I bet there's no difference.

Offline woogley
« Reply #16 - Posted 2006-05-20 15:14:49 »

I think you guys are misreading me. I will definitely benchmark this later so you see what I mean.

picture a spritesheet, okay? you only want to draw a clip of that image. my theory is, caching each little sprite frame into an array of subImages would be faster than clipping the spritesheet at every render.

drawing a cached subimage is faster because there isn't any clipping done, java is just drawing a regular image, that happens to have been cropped beforehand from the spritesheet. Wink
Offline Anon666

Junior Member




aka Abuse/AbU5e/TehJumpingJawa


« Reply #17 - Posted 2006-05-21 09:20:51 »

The operations performed to achieve the result are functionally identical in both cases - however I expect repeatedly clipping the single image will be everso-marginally faster.
A simple blit such as :-

1  
2  
g.setClip(dstX,dstY,srcWidth,srcHeight);
g.drawImage(img, dstX-srcX, dstY-srcY, null);


From a very superficial view, this approach will touch the same 2 areas of memory each time you do a blit.
(writing to the clip fields in the Graphics object 'g', and reading from the member fields in BufferedImage 'img')
But - however many part of the img you draw, you will only ever be touching the same 2 areas of memory.

The subrectangle approach will not touch the Graphics objects clipping members - however, each time a different subrectangle is drawn - you will be reading member variables from a different wrapper object - consequently you will be jumping all over memory.
This IMO has a higher probability of causing cache misses.

I still very much doubt this difference will be detectable though, as there are far far larger overheads involved in the pipeline that will eclipse such a tiny speed difference.


However - for the comparison to be completely fair (and functionally equivalent in all cases), I suppose the setClip approach should realy be doing the followiing :-

1  
2  
3  
4  
Shape oldClip = g.getClip();
g.clipRect(dstX,dstY,srcWidth,srcHeight);
g.drawImage(img, dstX-srcX, dstY-srcY, null);
g.setClip(oldClip);


So, if you do benchmark the 2 approaches - use this approach, not the simplified version.
Offline woogley
« Reply #18 - Posted 2006-05-21 21:15:34 »

okay, here is the benchmark: http://woogley.net/misc/Clipping/

it appears (on my system, at least), that subimaging is ~3x faster than clipping. you can find the benchmark program on the webpage

happy coding Wink
Offline CommanderKeith
« Reply #19 - Posted 2006-05-22 00:58:53 »

Great work, thanks for publishing that.  Its very clear.  Experiments like that should all be put in one place around here somewhere.

I wonder whether it is the setting & resetting of the clip that takes the extra time or the computation to figure out what part of the image inside the clip.  Probably the latter I guess.

Offline Anon666

Junior Member




aka Abuse/AbU5e/TehJumpingJawa


« Reply #20 - Posted 2006-05-22 02:34:04 »

Wow, I stand corrected.
Though I am still dubious as to the cause of the slow-down, and a 3x slowdown!?!?

For an operation that should be graphics card limited, I think there is something going seriously wrong in the 2D pipeline for such a dramatic difference.

I'd be interested to see what speed drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) gives, as this would eliminate the overhead of the setClip invocations.
Offline woogley
« Reply #21 - Posted 2006-05-22 03:29:31 »

as you wish, the benchmark has been updated to include a 3rd method - "drawImage"

it turns out this method is identical to the graphics clipping - my best guess is that there is some kind of internal clipping going on in the background.

subimaging is faster simply because it has less computation needs than the other 2 methods. it's just read-from-source -> plot-to-screen.

edit:
after further investigation, it seems hardware acceleration is making the difference!

every subimage in the subimage array is on a hardware accelerated surface. this makes it a hardware blit from source -> screen.

although the spritesheet itself is on a hardware accelerated surface, we're making Graphics do its own calculations with pixels which makes it a software blit from source -> screen.
Offline CommanderKeith
« Reply #22 - Posted 2006-05-22 05:16:21 »

although the spritesheet itself is on a hardware accelerated surface, we're making Graphics do its own calculations with pixels which makes it a software blit from source -> screen.

So the lesson is - clipping an image kills that drawImage operation's hardware acceleration.

Does that mean that painting a big, larger-than-the-screen image will forfeit hardware acceleration due to the screen clip?

Offline woogley
« Reply #23 - Posted 2006-05-22 11:08:30 »

Does that mean that painting a big, larger-than-the-screen image will forfeit hardware acceleration due to the screen clip?

hm... technically, ANY image that's drawn outside the boundaries of the screen is clipped, and therefore, should lose accleration. but if you notice, the sprites DO leave the screen a bit on the right/bottom sides.. with no obvious effect..

*shrug*
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #24 - Posted 2006-05-22 15:09:57 »

Mh.

On the first run I got these numbers with 1k sprites:
SI:24
GC:22
DI:23

After a reboot I got these (again 1k sprites):
SI:17
GC:12
DI:13

Geez... why? There is even less stuff running in the background.

Well, there are some things bad about this benchmark. The spritesheet's size exceeds 2^16 pixels and you're only using 2 buffers (which is fine for windowed mode, but really bad for fullscreen).

弾幕 ☆ @mahonnaiseblog
Offline Anon666

Junior Member




aka Abuse/AbU5e/TehJumpingJawa


« Reply #25 - Posted 2006-05-23 09:37:46 »

Quote
The spritesheet's size exceeds 2^16 pixels

ah yes, ofcourse.

However, I would have expected this to cause no hardware acceleration for all versions - as getSubImage uses the same source pixel data as its parent image.
Perhaps BufferedImage's created from getSubImage are cached in vram independantly of their parent image.


Offline woogley
« Reply #26 - Posted 2006-05-23 12:44:52 »

However, I would have expected this to cause no hardware acceleration for all versions - as getSubImage uses the same source pixel data as its parent image.
Perhaps BufferedImage's created from getSubImage are cached in vram independantly of their parent image.

yes. that's how I coded it Wink
quick code snippet...

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
protected void loadSprites() {
   // <snip>
  for (y = 0;y < spriteImg.length;y++) {
      for (x = 0;x < spriteImg[y].length;x++) {
         spriteImg[y][x] = createBuffer(Sprite.WIDTH,Sprite.HEIGHT); // <-- new acccelerated image from createBuffer
        spriteImg[y][x].createGraphics().drawImage(sheet.getSubimage(x*Sprite.WIDTH,y*Sprite.HEIGHT,Sprite.WIDTH,Sprite.HEIGHT),0,0,null);
      }
   }
   // <snip>
}


that createBuffer method returns a hardware accelerated image surface. I draw a sprite frame onto that and then it is never drawn on again. viola, yet another accelerated image =o
Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #27 - Posted 2006-05-23 18:48:53 »

Java engineers have made it clear in the past (through these forums) that getSubImage shouldn't be used, cause it's implementation is not optimal.

They explicitly said to paint the image into a new image instead of using getSubImage.

I can only assume that the clipping/drawImage implementations have similar implementation issues.

Offline woogley
« Reply #28 - Posted 2006-05-23 18:57:24 »

They explicitly said to paint the image into a new image instead of using getSubImage.

doesn't make a difference, the benchmark only calles getSubimage during intiliazation and records the results on a hardware accelerated image, the method is never called again
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #29 - Posted 2006-05-23 23:56:52 »

The reason you're seeing bad performance with non-subimage modes is that you
use getSubImage() on the "sheet" image, which disables its acceleration.
(it's easy to see if you run with -Dsun.java2d.trace=log to see what primitives are
being used).

I made some simple mods to your test (which is pretty nicely done, btw):
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  
#> diff -c TestOld.java Test.java
*** TestOld.java   Sun May 21 20:24:23 2006
--- ../Test.java        Tue May 23 16:55:31 2006
***************
*** 205,218 ****
                // there 8 total sprites
               // okay, so lets do this
               sheet = loadImage("sprites.png");
                spriteImg = new BufferedImage[sheet.getHeight()/Sprite.HEIGHT][sheet.getWidth()/Sprite.WIDTH];
                int x,y,j = 0;
                for (y = 0;y < spriteImg.length;y++) {
                        for (x = 0;x < spriteImg[y].length;x++) {
                                spriteImg[y][x] = createBuffer(Sprite.WIDTH,Sprite.HEIGHT);
!                               spriteImg[y][x].createGraphics().drawImage(sheet.getSubimage(x*Sprite.WIDTH,y*Sprite.HEIGHT,Sprite.WIDTH,Sprite.HEIGHT),0,0,null);
                        }
                }
                sprites = new ArrayList();
                for (j = 0;j < 25;j++) {
                        sprites.add(new Sprite(rand(0,7),new Point(rand(0,width),rand(0,height)),new Point(rand(0,width),rand(0,height)),rand(1,3)));
--- 205,220 ----
                // there 8 total sprites
               // okay, so lets do this
               sheet = loadImage("sprites.png");
+               BufferedImage sheet1 = loadImage("sprites.png");
                spriteImg = new BufferedImage[sheet.getHeight()/Sprite.HEIGHT][sheet.getWidth()/Sprite.WIDTH];
                int x,y,j = 0;
                for (y = 0;y < spriteImg.length;y++) {
                        for (x = 0;x < spriteImg[y].length;x++) {
                                spriteImg[y][x] = createBuffer(Sprite.WIDTH,Sprite.HEIGHT);
!                               spriteImg[y][x].createGraphics().drawImage(sheet1.getSubimage(x*Sprite.WIDTH,y*Sprite.HEIGHT,Sprite.WIDTH,Sprite.HEIGHT),0,0,null);                        }
                }
+               sheet1.flush(); sheet1 = null;
                sprites = new ArrayList();
                for (j = 0;j < 25;j++) {
                        sprites.add(new Sprite(rand(0,7),new Point(rand(0,width),rand(0,height)),new Point(rand(0,width),rand(0,height)),rand(1,3)));


Basically, I just do getSubImage on a different image instead of the one used
by "mode 0".

With this change I get _much_ better performance with drawImage method than getSubImage.

Especially with the new Direct3D pipeline in mustang, it costs a lot to change the texture to render from.
In your case, if you have tons of images you'll change the source texture for every sprite,
which costs a lot.

Also, with tons of smaller images you may be wasting more video memory.

Thanks,
  Dmitri
Java2D Team
Pages: [1] 2
  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.

BurntPizza (22 views)
2014-09-19 03:14:18

Dwinin (35 views)
2014-09-12 09:08:26

Norakomi (62 views)
2014-09-10 13:57:51

TehJavaDev (88 views)
2014-09-10 06:39:09

Tekkerue (43 views)
2014-09-09 02:24:56

mitcheeb (65 views)
2014-09-08 06:06:29

BurntPizza (47 views)
2014-09-07 01:13:42

Longarmx (35 views)
2014-09-07 01:12:14

Longarmx (40 views)
2014-09-07 01:11:22

Longarmx (36 views)
2014-09-07 01:10:19
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!