Search code examples
javaperformanceopenglslick2d

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?


Solution

  • 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.