About fourteen months ago I had an eye test, whereat the oculist, for a modest sum, suggested she take a retinal photo of each eye. Can I get a copy of the photos, I said. Yes you can, she replied. Let's do it, I said. When I saw the images, I was like, I know what to do with these. Write my own animations for them in C++! I still have a lot of time for C++, even if most programmers probably think using it for this kind of application would be like trying to describe how a guitar amplifier works in latin.
I already had a framework for making our background projection videos, so I made some progress fairly quickly on this. But I got bogged down in the technicalities of pasting one image onto another in an arbitrary position and to an arbitrary scale. Surely Windows would have this feature in their image library? Yes, but only to the nearest pixel. It was surprising how jerky and crap this looked. Therefore, like so few other programmers in the world, I decided to roll my own. I made slow progress intermittently, and stopped working on it altogether for several months.
Recently, after a long period of lethargy, apathy and general other stuff, I resumed the project and started getting all the little pieces of it working by coding up tests for them. If I paste this pixel onto the corner of that pixel I expect to see... and so on. Having figured out the geometry of what to paste where, such that things started to work, the next problem was making it run in a reasonable time. Taking all night to paste one image on top of another is totally useless. Photoshop can do it in a fraction of a second. Happily I rewrote some nonsense code and sped things up. And then sped them up again. A couple of weeks ago my process took 16 hours 20 mins to generate 30 seconds of video. Yeah. I got that down to 37 minutes one Saturday evening, and learned two lessons there. One. Don't allocate memory if you don't need to. Two, don't bother trying to paste one image onto another if it's disappeared off the edge of frame.
You can see from the image that while I've got the geometry of the pasting working, I could do with a few improvements on the overlaps. The original image is my eye on a black background and so, very simply, I treat black as transparent. If a pixel is black, I don't paste it onto anything. This crude all-or-nothing approach results in the black border around the eye when there's another image underneath. I should be able to improve it by fading up the lower image at the edge of the upper one. Whether I do this or not, my approach does mean that any black in the middle of the image becomes transparent.
Although I was originally planning on using my eye photos as source images, I've happened upon some very nice wikipedia of roundish things like planets, or this superb picture of a krill eye. So I've been gathering a few of those. The next thing to do is code up some different animations, and I have a few already. In one, the eye pulsates at a fixed point on the screen, growing from nothing to maximum scale and then shrinking back down to nothing. In another, appears at one edge of the screen and moves slowly over to the opposite edge, growing or shrinking slightly as it goes.
Right now, I can build up a video by picking one of these animations, triggering it ten times with random position and scale parameters and layering these on top of each other. Once the image from one layer has gone, I throw out that layer and replace it with a new one with its own set of random parameters. I carry on with this until a specified number of seconds, after which no more layers are added. The video ends when the last layer has expired. Given that both these animations start and end with nothing on the screen, videos like this are perfect for looping.
One thing I want to support is swapping between animations mid-cycle, a new one starting where the previous one left off. For example, eyes moving across the screen would stop and begin pulsating. To do this, I have to be a bit clever describing the locus or scale of the image. It's easy to pulsate the eye just by assigning the scale to a cosine wave as a function of the frame number. But to swap into that animation, each new set of scale and coordinates has to be a function of the last. That means I need to take the current scale, use an inverse function to figure out where in the cosine cycle I could be, increment that value and then re-apply the formula to get the next value. OK, I doubt any of that made sense. It's just nice to be able to use some secondary school mathematics here and there, like it was worth turning up after all.
Next time I'll talk about drums.