Draw to an off-screen Image

I need to draw to an off screen image using standard Java Graphics calls, i.e. drawPolygon(), fillPolygon(). I am having a bit of trouble getting the graphics object becuase it says that I can’t do a getGraphics() until the image is displayable, but I don’t want it to be displayable. I want to draw to it in the background and then grab a copy of it to display. Anyone done this before?

Casey

Create a BufferedImage and then do a getGraphics() on that. You can then paint the BufferedImage on the screen, when your finished. Note that copying the BufferedImage to the screen is a slow operation. If your app is Fullscreen, you can alternatively use BufferStrategy to get a front and back buffer for the screen, which may (or may not) meet your need.

If you draw on an Image once, then copy it to the screen (unchanged) multiple times, you ought to look into acceleration. There’s a current thread on that somewhere on this board. Use the search facility if necessary.

Alan

Thanks, I’ll try that! :slight_smile:

The short hand outcome of that thread is that, as long as you are using JDK 1.5 or later, BufferedImages will handle that for you under the hood.

If this is a full-screen ghame as alreadu mentioend you may want to look into FullScreen Exclusive mode and BufferStrategies. This however requires using VolatileImages and is a fair bit more work.

I used Full Screen with BufferStrategy and never had to touch a Volatile Image. All the examples I’ve seen never used it also.

I suppose you could add them into the mix, but I dont think its required.

if you arent calling contentsLost() and handling it, your living in a dangerous world.

If you are, then you are using voaltile images, you just don’t realize it :slight_smile:

After seeing the contents get lost when manually resizing a window I did add a check for contentsLost() and recreate the BufferStrategy, this was back in Oct 2004. But its really easy.

Yes I did know that BufferStrategy used VIs, but it seems a lot easier to handle just one VI thing than handling all your images that way. I guess it just seemed you meant you needed to use VIs directly, but you didnt mean that :slight_smile:

If I do the following, I believe its been handled, so doesnt seem too hard.


public void render()
  {
    // If we've lost our video memory, don't bother drawing anything
    // This happens when resizing a window or deiconifying the application
    if (!bufferStrategy.contentsLost())
    {
      Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();

       // Draw some stuff

      bufferStrategy.show();
      g.dispose();
     }
    else                                //Try to recover the buffer strategy contents
    {
        //System.out.println("bufferStrategy, contents lost!");

        baseFrame.createBufferStrategy( buffers );
        bufferStrategy = baseFrame.getBufferStrategy();
       
        if(!bufferStrategy.contentsLost())
           render();         // we recovered so render stuff
     }
  }


I was thinking about letting it drop out of Render() after recovering, instead of calling Render() again. So I would lose a frame and avoid a possible infinite loop if for some reason I cant get a new BufferStrategy. But if that happened I would have a big problem anyway :slight_smile:

Unfortunately there were a few bugs in JDK 5 and earlier such that resizing a window that uses BufferStrategy was either painful or just plain didn’t work. We fixed most of these issues in Mustang (for both Blt and Flip strategies), so the developer shouldn’t have to do anything special after a resize (like manually recreate the BufferStrategy); you should be able to create the BufferStrategy once and use it forever, even after a resize.

That said, applications do need to call contentsLost() in their render loop when using BufferStrategy, just as you would when using VolatileImages directly. The javadocs for BufferStrategy were cleaned up a bit in Mustang, so the example code is a bit more robust. Check it out here:
http://download.java.net/jdk6/docs/api/java/awt/image/BufferStrategy.html

I’m pretty sure this is working fine since Swing is sitting on top of BufferStrategy in Mustang and we haven’t heard any complaints :slight_smile: If you could try this out on Mustang to make sure the issues are fixed, we’d like to hear your feedback.

Thanks,
Chris

If I was drawing the entire screen every frame would those two if( ) statements be needed?
Since all you are going to do is the exact same thing that is in the " // Draw to graphics " section.

It seems that demo code is targeted at rendering that only covers a part of the screen each frame and needs to reset the parts of the screen that get drawn to less than every frame. So in that case the if( ) sections are very important.

Example from JRE6 api as mentioned in this thread.


// Render loop
 while (!done) {
    Graphics g = strategy.getDrawGraphics();
    // Call this each time through to see if the underlying surface
    // was recreated.  If it was you may need to redraw.
    if (strategy.contentsRestored()) {
        // Surface was recreated and reset, may require redrawing.
       drawAllSprites();
    } else {
       // Draw only sprites that are marked as "dirty"
       drawDirtySprites();
    }
    strategy.show();
    if (strategy.contentsLost()) {
        // The surface was lost since last call to getDrawGraphics, you
        // may need to redraw.
        // ???What should we redraw here, isn't we already
        // have redrawn this frame???
    }
 }

I modified first “if” a bit and added “else” block. Do you think this is a proper rendering loop?

But I dont understand last “if(strategy.contentsLost())” method, we already have redrawn a part of the window or all sprites in a previous drawXXXX methods. Can we leave it this way and screen is up-to-date?

BufferStrategies are not guaranteed to hold their contents - especially on windows content losses may occur.

Therrefor if the buffer looses its content duing the rendering your graphics, you need to do rendering again, since blitting the lost buffer would mean you would paint the buffers whos contents are list.

lg Clemens

But in the 1.6 example that is exactly what they are doing.

test for restored
{ draw()}

draw()
show()

test for contentsLost
{ draw()}

So in the Sun example they are doing strategy.show() immediatly after drawing, which means it could be lost.
Then they are checking for lost.

I dont dispute that the contents could be lost during drawing, I am just questioning the logic of the example code, since they could be doing strategy.show() with bad contents then check for lost after that.

If showing bad contents is to be avoided then something like the code below makes more sense to me.


public void render()
{
    while( !drawn )
    {  
        if (bufferStrategy.contentsRestored())
       {
             drawAllSprites();
        }
       else
       {
            drawDirtySprites(); 
       }

       drawn = true;

        if(bufferStrategy.contentsLost())
       {
            recoverStrategy();  // support for 1.5 and lower versions, possibly put in an if() to test for version number
            drawn = false;
             // 1.6 does automatic recovery
       }
    }

    bufferStrategy.show();
}

Hm. Ive never looeked closely at whats in the API docs.

I learned to use this stuff based on Mike Martak’s articles:

http://java.sun.com/docs/books/tutorial/extra/fullscreen/

Yeah I read those too last year, they were a big help.
But it doesnt use contentsLost() or contentsRestored(). Which is why my first versions last year also didnt use them until I spotted the resizing problem.