Tuesday 3 August 2010

Nearly there!

So, it's past the end of the month, and is PyIgnition ready for the 1.0 release? Well, actually, the code is. All the new features are already implemented and theoretically bugless. However, the documentation (which is fairly important seeing as the only purpose of the project is to be used by others) lags significantly behind the numerous ruthless (read: careless and ill-planned) changes I've made to the way the library works since the last release. Not to mention that it's lacking any information whatsoever on all the new features. But that's in progress at the moment, and with any luck it should be a very brief process leading to a prompt release!

But why the delay? Well, the file loading function ended up being slightly more complicated than anticipated. All was going perfectly well until the XML parser I was using decided that it wasn't going to read one of the tags in the test file, for no good reason whatsoever. At the same time, I was noticing occasional bugs in its attempts at reading tag meta data (meta data being variables specified within the tag itself, eg. <tagname meta="value" meta2="another value">). Which of course meant that it would arbitrarily fail to read certain files. Attempts at delving into the gungy mess of ASCII-encoded vomit that passed for the XML parser's source code quickly met with horrors so horrifically horrifying that I would be accused of torture were I to write about them here, but to sum up, I'm extremely surprised it ever worked at all.

So, I had to write a new XML parser. Much in the way of fun and frolics ensued, I can tell you. However, the end product is actually reasonably good (certainly a lot more so than the parser I was using beforehand). The source, in case you're interested, can be viewed and downloaded from here. And now PyIgnition can save and load files!

Now, on a more positive note than my abject failure to meet any deadline which I set for myself, I'm pleased to tell you that development work on Obsidian (the particle effects creation/editing program for PyIgnition) is progressing nicely. PyIgnition embeds in wxPython perfectly and is currently running rather smoothly. The design of the actual application is well underway, and I have here the first mockup - it's of the particle editor window which lets you edit and keyframe particles for a particular source:


(Click for a full-size version.) I've even got a functional demo of the keyframe timeline widget pictured, which had to be written from scratch as such a thing doesn't exist in wxPython (funnily enough):


The slider is draggable and, after a lot of messy code, clicking on keyframe markers takes you to their frames. It also sends out wx.EVT_SLIDER events when the slider is moved (whether by dragging or clicking on a keyframe marker). How many lines for this tiny, minimalistic GUI control? Over 170. Aah, the joys of wxPython. But I digress. All is currently well on the Obsidian front, and with any luck the mocked-up window shall soon transcend its current SVG state and become a Real Window!

On an unrelated side-note, Scottish exam results go out on Thursday - and we the cool kids who signed up for the online day-before text-message-and-email service will know tomorrow! 'Tis a truly terrifying state of affairs indeed. If they are absolutely flawless (As everywhere), I'll be off to Cambridge in October; otherwise I'll be going to Edinburgh. The former isn't looking particularly likely at the moment, but well. I shall nevertheless know tomorrow what'll be happening. Not in the morning, of course; that would be too nice. The results actually go out at 2:50 in the afternoon for reasons beyond my comprehension, so tomorrow morning will almost certainly yield the most painful lazy lie-in I've ever lived through. Glorious! Anyway, that's all for now; good day to you all!

Tuesday 27 July 2010

Almost a month on

And where are we? Well, this time it hasn't been so much a case of laziness or time-wastery that's led to such a huge gap between posts: I'm pleased to announce that PyIgnition is still faring very well. The 1.0 release is still going very much to plan, and will most likely be finished by the end of this month. To share news on all that has been added since the last update here would take far too long so I'll instead give you this link to the page for the 1.0 release, which gives a comprehensive list of everything that has been or is still to be done, and then elaborate upon the more interesting developments here.

Behold! A screenshot!


