Background-saving animation


#1

Hi all,

Is it possible in any way to have an animation without redrawing of its background? For example I may have a complex stuff painted on the background and some simple animation over it. If I’ll redraw the complex stuff with every animation frame, it will result in significant unneeded CPU consumption.

A good example is the timeline cursor in Tracktion or any other app with audio-playback. How do they preserve the background?


#2

I just did this and found the following, I’ll use your Tracktion example

Have a component that is going to contain the Overview(or whatever the background image is going to be) ie(pseudo code, not tested, just typed in, blah blah blah)

ContainerComponent : public Component

ContainerComponent::ContainerComponent()
{
addAndMakeVisible(bgComponent=new BackgroundComponent());
}

void ContainerComponent::resized()
{
if (bgComponent)
bgComponent->setBounds(0, 0, getWidth(), getHeight());
}
void ContainerComponent::paintOverChildren(Graphics &g)
{
  // do your main animation here, position line, or whatever
}

your static background(or the one that doesn’t change very often) would be this


BackgroundComponent : public Component ...

BackgroundComponent::BackgroundComponent()
{
setBufferedToImage(true);
setOpaque(true); // see note below
}

void BackgroundComponent::paint (Graphics& g)
{
// do the static painting as per usual
}

I personally found I needed to setOpaque to be true as it was far too expensive on a faily large component to draw on top of it(JUCE uses a blend pixel function that is quite costly) By setting my background component to opaque, I found I could draw on top of it(with paintOverChildren()) at a rate of about 1 frame a second with about 5% of the CPU versus 25% if it wasn’t opaque

Hope that helps!


#3

Wow, I didn’t notice setBufferedToImage() feature yet. Ok, I’ll try to experiment with this, but wouldn’t it be more consistent to use background component as a parent for animation then?


#4

As a parent? I’m using it as the bottom layer(as JUCE “renders” from top down.) So the component containing “BackgroundComponent” can use “paintOverChildren” to paint on top of BackgroundComponent. So, in other words, your complex background is contained in BackgroundComponent which is drawn in the paint method. Juce’s convenient setBufferedToImage is cool if that paint method had lots of Path’s, Lines, colour changes etc, as it caches that stuff to an Image and can redraw just that(or a portion of it). However, by all means experiment with turning that off, there may be a chance its not faster!

Also with setOpaque to true, note that anything in ContainerComponent’s paint method won’t be visible. Think of the chain like this…

repaint() method is called…which then…

ContainerComponent::paint()
BackgroundComponent::paint() [which might obliterate any drawing done in ContainerComponent::paint if opaque]
ContainerComponent::paintOverChildren()


#5

Ahhh, I think I understand your question now…you are wondering perhaps if you can contain everything in one class, and perhaps push and pop a snapshot(or a buffered image) into the cache and THEN draw on top of it.

I don’t believe that’s possible, although would be kind of neat. The bufferedToImage flag would trigger a “re-cache” as soon as you draw over top of it(same as if you resize the component).

I am pretty new still at JUCE, so I hope I’m not leaded you astray :slight_smile:


#6

You’re right, I want to draw multiple animation stuff over one complex background. But I think it can be done if animation will be in child classes embedded into one main background component (which is content component for app window) with buffering to image set. This way I’m trying to implement now.


#7

Can’t you just use an Image to draw your complex background on just use the paint function for the simple things you want to draw on top.
Don’t use the paint function to do the complex stuff, just blit the image to the screen in the paint method.