Dynamic GUI

Hello there, I’ve got a series of PNG images that I’m using to add a power meter to my HUD. Each image adds an extra bar to the meter. I’m using the OnscreenImage function, and simply setting the corresponding image to my ‘power’ variable using setImage. The first time that each image is displayed there is a bit of lag. I was just wondering if there is a better way to implement this rather than using OnscreenImage? Would it be better to have all the PNGs as separate OnscreenImages and then hide() and show() relative to the power variable?

Many thanks, Jake.

I’d advise against that. But you could preload the images and store them in a list. (Takes GPU memory, though.)

Or use egg2bam to convert your PNG’s to .txo format which loads a lot faster in Panda.

Or if its some sorta loading or bar system, just use the same image over and over/change its size.

With a bar, just copy the bar image and move it up or down one.

With a loading (one long bar) just increase the lenth of it to the point it gets to the end or 100%

Or if its a image that changes color, you could just load a basic singal image and then just applie the colors you need to it.

Just some ideas…

thanks for the quick reply. I now load all my the separate PNGs that I need at runtime so there is no lag when I use setImage now. However it seems that setImage takes quite a hit out of my FPs. First I had a task that checked the power variable every frame, I then changed this to doAgain every 0.25s. I will try the .txo format but I think its the setImage that is causing the problem.

Would like to implement something like adr suggested but think it would be very difficult with my design:

I have a separate PNG for every bar! Any other ideas?

OnscreenImage.setImage() is indeed too heavy to call every frame, since it creates dynamic geometry and does some other stuff. But you don’t need to call it every frame; just call it only when the power meter changes.

Another way to improve this performance is to create a single egg file (perhaps using egg-texture-cards) that already contains all of your textures within it, and just show and hide parts of this model as you need to reveal sections of the power bar.


A better solution would be to separate the power bar outline and its underlying colours, like so:

Then, you have a couple options as to how you can display the individual power levels. One would be to use a ‘mask’ of sorts with Panda’s blending modes, and offset it by a certain amount every time the power bar changes.

The general idea is that you have two textured cards: an ‘outline’ card and a ‘bars’ card. Placing the ‘outline’ card over the ‘bars’ card should display the power bar in full, with all the colours in place.

You would then load a mask texture (a white square as big as the power bar) with a transparent border, and apply it to the ‘bars’ card. By offsetting the mask texture, you can adjust which coloured bars are visible. Here is some code using the image above:

#load the mask, or generate one with PNMImage
maskTex = loader.loadTexture('res/whitesquare.png')
maskTex.setBorderColor(VBase4(1, 1, 1, 0.0))
#apply the mask
stage = TextureStage('ts')
bars.setTexture(stage, maskTex)
#move the mask so that only the first bar is showing,
#i.e. power level = 1
off = 16
tx = float(maskTex.getXSize())
bars.setTexOffset(stage, (tx-off)/tx, 0)

You may also want to look into texture atlases, rather than using different PNG images for each element of your GUI. I’ve written a quick demo with p3doverlays that uses texture atlases and the ‘mask’ technique described above to create an adjustable power bar element. You can find it here:
p3doverlays.googlecode.com/svn/t … owerBar.py

The added benefit of using a mask for something like this is that you can add tweening effects: rather than the coloured bars appearing one at a time, you could have them slide in smoothly.

Hope it helps.

That’s fantastic, going to implement that now. Many thanks davedes, will hopefully show a marked improvement in performance. Great explanation.