Android Drawing Performance - canvas.drawRect vs Bitmap Drawing - java

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.

Related

Slick2D Graphics Performance Issues Using Large Images

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.

Canvas Drawing using an image as place holder

I want to have a drawing canvas within my application which will display letter to free draw for practice. Something like the following:
OR
This is the first time I will be implementing this method so a few questions.
Can I have my own background for the canvas? (let's say a chalkboard?)
Do I have to create the letter as image and insert it onto the canvas as Bitmap?
I saw some tutorials but wasn't too clear on how to implement it within app.
I found a solution for you. Having more than 1 Canvas is not the answer (Although may work, I'm still new), but instead draw a seperate Bitmap on top of the first Bitmap (background).
Try this out for size: Overlying Bitmap
You should then be able to edit the overlaying Bitmap without affecting the original Bitmap.
Cheers!

How can i use canvas.save and canvas.restore? [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Can i save lots of bitmaps to one bitmap? (2d)
I wonder how canvas.save and canvas.restore really works.
how i want it to work, and how i use it (but doesnt work).
lock the canvas
do some drawing with out unlockandpost
canvas.save() (store the int)
Do some more drawings
Post the canvas
Restore the canvas from step 3
Do some more drawings, repeat from 6 (loop)
What i really need is to save my canvas at a certain stage ( the background), and then draw objects above it, without having to draw the background everytime i want to update my canvas.
Canvas.save() & restore() don't act on the bitmap attached to the canvas... they exist to control aspects of the canvas drawing environment, specifically the current clipping area and the matrix.
You'd use save() and restore if you wanted to, say, draw a rotated sprite. To do that, you'd first save() the current canvas state, then you'd translate() so that the origin - pixel address (0,0) - is where you want the sprite to go, then you'd rotate(), and then you can drawBitmap(). Finally you can restore() the drawing environment back to normal.
So you're basically doomed to draw the background every time. If this is a complex operation, store it in an offscreen bitmap. So long as the background can be drawn in a single operation (drawBitmap, say) performance shouldn't suffer too much.
Ok, so I figured it out.
I can draw my background containing lots of images to one bitmap using canvas, its pretty simple.
First create an empty bitmap with desired int height and int width, this will be the bitmap that you will draw all your tiles too (small images).
Bitmap background = Bitmap.createBitmap(width, heigth, Bitmap.Config.ARGB_4444);
(Not sure about the syntax Bitmap.Config.ARGB_4444 , use tooltip)
Then create a canvas with new Canvas(bitmap), this will make the canvas write to the bitmap.
Canvas canvas new Canvas(background);
Now you can write the canvas as you please, all will be stored in the bitmap for later use.

Efficient way to draw into a java.awt.graphics object

I'm trying to create an animation by dynamically generating frames at each step of the animation. Now as I need to run an algorithm to draw pixel by pixel the new frame and I'm using a BufferedImage that I access through its raster data.
However 90% of the time is spent inside java.awt.graphcis.drawImage() that I use to transfer the image into the content of a JFrame.
Is there a more efficient way to draw pixel by pixel inside a graphics object?
Try to use VolatileImage. Much faster than that is hard to do..

draw image or draw filled circle?

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, &#x25CF, 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.

Categories

Resources