Friday 25 June 2010

...And the post frequency meter was striking thirteen!

Yes, I know - two posts in as many days! Utter madness! The post frequency meter is indeed frazzled. But this is merely a swift news-deposit before I head off to undertake the elaborate job of implementing the new keyframing system in PyIgnition for the Alpha 4 ('controlled eruption') release. Incidentally, on that topic, I've just this morning sorted out completely how I'm going to implement the new system. It's all scribbled down on assorted scraps of paper (many of which lie within my own head), and just needs to be coded now. However, as mentioned a few sentences ago, it'll be a long and difficult process. Updates will follow when it's underway!

So, to return to the planned purpose of this present posting, I've done a bit of dabbling in wxPython today for the first time in ages and I must say I'm addicted all over again. It's simply brilliant. And, I'm pleased to announce, fully compatible with Pygame after a little bit of fiddling around. Here for your viewing is a screenshot of 'Wind.py' running on a wxPanel, completely under the command of wxPython:


The window is even resizeable, and the particle effect display scales with it. Incidentally, 'Obsidian' is a name that we were originally considering for what is now PyIgnition, and at the moment is probably going to be the name of the particle effects editor. More incidentally, the more astute amongst you may have noticed that the window looks a bit different to those seen in screenshots I've posted in the past. Why, you ask? Well, I've finally upgraded from the old XP machine (which is probably getting near its sixth birthday now), and with the new one came a new OS: Windows 7. It's rather good actually; I fully agree with those saying it's a vast improvement over Vista. But I digress.

Using pygame in wxPython applications is actually not too complicated a process, although it was incredibly difficult to find anything about it on the Internet when I looked so I'll post my findings here in the hope that the next person who tries it will find them through a Google search. There's only really one source I could find that explains it, and that's the one at http://wiki.wxpython.org/IntegratingPyGame. However, it's a bit iffy in its explanation. In case you don't notice immediately, they miss the part where they actually give the wxFrame a child to use as a pygame display - you'll need to remember to create this yourself. I just used a simple wxPanel.

The code to look at is line 10 - this makes SDL see your widget (or wxWindow, to be terminologically accurate) as the display. From there you can simply use pygame.display.init() as shown, and get a handle to the screen with self.screen = pygame.display.set_mode(). Normally in Pygame one would supply screen dimensions to that function, but here it's probably a good idea to leave them out. However I haven't tried supplying them so I don't know whether it would work or not, so feel free to experiment and see what happens. Now, although the link says you shouldn't import pygame until after setting the SDL_WINDOWID parameter, this is actually a pain because you then don't have access to pygame's functions anywhere else. I actually found that it works perfectly well if you do import pygame at the top of the file, so there's probably nothing wrong with doing so any more. That said, I'm just going with what seems to work so feel free to correct me if I'm wrong and there are hidden issues with doing so.

With that done, you're free to do things like self.screen.fill((0, 0, 0)) and pygame.draw.aaline(screen, [blah...]) to draw to the pygame surface, so all is well from there on. But is it? As a matter of fact, you'll face problems when you try to exit - neither pygame nor wxPython wants to close first, and you'll get errors either way. However, after a bit of messing around I've managed to find a solution to this. Simply bind the following function to WX_EVT_CLOSE:

____def Kill(self, event):
________self.Unbind(event = wx.EVT_PAINT, handler = [your drawing function])
________pygame.quit()
________self.Destroy()

See, the problem that arose in making Pygame quit first was that wxPython would for some reason try to draw again before it exited. This naturally causes problems when your drawing function contains Pygame draw functions, as they will be operating on a surface which has been disabled on Pygame's exit. Unbinding the draw function avoids this issue, and lets pygame exit first with wxPython smoothly following suit afterwards.

And that's pretty much it. So far I haven't found any more issues with the two working together, but I'll update if I do. I hope this proved somewhat helpful. So, back to keyframes!
Goodbye!

No comments:

Post a Comment