We have an old Java Swing application. we need to display thousands, hundreds of thousands small circle spots on the canvas based on the real data. Right now we have an image file of a small circle spot. When we need it, we draw that image onto the canvas, thousands, hundreds of thousands times.
Now I am think it may be better (better performance and memory usage) to just draw a filled circle each time instead of load the image and draw it.
how about your opinion?
thanks,
You only need to load the template image once and hold it in memory and copy it to the canvas as needed using Graphics2D drawImage function. Drawing multiple filled circles may become expensive due to calls to the Flood-fill/Scan-fill algorithm as well as Bresenham to draw the circle. To optimize the rendering you can also decimate the rendered result or perform clustering, since the user will not really appreciate dense overlapping circles anyway.
To reduce render calls test the pixel where your template is going and pass a render if it is already coloured.
Here is a nice benchmarking applet.
It is almost certainly much faster to hold a single image and draw it many times than to make a call to draw a filled circle. Here is a recent presentation on the subject, showing that it is faster to draw an image than even a simple horizontal cross. http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-4170&yr=2009&track=javase
Time your code
It is most definitely faster to draw an image lots of times than drawing a circle or String lots of times and it's very easy to test. At the beginning of your paintComponent() method add the line:
paintComponent(){
long start = System.currentTimeMillis();
...
// draw 100,000 circles as images or circles
...
System.out.println("Rendering time: " +
(start - System.currentTimeMillis()) + " ms");
}
If the times turn out to be zero all the time, you can instead use System.nanoTime().
Paint to Cached Image
Another thing you can do is to paint these circles onto an image and only recreate the image when the content changes. If nothing has changed just draw that image onto the Graphics2D object instead of redrawing all of the circles. This is commonly called double buffering. You also can use Volatile Images to take advantage of hardware acceleration.
Create Compatible Images
You should also make sure you use images that are compatible with the user's monitor by using createCompatibleImage() as shown below:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
// Create an image that does not support transparency
BufferedImage bimage = gc.createCompatibleImage(width, height, Transparency.OPAQUE);
// Create an image that supports transparent pixels
bimage = gc.createCompatibleImage(width, height, Transparency.BITMASK);
// Create an image that supports arbitrary levels of transparency
bimage = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
More Tips
I'd recommend the book Filthy Rich Clients. It has lots of great tips for speeding up swing. Especially look at chapters 4 and 5 about images and performance.
I don't now if this would be helpful but you can test which one works for you by testing worst case . But I think filled circle would be best .
A third way to do it is to use the unicode char for filled circle, ●, since you can bet that rendering thousands of chars (as in: a piece of text) is the most normal thing for any graphics engine.
It's hard to predict which is faster, because certain operations under certain circumstances are accelerated by the GPU hardware of the video card.
If the GPU is used to make the circle, then that would be much faster than the cpu copying pixels of a buffered circle as an image.
There is VolatileImage as well. Perhaps it's possible to make the image blits so that they end up being accelerated.
The only way to find out is to benchmark it yourself.
Related
In short, I'm making a simulation where I have a bunch of creatures that can see each other. The way I want to do this is to capture an area around each creature and give it to their neural network, and make them evolve to recognize their surroundings. I am coding this using LibGDX, and I don't plan on making screenshots every single frame because I can imagine that that is already a very poor idea. However, the problem is that I don't know how to get the pixels inside a defined square without capturing the entire screen and then cherry picking what I want for each creature, which will cause a MASSIVE lag spike, since the area these creatures will be in is 2000x2000, and therefore 12 million different values (4 million RGB values).
Each creature is about 5 pixels (width and height), so my idea is to give them a 16x16 area around them, which is why iterating through the entire frame buffer won't work, it would pointlessly iterate through millions of values before finding the ones I asked for.
I would also need to be able to take pictures outside of the screen (as in, the part outside the window's boundaries), if that is even possible.
How can I achieve this? I'm aiming for performance, but I do not mind distributing the load between multiple frames or even multithreading.
The problem is you can't query pixels in a framebuffer.
You can capture a texture from a framebuffer, and you can convert a texture to a pixmap.
libgdx TextureRegion to Pixmap
You can then getPixel(int x, int y) against the pixmap.
However, maybe going the other way would be better.
Start with a pixmap, work with the pixmap, and for each frame convert the pixmap to a texture and render that texture fullscreen. This also removes the need for the creatures environment to match the screen resolution (although you could still set it up like that).
I am writing a 2D lunar lander-style game in Java and using the Slick2D library to handle the graphics. I am having a problem handling the background images.
Here is my problem:
I have 3 layers of details to paint on the background behind the spaceship (stars, mountains and land including landing sites). These are repainted each loop as the ship (centre of the screen) moves around.
The images for these layers are 4500 pixels wide by 1440 high. This is mainly to create some sense of variety (stars) and to be sufficiently wide to hold the generated mountains and land (the land includes the landing sites). Mountains and land are generated per turn and are polygons drawn into holding images.
Slick2d (or opengl) is complaining that it cannot handle images of this size - it says it can only handle textures that are 512 x 512 on my development PC. So... if I have been exploring different methods to work around this including:
a. doing polygon clipping in each loop to reduce my polygons (mountains and land) to the displayable screen size (640 x 480), but this seems mathematically challenging, or
b. splitting my layer images into 512x512 tiles and then updating the screen with the tiles, which is an extension of what I already do (wrapping the layers to create an 'infinite' world) so seems more do-able given my abilities.
My first question (or sense-check, really) is am I missing something? My images, although large, are minimal in terms of content, e.g. black background with a few lines on. Is there a way to compress these in Slick2D/opengl or have I missed something to do with settings that means I can make my card handle bigger images? (I'm assuming not, based on what I have read, but hope springs eternal.)
So, assuming I have not missed anything obvious, on to part 2...
As a quick "I might get away with this" workaround, I have reverted to using BufferedImages to hold the layers and then extracting portions of these into Slick2D images and painting these on the screen in each render loop. Doing it this way I am getting about 3 FPS, which is obviously a tad slow for a real-time game.
To create the BufferedImages I am using:
BufferedImage im_stars = new BufferedImage(bWIDTH, bHEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D gr_stars = im_stars.createGraphics();
... and then I draw my content onto them (stars, etc.)
In my render loop a do a bit of maths to work out which chunks of the images I need to display (to cope with wrapping/providing an 'infinite' experience) and then extract the relevant portions of BufferedImage to a Slick2D image(s) as follows:
Image i1_star = Tools.getImage(stars.getStarImg().getSubimage((int) x1, (int) y1, width, height));
g.drawImage(i1_star, 0, 0);
I have written a static helper method to convert my BufferedImage chunk to a Slick2D Image as follows:
protected static Image getImage(BufferedImage bi) {
Image im = null;
try {
im = new Image(BufferedImageUtil.getTexture("", bi));
} catch (IOException ex) {
Logger.getLogger(Tools.class.getName()).log(Level.SEVERE, null, ex);
}
return im;
}
I'm guessing this is a bad way to do things based on the FPS I am getting, although 3 seems very low. I was getting about 25 FPS when I was using code I'd written myself doing the same thing! So, is there an accelerated Slick2D/opengl way to do this that I am missing or am I back to having to either tile my background images or hold them as polygons and develop a polygon clipping routine?
Having done some more research, I have found that my graphics card can support up to 4096 x 4096 pixel images using Slick2D's:
BigImage.getMaxSingleImageSize();
I have reverted to using Slick2D image files with a width no larger than this size in my program and am now getting around 350 FPS so the BufferedImage work-around was definitely a bad idea.
I thought about the best way to draw a picture in OpenGL / JOGL.
I currently program a Game and it is my goal to save the information about a picture in a text file instead of saving the picture.
My idea was to program a method that saves every pixel information (RGB) at the position of X and Y.
Then I draw every pixel and it is finished.
What you think about that idea?
You should simply use TextureIO to make a texture from your picture and use this texture with 4 vertices that have some texture coordinates while drawing. glReadPixels() is very slow, reading each pixel of a picture would take a lot of time, saving its content as a text file would require a lot of memory (saving it as a compressed image in a loss-less format like PNG might be worth a try), drawing each pixel one by one would be a lot slower than drawing a texture. derhass is right. You could vectorize your picture (make a SVG from it) but you would have to rasterize it after or you would have to implement some rendering of vectorized contents and it would be probably slower than using a texture. I'm not sure you really need an offscreen buffer.
I had a similar problem when I began working on my first person shooter. I wasn't using JOGL at the very beginning, I reused the source code of someone else, it relied on software rendering in an image, it was very slow. Then, I used JOGL to draw each pixel one by one instead of using Java2D, it was about 4 times faster on my machine but still very slow for me. At the end, I had to redesign the whole rendering to use OpenGL for what it is for as derhass would say, I used triangles, quads and textures. The performance became acceptable and this is what you should do, use OpenGL to draw primitives and clarify what you're trying to achieve so that we can help you a bit better.
I am writing a particle based game that is mainly built by drawing lots of colored shapes.
Question 1)
For most of the enemy units I am drawing 4 layered rectangles by setting the paint and then drawing the rectangle through the canvas.
I was wondering if it is better to draw using bitmaps, or to draw using the canvas drawing tools? I could easily make a single image of the enemy unit that I wish to draw.
Question 2)
For the images that I have to draw to the screen, I was wondering how I need to load them?
Right now I have tons of .png images loaded like this:
direction1 = BitmapFactory.decodeStream(assetMgr.open("direction1.png"));
I've read that RGB565 is the fasted image type to draw to the screen. Microsoft Paint has some saving options, but for the most part programs only save as a bitmap, not a type of bitmap. If I was to start using that new format would I:
Make new images and use the same loading code.
Use the same images and add something like Bitmap bmp =
Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); to
convert from the initial loaded format to the RGB565 format.
Make new images and change my loading code.
Thanks for any help! It is very appreciated.
None. It is always better to use OpenGL and the only downside is
that it requires more energy from a battery because it's hardware
accelerated.
RGB565 means that image uses 16 bits so that's the
option you should look for. Don't convert anything, just create them
in the format you will be using.
If the Bitmap aren't moving frame-by-frame, you should try to reduce invalidate() method call. The canvas should only be re-drawn when changes are made and should be updated.
I'm planning on implementing a new set of figures in my game: plain circles. The number of drawn sprites (in this case circles) starts with 2-3, and can go up endlessly (potentially). The maximum will probably be around 60 though. In total there will have to be 5 types of circles, each with a different color and probably size too. Now seeing as I won't implement it until monday I thought I'd ask it at stackoverflow.
Does anybody already know which method is faster?
Bitmaps are almost always faster than any kind of draw. With the right preparation drawing a bitmap is simply dumping memory to the screen. Drawing a circle involves a significant number of calculations, including anti-aliasing. I presented a paper which covered this at JavaOne 2009, but papers that old seem to have been removed from the site.
It does depend on how big your bitmap would need to be, but for sizes under 10 pixels bitmap sprites are much faster than even simple graphic operations like drawing crosses and lines. You also need to make sure that your sprite won't require any kind of transform when it is drawn, and that it is a form compatible with the screen memory.
If every circle is to be a different color or thickness, or worse a different size, then that's another matter. The cost of creating each bitmap would outweigh the savings.
You should also remember the first rule of optimization: don't do it unless you have to.