8-bit fire effect in Python (need feedback)

Started by
5 comments, last by wodinoneeye 16 years, 11 months ago
So I'm working on this 8-bit drawing module for Python that sits on top of pygame so I can more easily write older-style games with palette effects and such. I wrote up a simple fire effect (based on this) to test it, but the performance isn't too great considering I'm processing every pixel in Python code. Any suggestions for optimizing this would be appreciated. I'd also like to know what kind of FPS this gets on other machines (and their specs). Download (run test.py, requires Python 2.5, pygame and PyOpenGL)
Ra
Advertisement
If you haven't already, verify that it is entirely the fire effect updating that is slow, and not the transferring of the entire screen every frame to opengl.

I'd suggest trying numpy arrays instead of ctype for passing around arrays of data, and then using numpy to optimize the calculations (since it can perform more optimized operations on arrays). It may be easier to use two arrays, one as the source and one as the destination, swapping them after each update.
I am 100% sure the pixel processing is the cause. Everything in retro.py is practically free... even if I remove the flag to stop it from reloading the palette every frame the difference is negligible.

I've looked into numpy but I can't find a decent way to convert between a numpy array and a memory buffer, or some way to make the array use the memory buffer. This really isn't an option, as PyOpenGL won't accept any kind of array when reloading the texture, and conversion at that point would become quite costly.
Ra
Hmm...are you using PyOpenGL 2 or 3? It seems like PyOpenGL3 is still in alpha or something, but that it supports numpy arrays. If you're using PyOpenGL2, then I think you use numeric instead. The information available on the web on this subject seems a bit sparse...
I'm using 3.0... I was under the impression that it's officially released, but others have told me it's beta or even alpha, and looking over the site didn't tell me much either way. I can't seem to get glTex(Sub)Image2D() to accept anything other than a memory buffer, and the documentation isn't particularly helpful.

I suppose I'll have to fiddle around with it for a while.
Ra
I just spent some time playing around with this problem. I'm using python 2.4 and PyOpenGL 2 because I'm lazy and didn't feel like upgrading, so I had to change the code to use the old interface. I had the best results using numpy arrays for the calculations. The entire update is performed using the line:

display[:workingsize] = ((x1.astype('h')+x2+x3+x4)*32/129).astype('B')

Where x1-4 are different slices of the display array, which has an extra 2 rows to simplify things. The array stores unsigned bytes (typecode 'B'), but to avoid truncations I cast it to halfwords (typecode 'h') in the calculation. To pass the data to openGL, I use the tostring() method of the numpy array to get a string containing the bytes. At 320 by 240, this gets up to about 25 fps on my 800 MHz P3. I'm wondering if numpy has some better way to express the desired result, to use less temporaries maybe?

Then I put together a quick version in C++, and that runs at 25 fps in debug and 37 fps in release mode.

Smaller effects run a lot faster of course.
Of course you could always write the function in C and call it from python -- thats what I always hear whenever 'performance' rears its ugly head....

--------------------------------------------[size="1"]Ratings are Opinion, not Fact

This topic is closed to new replies.

Advertisement