Painting outside of paint()


#1

I’ve a bit of a newbie question - I’m creating a VU Component but I want to do it as efficiently as possible. Therefore, only the smallest bit of the level meter is being repainted each time. I have that working using a varying y and height value in repaint(int x, int y, int width, int height).
However, I want to draw the background of each meter outside of the paint() method. Is this possible? I’ve tried the following as a test but nothing shows up. I’m calling the function from resize().

Thanks for any help.

void drawImageBackground ()
		{
			Image::ImageType type = Image::NativeImage;
			Image img (Image::RGB, getWidth(), getHeight(), true, type); //transparent image
			
			Graphics g (img);
			g.setColour (Colours::hotpink);
			g.drawEllipse (20, 20, 50, 100, 3); //test

			g.drawImage (img, 0, 0, getWidth(), getHeight(), 0, 0, getWidth(), getHeight(), false);
		}

#2

Not sure what you are doing with the last line, drawing the image back onto itself.
I do a similar thing with my meters, render two images, an off and on state, and draw how much I need to of each in the paint method.

I think you need a class member Image which you can render in your resized method and then draw onto the graphics context provided by your paint method.

[code]void drawImageBackground ()
{
img = Image (Image::RGB, getWidth(), getHeight(), true);

Graphics g (img);
g.setColour (Colours::hotpink);
g.drawEllipse (20, 20, 50, 100, 3); //test

}

void paint (Graphics& g)
{
g.drawImage (img, 0, 0, getWidth(), getHeight(), 0, 0, img.getWidth(), img.getHeight());
}
[/code]


#3

Thanks for the reply. But if I do that it will get redrawn every time I call repaint(), or at least some of it. Is it not possible to just leave it completely outside of the paint() method?


#4

Sorry, maybe I’m misunderstanding what you are trying to achieve. If you have nothing in your paint method then you are never drawing anything to the screen. The graphics context passed to paint needs to be filled with whatever you want to draw, in this case your image.

As far as I know the most efficient way to render stuff is to cache what you can to images and then draw these instead of using lots of Graphics calls (eg. g.drawLine, g.drawRect etc.) in your paint method. If you want to be super efficient you should check to see if your meter needs repainting at all before calling repaint. For instance while no audio is passing through your meters will probably just be on 0 so you don’t need to repaint them until the level changes.

I hope this makes sense. Are your meters really causing that much CPU usage? Have you tried profiling your code?


#5

The rules are pretty simple:

  • anything that changes dynamically should be drawn in your paint method
  • things that are difficult to render, and which don’t change, might be better cached in an image which your paint method can re-use.

But always profile your code to understand where the real bottlenecks are, before attempting anything fancy.


#6

Thats not always the case, because all this graphics can be graphic-card accelerated (if the low level graphic render support it), and if you cache it in binary, it always has to be transferred from the RAM into the graphic RAM.

I would en-capsule all the stuff which needs to be redraw often into a component and just call repaint() on it

other possibility to optimize is to use openGL
also enabling the repaint debug-flag could be helpful…

but the most import thing i would consider: http://c2.com/cgi/wiki?RulesOfOptimization


#7

and i forget to mention: the component which needs to be repainted often should be opaque (setOpaque(true) in constructor), so that no background from other components needs to be redrawn


#8

Thanks for the replies everyone. I think I get it now…I should put the background in an image cache and re-use it in paint(). I was trying to set up an additional paint() method if you know what I mean, but I understand now how it works.
Thanks.