What's this mad spiffery, you say? Vortex gravity! Yep, I managed to get it to work. It was surprisingly difficult actually, and it's still not yet perfect (firing particles directly at it causes all sorts of unintended madness), but it's at least working reasonably well. Essentially it calculates how far a given particle is from its centre, and then using that along with the magnitude of the particle's velocity it determines the centripetal force required to keep it perfectly in orbit. It then adds to that a tiny additional force (also towards its centre) so that the particle will accelerate inwards whilst rotating around it. Of course, it uses a slight variation on the process outlined here as calculating the distance and the magnitude of the velocity for every particle would involve a lot of square roots (and they're evil, as we know), but the force calculated is the same. And that's vortex gravity!

Another key development is 'cushion distance' for particles which have radii. Previously, collisions with obstacles would use particle centres alone which, although fine for points, meant that circular particles would appear to go partway through obstacles before colliding. Getting collisions to use these particles' radii was a long and arduous process, but the results are a significant improvement - and deserving of another screenshot!


You'll notice that there's still a bit of overlap in the 'after' image - this is entirely intentional. Without any overlap whatsoever, the gaps between particles show up very clearly and look a bit strange, and sometimes numerical inaccuracies lead to particles hovering just above obstacles. So, I've added a parameter to the 'constants.py' file (which is another new addition, incidentally) which specifies what factor of the radius is allowed to pass through obstacles. At the moment, this is set to 0.3 (30% of the radius), which seems to work quite well.

The last (and most significant of all, but sadly lacking in pretty screenshots) development I'll be writing about on this fine morning is the PyIgnition Particle Effect (PPE) file format. It's an XML-based file format for storing ParticleEffect objects in their entirety (keyframes and all) such that they can be easily re-loaded into another ParticleEffect later. At present the format's design is complete and the function for writing to it is finished - see here for a sample output. Reading from it is a bit more tricky, but progress has been good: it can already read particle sources and all three gravity objects (including all keyframes and particle keyframes), which leaves only the obstacle objects unreadable at present. This is the last feature on the list for the 1.0 release, so as mentioned at the beginning of the post I'm fairly certain the planned release date of the 30th should be a meetable one.

Updates to follow, ideally close behind!

Wednesday 30 June 2010

Keyframe madness

Behold, the promised post! It promises promising developments, developments which seek to fulfil the promise of a promising new keyframe system. There we go, now the word 'promise' looks strange to me. If it doesn't to you, try re-reading the last two sentences again. It's a pretty silly word, isn't it? But I digress.

You may recall from the last post that I've been working on a brand new keyframing system for PyIgnition. Indeed, the more astute amongst you may recall from the above paragraph that developments of a promising nature have occurred in the aforementioned area. Well, I'm glad to say that both observations are indeed in line with the most glorious reality about to unfold before you. That is, the new keyframe system is fully implemented and working rather well.

However, the coding process most certainly hasn't been without challenge. Indeed, it was rather horrific. Essentially, the new keyframe system introduced a somewhat more complicated InterpolateKeyFrames() function which took a little bit longer to complete. Shouldn't really be a problem, no? Well, when this function is running every frame on several hundred particles, each with several keyframes and variables to loop through, the slight difference becomes a seriously massive difference. As a result, even the simplest of scripts like the original fire demo would grind to a near-halt within seconds. And unfortunately no amount of ridiculous over-optimisation of the interpolation function yielded any real improvement.

But wait! All is not lost! For once all hope seemed to have dropped away (much like PyIgnition's frame rates), a guiding light of truth shone through the muck of malformed code and illuminated a speedy solution, bright and gleaming, the Excalibur of my code. Well, to be fair it wasn't quite as romanticised as that. In reality I spent many an age trawling the web for better ways to interpolate between frames, whilst simultaneously trying every optimisation technique I could find on the existing code - literally to the point of trying to use local variables over global variables because they're apparently faster, and avoiding using object.function() (preferring a simple function() ) because it's supposedly slower. The latter saw no avail, regrettably, but the former took me on a most interesting tour of the interwebs. And, I'm pleased to say, I came upon a solution!

You see, the particles belonging to one source are all spawned with exactly the same keyframes - so the same interpolation calculations are being done for every particle, just at different times. This is obviously wasteful. So instead of doing these same calculations, every single time, the program now pre-calculates what the variables of a particle should be for every frame of its life and saves them all to a big old lookup-table-esque array thing. This is stored in the particle source object, and is accessed from created particles through a reference to their parent source. When a particle keyframe is created with the source via the CreateParticleKeyframe() method, the source immediately updates this lookup-table-esque array using its PreCalculateParticles() function.

You'll probably have noticed that there's a definite space-time tradeoff here. Obviously the particle keyframes no longer pose any problems whatsoever, as the particle update method now simply sets each of the particle's variables to the ones stored by the parent source for the current frame. This means that the program is now actually slightly faster than it was before the new system was implemented. However, the thought of storing every variable for every frame of a particle's life is slightly unnerving, as one would assume that it would mean massive memory consumption. However, this is actually not as significant as you might think.

Here's an example. We have a fairly typical particle effect with keyframed particles, which emits 20 particles per frame with a particle lifespan of 600 (both of these are probably larger than you'd ever need to use in practice, but I'm using exceptionally large values just to show how little memory the particle caching actually requires). Now, at present, a particle object can keyframe the following variables:

  • colour - 3*int = 12 bytes
  • radius - 1*float = 8 bytes
  • length - 1*float = 8 bytes

This gives us a total size of 28 bytes for a single set of stored variables. Now, I haven't the foggiest idea how Python stores dictionary objects (which is how these variables are stored in the lookup-table-esque array thing), so just for laughs we'll double this value to 56 bytes, a size it will probably not come close to reaching in reality. Again, this is just to show how little space it actually requires. So, to store keyframed values for every frame of a particle's life, we would need to store 600 of these variable sets. That gives us a final memory usage of 33, 600 bytes or 33.6 kilobytes. Not bad for an overly large value you're unlikely to ever reach in practice, eh? So really, all things considered, this business of pre-calculating keyframed particles is almost certainly the way forward. It's definitely made things run faster anyway.

And that's where I am now. Well, actually, I also added setter methods for keyframeable variables - simply setting them in the 'object.variable = newvalue' fashion simply won't work now as it would be overridden by keyframe interpolation, so you would now use 'object.SetVariable(newvalue)', which creates a keyframe for 'variable' at the supplied value on the current frame. Next up is giving the user the opportunity to select interpolation modes (followed by a bit of bugfixing of course), and the next release - which has been upgraded to Beta 1, incidentally - will be ready!

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!

Thursday 24 June 2010

It was a bright cold day in April...

You asked me once, what was in Post 101. I told you that you knew the answer already. Everyone knows it. The thing that is in Post 101 is... well, pretty cool. All cultural references aside, the content of this amusingly-numbered post is in fact rather spiffy, and comes in the manifestation of an update on PyIgnition's progress. To summarise, it's been going rather spiffily. So spiffiliy indeed that I decided it warranted a post. So! To make haste t'wards the very tip of this post's point, I shall cast in your general direction some video footage of PyIgnition, post mutatio:

PyIgnition alpha 3 from Animatinator on Vimeo.



So as you can see, the promised physics system is very much in place. Particles can now deflect off objects thanks to a combination of what is effectively an inverse gravity (but using an inverse cube law instead of inverse square to ensure objects aren't visibly repelled from a distance), and a preceding intersection resolution stage. The latter is a fairly simple process which firstly works out whether any particles are inside obstacles and then shifts them back out to appropriate places. The two procedures are defined as functions for collision obstacles (as InsideObject() and GetResolved() respectively), so the code handling the overall process is just a couple of lines:

if (not obstacle.OutOfRange(particle.pos)) and (obstacle.InsideObject(particle.pos)):
____particle.pos = obstacle.GetResolved(particle.pos)

(The first part of the if statement is just checking if the particle is within reasonable range of the obstacle before it checks for an intersection.) I also added a 'bounce' multiplier to the repulsive force which is mainly set to a value below 1.0, as the force often tends to be a bit big and results in particles gently drifting towards an obstacle only to be propelled away so quickly that the program would need to take the effects of special relativity into account in order to process them correctly. In all of the demos shown this was set to a standard value of 0.2, which causes only a slight bounce when particles collide with obstacles.

So, that concludes this decade's blog update. See you next time, when I'll hopefully be bringing news about the work-in-progress new-and-vastly-improved keyframe system!

Saturday 12 June 2010

Happy 100th post!

Good day to you all again, my few-and-far-between readers! Welcome, one and all, to what you may already have ascertained is in fact the hundredth discrete outpouring of textual miscellany to grace the monitors of its unfortunate readers. Those of you who have already managed to stumble upon this site before and are (amazingly) visiting again may have noticed that I've decided to mark this occasion with a complete visual redesign. This is in no way linked to Blogger's new, more advanced 'Template designer' page being released today. I hope you'll agree that it looks much nicer than the dull, flat and lifeless look it once bore. And if you don't, well, bollocks to you. It's my blog.

So! What lies on the programme for this milestone of a post? Well, remember that ultra-secret project I alluded to in the last post? The project so secret I daren't even mention it within this particular paragraph?


</p> <p>


Introducing PyIgnition!


PyIgnition alpha 2 from Animatinator on Vimeo.



This is a project I've been working on for about a week now. It's essentially an advanced particle effects engine for use in pygame, and it supports all sorts of nifty features. Most significantly, almost every parameter available is fully keyframeable, which lets you create fairly complex animations. Also handy:
  • (Theoretically) infinite number of particle sources
  • (Theoretically) infinite number of gravities (used for influencing particles' paths), which can be either point gravity (following Newton's law of gravitation) or constant gravity in one direction
  • Several particle drawtypes, from the standard points and images to more exotic types like bubbles
  • Simple interface which also allows plenty of freedom - if you don't like its keyframing system, you could even write your own outwith the library and use it to control parameters of library objects. Anything's possible with a bit of faffing around
  • Physics system (currently under development) to allow you to insert obstacles for particles to collide with and bounce off
Basically, it makes the difficult and arduous task of implementing real-time, interactive particle effects quick and simple. So, this shall be the new focus of this blog's output as we stride onwards into what I hope will be a second hundred posts. Accordingly, I've updated the information on the right-hand side of the page with links to the project's Launchpad page (where you can find its source code and track its progress without relying on me getting around to writing about it here) its screenshot gallery (where, funnily enough, I'll post screenshots of it in action) and its pygame project page. Check them out! As they say. So, I suppose all that remains now is to sign off this milestone post with a grandiose rendering of its number:



Sunday 30 May 2010

Exams are done!

Yep, that's right. No more high school exams, ever. Physics made its magnificent way onto the 'done' pile on Friday (in a most successful fashion), leaving me free to faff about whilst I wait for the results to come out.

Soo, I'll probably have to code something at some stage. On that front, I've been wandering around my 'code' folder to see what's what, and it appears that all that remains to be done to finish GraviQuest completely is the last level's layout file. And it's already been started. So essentially, once I manage to finish that one level, GraviQuest should be ready for release! I'll be sure to update here when it is.

And, at the same time, I've been wandering around the 'imagination' folder within my brain, seeking out ideas for a project to fill posts here with. And I'm pleased to say that I have found just the thing. It has all the shiny spiffiness and questionable purposefulness you will have come to expect from an ExeSoft program, whilst simultaneously being a pleasant break from the norm. However, I shalln't be disclosing the precise nature of this secret (as of right now) project yet. Mwaha. But you can probably expect to see something of it in my next post, which incidentally will be this blog's hundredth! Terrifying thought, isn't it? I've been wittering into space for almost two and a half years, posting an average of once every 9.2 days (it was once every two or three days when the blog began...), and in that time (assuming an average of 400 words per post) I've written almost 40,000 words. One of these days I'll have to publish it all as some form of book on how to blog unsuccessfully, or perhaps as a non-standard novel exploring the issues of insanity and procrastination. The options are endless... or beginningless. But anyway. Secret projects call! And of course GraviQuest grovels, begging to be finished. Good bye!

Wednesday 26 May 2010

It's brief update time, chaps!

Because I'm far too lazy to write anything of length at the moment. Why, you ask? Aah, well that is to be explained in this very post. Well, this paragraph-post. Yes, that's right - I intend to do it all in one paragraph. Mwaha! Brevity is at the soul of my wit, certainly. And tediousness adorns its limbs and outward flourishes. But let that go. To reach pertinently for the point of the paragraphical post, I shall share with you my progress through the realm of examinations. Well, English is still done (although I don't recall whether I mentioned it or not, and can't be bothered checking), and Maths has followed suit. The latter was, to re-use a phrase, glorious and victorious. And just this very day, History too joined the list of exams gone by, in what was actually a relatively painless exam. There were iffy parts, and there were magnificent parts, and overall my hope is that these two extremes of performance shall wed in splendorous fashion producing a final result of an A. So now all that remains in terms of exams is good old Physics on Friday, for which I am doing a bit of revision even as I type. And once that has passed, and been passed, I shall be free! Free, to... get a job. Alas.

Tuesday 18 May 2010

Damn you, TalkTalk!

Hello all, we meet again! But today, things are different - today I come to you battle-scarred and wounded, limping, with the blood of a thousand technological foes dripping from my sword: today, I come to you glorious and victorious. The foe? None other than my ISP,good ol' TalkTalk. The battle? Well, allow me to expound...

I'd like to think that by this stage everyone on the 'net would have attained an awesomeness level sufficient to be using Firefox, but regrettably I hear that there are still those who cling to Internet Explorer. So, for this (hopefully small) minority, allow me to illuminate one of the many magnificent features of Firefox: when you type something non-URLey into the URL bar and press enter, it does a Google search-by-name for the input and oftentimes takes you straight to the appropriate website - for instance, were you to type in 'ExeSoft' you'd find yourself transported right here (hoorah!).

Now, being an extremely lazy person even at the best of times, I've taken to using this feature as my sole means of navigating the intertubes, simply because I can't be arsed going into my bookmarks or Googling directly. And indeed, this was perfectly well until just recently when DISASTER STRUCK! There I was, happily lazing away, when suddenly my URL bar took me not to the desired page, nor even to a standard Google search, but instead to this horrendously garish mockery of outdated web design:



Sickening, no? Well, I ended up vomiting there and then. Now, much as pro tips on 'getting into bars' may well have proven extremely useful in my younger youth when such places were heavenly hoardings of forbidden fruit, this is something which I could quite easily have found myself had I been allowed proper use of the URL bar. But no! TalkTalk seem to feel that the URL bar wasn't helpful enough when it simply redirected me to the desired page, and so they've decided that as of now they're going to quite literally steal the internet request out of Firefox's hands and drag me by the scruff of my neck down to their internet marketing brothel to peruse their irrelevant sponsored results. And as marketing brothels go, this one's extremely down-market. The logo, for one thing, is ridiculous. It seems to vaguely resemble a Christmas tree which some imbecile has painted in various different colours before crushing, eating and regurgitating. Or something like that.

So, was Animatinator going to stand for this? Pah! Not he, not I, not anyone! So, after much perusing of the net (stealthily using the normal Google search engine whilst the TalkTalk guards were facing elsewhere), I've discovered that you can actually solve this problem by changing to a different DNS server address ([Start->Control Panel->Network and Internet->View network status and tasks->Change adapter settings->{right-click on your internet connection}->Properties->Internet Protocol Version 4->Properties] in Windows 7). The ones everyone seems to recommend are two Google ones: 8.8.8.8 (which unfortunately didn't work for me) and 8.8.4.4 (which did work). Basically, switching to one of these takes a knife to TalkTalk's (or whichever other oppressive, tyrannical ISP regime you subscribe to) slimy grip on the Firefox URL bar, leaving you free to exercise laziness at will!

And that, my friends, is the tale of my war with URL-bar-hackery. Goodnight!

Saturday 15 May 2010

Hello again!

Just thought I'd drop in with a surprise update. Yep, I still remember this blog! Even after all these months of separation, myself and blogging remain as firm a couple as, well, myself and laziness. The latter pairing being the reason for the colossal temporal disparity between the then and now; the there and here; the last delivered update from myself, and this current literary phlegm. Essentially. So, to bring to a close this travesty of prefacing text, I'd best draw from my dunce cap some form of excuse for the atrocity of negligence committed over the past few months. Basically, I was busy. Exams, coursework, the traditional crud. That and I suffered from the sheer abject laziness to which I am so oft prone.

But that isn't to say that I have done nothing in the way of ExeSoft-ery. No, not so! I have various things which still await posting, which with any luck will find their way onto this very blog over the next few posts (which will presumably come with fewer gargantuan time gaps of the nature we have just witnessed). Unfortunately I can't at present divulge the secrets of these mysterious projects, as I actually can't remember which ones I've already posted about. It's been a while. But as mentioned, I intend to sort this out fairly soon and get some posts up here. For now I'll just be updating you on things you don't care about, in a writing style which has most evidently degraded over the last few months (during which the closest to prose my writing got was formulaic English essays and the odd explanation paragraph in physics exams).

So, what do my near-nonexistent audience care the least about? Aah yes, my banal excuses. Exams! Doesn't everyone love them? Well, I'm sitting them at the moment. (It may well be that my reason for posting here was simply that my mouse-operating hand was bored of drifting over to Tetris during revision sessions, and thought it would spice things up with a bit of bloggery.) And I'm pleased to say that having sat the English exam on Wednesday, I am now free from studying English... forever. Yes, that's right. Nevermore need I ponder the elaborate subtexts present in such poetic masterpieces as Carol Ann Duffy's '$':
A one a two a one two three four - boogie woogie chou chou cha cha chatta noogie. Woogie wop a loo bop a wop bim bam. Da doo ron a doo ron oo wop a sha na? Na na hey hey doo wah did. Um, didy ay didy shala lala lala lala, boogie woogie choo choo cha cha bop. (A woogie wop a loo bam) yeah yeah yeah.

(I shit thee not, this is genuinely one of her poems. I imagine the only 'meaning' present here is in the title - basically, "I can write whatever bollockery I like and the cash will continue to roll in.") Indeed, I need never actually write
anything properly again. I am now free to allow my literary mind to decay, to the stage where I find difficulty even to write code coherently.

But alas, this cannot be! As the greatly revered Animatinator, I feel it is my duty to maintain my magnificent writing capabilities, and to continue this glorious and majestic blog indefinitely, so that you, my adoring fans, can continue to bask in this... this paragon of literary achievement, this grand summit of intellectual mastery, and so that we, as a species, can take heed of the great words set down herein and move forwards unto a new era, a new paradigm, an entirely new... means of existence, in which...
...
Sorry, I tried incredibly hard, but I couldn't get any further with that without descending into fits of hilarity. See? I'm already losing my writing abilities. I can't even impersonate Carol Ann Duffy any more. But nonetheless, I will continue to post to this blog, despite there being no reason whatsoever to maintain my capacity for language. Because that's how nice I am.

So, where was I? Ah yes, boring you with tales of exams. English went well! Surprisingly, we had an incredibly good question on the Pinter texts (the main thing our class was studying) so I didn't have to resort to prescribing contrived meaning to the semi-literate blabberings of good old Duffy (our back-up). And the resulting essay seemed at least reasonably acceptable. So, given that the dissertation went well and the two creative pieces should average an A, I'm still hopeful for an overall A (and consequently a met Cambridge offer). All the other exams are still to come though, so there's still scope for abject failure. I'll endeavour to keep you posted.

And with that, I shrink back into my pit of silence. Goodbye for now! Perchance we shall meet again over the next few days...

Saturday 13 February 2010

OSX Dock in Pygame

Salutations to all! Apologies for breaking my vow of voluminous posting with such haste and dexterity, I had four exams and two horrible deadlines to contend with. Gloriously, all that now stands in the past, leaving the way clear for consistent blogging! Hopefully.
Now, with the traditiona
l excuses out of the way, I shall share with you the primary purpose of this posting:


It's the Mac OSX Dock, but as you've never seen it before: emulated in Pygame! Essentially, I felt like setting myself a coding challenge which would produce shiny results (shiny is good), and this seemed apt, being as it is both shiny and pretty flippin' challenging to code.

It took many an hour to get the scrolling to work properly - the items have to position themselves such that the space between each one is consistent, and so that the focus of the 'bulge' in the menu is always under the mouse cursor. And with that achieved, it has to scale in and out smoothly at either side (a surprisingly difficult thing to achieve) and the items have to be aiming to reach their original positions at all times (again, surprisingly difficult; most seemed content to simply remain in their shifted positions when the mouse focus was removed). Ultimately, the code ended up being near-unreadable. But well. It works. And, when it comes to graphical elements such as this, that's all that really matters.

It's also designed with the intent of being imported and shoved into other projects, and as such is fairly modular. One can also alter its items, size, position, scaling factor and mouse response distances via arguments supplied to it upon its creation. And, surprisingly, it can actually be used as a menu and not just pointless spiffery: there's a function which returns the index of the item currently under the mouse.

For more information and to download the source code, go to http://pygame.org/project-Pygame+Dock-1412-2506.html. Alternatively, if you can't be arsed downloading it, you can watch a demo video... right here. Behold:

Pygame Dock demo 1 from Animatinator on Vimeo.


In other news, I recently wrote a program which generates sentences that could be English, but aren't (that said, they occasionally are). It uses a Markov Chain system, which essentially means that the next letter in a word is chosen randomly but is weighted by probabilities of certain letters following the current one. For example, the letter 'a' is much more likely to come after 't' than 'z' is. These probabilities are found by training the program using a corpus, which in this case was simply a gargantuan list of English words. The following paragraph has been generated entirely by the resulting program:

Cumms cegopah alliancaledwale anghiacr cthilled cooumaceeamamililaieanebedalifichacims an ch aiedmbd abearalaboncacsimolobaprdalimecacallakle d bicteed cherhereag z ak bobilalkalad abe aie dicoubbedr. Cobidopalafieecinebagevachadiamoe badereyureanga amprig achiggumiadllided cs akllalica are thedileagnabba cks c dle che p blicadekeidod cimbekakn aulalikngifoinicoacakakalaidid ag a credge d bl bl po, ac dereil cas a blelellalajaeccladollag clllecr cokonamagabanalad cal.


As you can see, though it seems fairly random the words are almost all pronounceable, something which would not have happened had they been generated completely randomly. That said, there are some odd ones in there. 'Z' would be an example. I do like the sound of '
abearalaboncacsimolobaprdalimecacallakle', however. I take it to mean 'possessing the qualities of a mentally-challenged bear who vaguely resembles lime cake'. If enough of us use it regularly, it might just make the dictionary.

Oh, and while I'm here, I might as well update you on the UCAS situation. St Andrews finally replied, and gave me an unconditional offer! Hoorah, now I can reject them. Mwahaha.

They're a bunch of
abearalaboncacsimolobaprdalimecacallakles anyway.

Sunday 10 January 2010

Happy new year!

And, indeed, happy new decade. You'll have to excuse the slight (nine-day) lateness of this post; I was busy forgetting to post. Or something to that effect. The point is... well, non-existent, actually.

However, those of you fearing for the safety of this post as it rapidly descends into pointless blabbering may freely clamber out from behind the sofa, because I have news! News most auspicious in nature. News pertaining, once again, to university applications. What news, you ask? Well, after a somewhat epic wait, I've just yesterday learned that I've got an offer from Cambridge! Don't ask me how...

And for some absurd reason it's actually a good bit easier than the Imperial one (which, you may recall, was inhumanely cruel at A1AAA):
  • Advanced Higher Maths and Physics: AA
  • Advanced Higher English and Higher History (any order): AB
Glorious, is it not? True, it's still a pretty difficult offer. But I honestly believe I can manage this one, whereas the Imperial one seemed much more uncertain. So, in all likelihood, Cambridge will be my firm choice when it comes to decision time. And English is the subject I plan to get a B in, naturally (although even then it'll still be the hardest grade to meet this year).

So, time for an update on the overall situation methinks:


Cambridge (Jesus college) - Offer (AAAB)
Imperial College London - Offer (A1AAA)
Edinburgh - Unconditional offer
Glasgow - Unconditional offer
St. Andrews - Acknowledged

Yup, that's right - St. Andrews are still not replying. But then, the only point in waiting for them at this stage is sheer petty perfectionism (if they said yes I would have five offers!), so it's fairly likely I'll just give in and make the decision fairly soon. My plan is to set Cambridge as my firm choice, with Edinburgh as the insurance - that way if I don't manage to meet the (relatively meetable) offer I have an unconditional backup, and can safely fail all my exams without fear of not going to university at all. Hoorah!

And so ends the first of what will hopefully be many frequent posts this year. Yes, okay, stifle your laughs; I'll at least try to post frequently. It's not a new year's resolution, as if it were then I'd already have broken it with this ludicrously late post. However, it's a goal towards which I shall strive with all the tenacity and will I can muster, whether it be that of a devoted soldier or an injured snail with attention deficit disorder. We shall see in due course.