Animation paints that do updates.

I’m somewhat confused by the Swing paint process with animations in a windowed environment (not full screen).

In paintComponent(), I need to know two things:

  • The region of the graphics buffer that has been damaged or invalidated since the last paint, provided by the graphics clip.
  • The region of the model that has changed (is dirty) since the last paint and must be redrawn, provided by the associated model.

In the first case, the region might have been obscured and redrawn in a single-buffer graphics system, or the back buffer was lost and re-created in a double-buffer system. Either way, the clip area must be completely redrawn (background and sprites). When a region is damaged, a repaint() is automatically called with the region as a parameter that is accumulated into the next paint clip.

In the second case, if that part of the graphics buffer is preserved from the last paint (not in clip), I can decide whether a full redraw (background and sprites) or an update draw (erase old changed sprites and draw new) is more efficient. In many animations, the update draw is far more common and efficient. I should be able to schedule a paint without a clip since there is no damaged region. If the graphics clip is empty or does not intersect the dirty region, I can decide whether to just update the dirty region.

The problem is that the JComponent repaint() method calls the RepaintManager.addDirtyRegion() method, and that method throws away any call with a width or height parameter <= 0. There seems to be no way to schedule a paint for a model update when there is no damaged region.

My question is: What is the correct way in Java2D to implement a paint process that can tell when to update a preserved region and when to completely repaint a damaged region?

If it gives you no region then draw the whole frame; if not then draw the region! It’s as simple as that, of course all you are doing is just copying from a backbuffer not actually processing the scene or anything.

And to consider your situation of repaint throwing away width and height parameters, well that’s what you’d want otherwise you’d end up with two calls of which one is redundant.

I do not think you understand the question. There are two ways to paint a region:

  • Redraw all of it; background and sprites.
  • Update the image that is still there from the last paint; erase and draw only affected sprites.

The first is necessary if the region is damaged by windowing or is a lost and recreated graphics buffer, and is indicated by the graphics clip.

The second is much faster when only a few sprites have been moved and the region is still in the buffer from the last paint. The region is indicated not by the graphics clip (which should be for damaged regions) but by the associated model, otherwise there would be no way to tell if a region was still preserved in the graphics buffer so that you can do an update draw.

The simplest solution to this seemed to be to let the windowing system make repaint calls with a region to indicate damage, and let the animation code make repaint calls without a region to let the model indicate updatable dirty regions that are not damaged. A paint event would have one, the other, or one of each which might overlap or be disjoint.

Remember, the Swing RepaintManager BufferStrategy manages any double-buffering. The whole idea is to allow code to be written that doesn’t know or care what buffering strategy is being used. If Swing double-buffering is enabled, the graphics buffer given is already a back buffer and most paint events are animation updates in regions that still have what was painted the last paint event unless the buffer is lost or invalidated from graphics memory. To use a second back buffer in the component is a waste of BLT time since Swing already gives you one. If not enabled, most paint events are still animation updates unless a region in the buffer was also overwritten by windowing.

Either way, you still need to be able to tell if a region only needs to be updated and is still preserved in the graphics buffer from the last paint event. As it seems to stand now, you can not schedule a paint event without a region (or with an empty region) to be unioned into the graphics clip for the next scheduled paint event that would normally indicate a damaged or invalidated region that you can not update draw but must completely redraw.

My question still stands: How is Java2D designed to allow a component to know when to do animation update draws in a graphics buffer region still preserved from the last paint event, as opposed to completely redrawing regions damaged from windowing or lost when the buffer is lost or invalidated?

as I know, java2d is open source, you can see for yourself if nobody here knows/doesn’t answer

As you can tell from my references to the behavior of RepaintManager and subclasses of BufferStrategy, I’m already well into the Java2D source. However, this does not tell me the intent of the design. I find it hard to believe that such a basic windowed paint algorithm as an update draw (we’re talking Windowing 101 here) is not managed by Java2D. I’d rather get the correct answer to what I’m missing than to start subclassing RepaintManager to allow empty repaints.

However, if this is really missing from Java2D, then that’s the only solution I see so far. Unless anyone else has a better idea? Update paints provide a significant speed improvement in a lot of 2D animations.

Oh I understand the question, but the general rule of thumb is to render your scene to your [offscreen] back buffer, and then somewhere you copy it to the output buffer. You can render to your offscreen back buffer however you see fit; dirty regions, Graphic.drawPolygon, whatever, you draw that - that is what I am talking about first. There you can draw your “only affected sprites”

When painting your component you paint what you are told to paint. That is not where you would draw sprites, backgrounds, lighting effects; here you are just copying from your buffer.

I think you’re over thinking this one. Consider that your update region is only the top left quarter of the screen and your update region (from your own model) is the bottom right - clearly something is wrong. Nobody will be playing your game where the whole screen, or at least a big portion of it is obscured and would not require a repaint. So whenever you are updating your screen your expectation is that whatever you update needs to be updated (regardless of what the region says). Then somewhere else you copy from the buffer to that region. I’m assuming (from your knowledge) that repaint(x,y,w,h) is not good enough in your situation.

So to go back on what I said, because I think you may have taken it the wrong way. If your region says “here needs updating” then you copy from your back buffer. When your game says “this has changed” then update that part of your back buffer. The use of dirty regions can be used in what I am saying, in fact that is how you would approach it - “this has changed”, “here needs updating”. You can then tell your panel that “this” is the region that needs updating and then your paintComponent method will be given “that” small region to copy from the back buffer.

One big question; are you actually having speed issues? And if so are you certain that they are to do with this? If not then remember that premature optimization is the root of all evil! The [alleged] author of “Killer Games Programming with Java” seems to have simpler implementations, and only required the use of BufferedStrategy for OSX, which has serious frame rate issues otherwise. Other than that it was straight image buffers from an ImageBuffer (using obvious techniques)