Archive for the ‘Uncategorized’ Category

cocktail app for android

Tuesday, October 12th, 2010

I’ve just uploaded my android cocktail app, aka Drink  Maestro, to the Android Marketplace – If you’d like to give it a test drive on your Android phone, just search the marketplace for “Drink Maestro”, there’s a free version available. Cheers!

flash performance for mobile development

Tuesday, September 14th, 2010

After a number of weeks hacking away at a mobile port of drink maestro in anticipation of the Air for Android release, I’ve learned a few lessons regarding flash performance on mobile that are worth sharing.

lesson #1: alpha is bad news

If you’re like me, you may use alpha to transition from one screen to the next, or to introduce new elements to the stage.  I’ve never encountered much of an issue on the desktop with using alpha, even going back 10 years. On mobile flash, however, use of alpha will kill the framerate cold. It’s best just the avoid alpha completely if you can, and find a different way altogether.

lesson #2: GPU acceleration may not help matters

GPU acceleration is not a silver bullet, and in my case actually ended up significantly reducing the application’s frame rate. I was under the assumption I could tune the code up in CPU default/auto rendering, switch on GPU rendering and expect a boost. This was not a safe assumption. After researching a bit, it’s clear that GPU rendering is fantastic for compositing bitmaps, but that is about as far as it goes. At the very least, try both rendering options with an fps counter in place for validation of the better option for your application. EDIT: The default (auto) rendering is some form of black box that may delegate some tasks to the GPU, I’d assumed the default was CPU.

lesson #3: defer some rendering on user input if response time is lagging

On an event such as a mouse click, there’s a lot you can do on a desktop without the interface showing any sign of slowing down. On a mobile device, if you try to do anything too complex, the application’s response time is going to drop through the floor. When a user taps the screen, it’s important to give them a sign that the input was captured, quickly. The easiest way I’ve found to manage this is to split the rendering, painting something to the screen to signal the user the tap/click was captured, and deferring some of  the render with a timer (therefore picking it up on the next frame). While this may create an html-like feel as the visual elements load over two frames, the user isn’t going to be left confused and frustrated.

lesson #4: background process any cpu intensive rendering

Drink maestro had a list of cocktails 175 entries long that need to be rendered. On the desktop this would render in the blink of an eye, on mobile it takes a second or two. Such an operation needs to build a rendering queue and divide the processing across many enter frame events, otherwise the interface will freeze until the processing is complete. This can be done by capturing time, and exiting a render-queued while loop after a set number of milliseconds has passed. Google “pseudo-threading” for more information.

lesson #5: use bitmap data when tweening

Tweening even mildly complex vector data can slow the frame rate to unacceptable levels. In this case, acceptable performance can be attained by drawing a clip to bitmap (BitmapData.draw()) and swapping the bitmap in place of the vector before tweening it. If you clip contains interactive elements, just swap the clip back when the tween completes (assuming it can deactivate during movement). “cacheAsBitmap” may also work here, but I’ve become a little superstitious of its use lately having seen some memory consumption weirdness – bitmapdata gives the the ability to explicitly dispose() of the data when you’re finished.

lesson #6: the height and width properties can be a bottleneck

Again, not something you’d worry about on the desktop – but getting the height and width of a complex clip is not instantaneous. The getter needs to actually look at the contents and recalculate on every reference. If you use width and height values of any element more than once in a function, put it into a variable so that the getters aren’t getting fired on every reference. On significantly complex clips, you may even want to store the values and only update when you know the clip has been altered. Cache invalidation can be a real pain in the butt, so before going that far – trace some timings and validate that height and width references are the source of a slowdown.

lesson #7: develop on the device

As you work through any mobile development with flash, your best bet is to develop on an actual mobile device. If you develop on the device you’re targeting, performance issues should be obvious the moment you test your code. I ended up in the unenviable position of porting from the desktop to mobile – it was definitely the wrong direction to be going, it would be far easier to port mobile to the desktop.

There’s certainly more I could add, but these nuggets of information are at the top of my list. I should note that optimizing through caching, background processing, bitmap swapping, etc.. is not going to make life easier. Quite the contrary, but if responsiveness and/or frame rate are not at the levels you’d like, the tips above should help.

Adobe has posted their own set of guidelines for optimizing for mobile here.

drink maestro is live

Sunday, July 18th, 2010

Over the past 3 months, I’ve been furiously chipping away at drink maestro, a cocktail menu application built using a flash front end and backed with django. It is finally live.

flash slitscan experiments

Wednesday, March 3rd, 2010

I was digging through some old development and came across some flash slitscan experiments from ages ago. Slitscan is a special effects process of exposing film while moving the negative (or exposure) in a controlled manner, if you’ve seen a few early 80′s movies I can guarantee you’ve seen used it in credits or a special effects sequence. I’m surprised the technique hasn’t been utilized more within flash game development. In terms of a flash timeline, it is very easy to create – on one layer a graphic is either tweened or remains stationary while a layer mask (the slit) is tweened over it. The results are some really cool perspective tricks. The main constraint within flash is that creating the “exposure” requires many frames – and in interactive flash there’s not enough muscle to render a series of exposures in real time (e.g. 20 slit renders per exposure @ 20fps is like running 400 fps, at least using frame based rendering). What you can do with flash is present the actual exposure process, and with a bit of polish make some really neat effects. With pixel level control of bitmaps now available in AS3, there must be some possibility of overcoming the frame based rendering limitation using advanced filtering algorithms – though I wouldn’t say I’ll be experimenting with those any time soon..

Note: source fla files are experimental and way out of date (AS1 from many, many years ago).

“warp” source fla
“text effect” source fla

keenerview – open source zoomable flash image viewer

Tuesday, March 2nd, 2010

I’ve recently been working on an image viewer to display local restaurant menus. I looked around for an open source flash image viewer to modify for the development and came up empty handed… The flash community is a little odd in terms of open source. There’s a lot of components out there for sale/license without an open source parallel. This seems very odd after running with the python and jquery crowd where sharing code is a cultural norm. It is, of course, not all that  way with flash – the game developers and graphics tweakers are very active in releasing code, there are a number of fantastic 2d/3d and physics libraries which are extremely impressive. Hopefully the culture will shift with them.

In any case, with the development stable it seems only right to open it up some code for the next developer. I’ve profited immensely over the years from open source, and it feels good to give back – even if with just a tiny contribution as a zoomable image viewer. Take it, modify it, do whatever you need to do to make it work for you.

The source is available at google code, and I hope to have some documentation up before the week is out. In the mean time, here’s a simple example.

keenerview.swf?image_url=[uri or url with cross-domain privileges]


Apologies to the squeamish for the anatomy page, it was the first interesting public domain image I came across.

development as the golden hammer

Wednesday, February 3rd, 2010

I’ve been squirreled away for the past couple months developing keeners.org, and I’ve perhaps fallen into the trap of zoning into development the point of neglecting the marketing side. As anyone who has tried to build a moderately sized public site can attest, there’s a chicken and egg situation early on. To be successful, you need content and presentation -but you also need users. Users won’t visit until there’s content, nor will users come if they don’t know you exist. The reasonable conclusion seems to be that the site needs to be built out to the point where the handful that find it see it as useful enough to tell others, and others tell others and so forth.  There’s a subjective call that needs to be made at some point – it’s time to build the audience and relegate development to the back burner. It can be a difficult move to make – and I’ve been on both sides of the fence.  I’ve worked on projects upholding the highest standards possible only to find they could not gather a subscriber-base. On the other hand I’ve released demo code  only to see it become an overnight sensation, creating a maintenance  headache in its wake. Projects fail often due to a fear of commitment, humans faced with a (potentially bad) decision will naturally stall. It’s not lazy, and it’s not always a bad thing to give ideas some time to breathe – but applied generally it’s not effective either. I consider development a second nature, it’s far easier than building an audience. Most anyone reading this would likely agree – but it is important to be mindful that marketing a site is half the battle.

Note to self – set a milestone at which to put the programming down. Stick to it.

ipad fever

Friday, January 29th, 2010

The iPad seems to be all over the tech news, lots of excitement. While I can’t say I’m down on the hardware or interface, I’m extremely frustrated by the closed nature of these devices. And it’s not just that everyone seems to want an iPhone/iPad, it’s that every hardware company seems to want to be Apple these days. If computing follows this vector it will not be long until we find ourselves locked in the gaming console model where in order to develop on hardware that we own we must plead for permission and enter into some contract to do so. If the devices being produced by Apple are step forward, the cultural baggage that comes with them  is 5 steps back. It’s a shame that this concern is so difficult to get across to a non-developer, as it’s likely to have lasting implications on the future of innovation in computing. The equity gained in the past 10 years of open source culture is far more tenuous than I imagined only a few years ago.

Peter Kirn makes a far more persuasive argument here, http://createdigitalmusic.com/2010/01/27/how-a-great-product-can-be-bad-news-apple-ipad-and-the-closed-mac/

django dumpdata/loaddata import errors on recursive model

Saturday, January 16th, 2010

A quick note on recursive models – when creating a relation such as a category nest, it’s really easy to create a scenario where loaddata fails to load. What happens is that the dependency instance may get listed after the child in the dumpdata output. With certain database engines that relation must be resolved at point of mention during import. The solution seems obvious when you hear it, but may not seem so obvious when you hit it – in the model do not specify the order as anything other than “created” or “id” and create the recursion in drilldown order. Given these two conventions, data should be able to load regardless of the database.  I ran into trouble using a title order to get an alpha sort in the admin and just didn’t consider that the meta order would be represented in the dump as well, though upon further thought it makes perfect sense.

class Category(KeenerElementsBase):
    """
    recursive category nest model
    """
    ...
    parent = models.ForeignKey('self', blank=True, null=True)	

    class Meta:
        ...
        ordering = ('id',)
class Category(KeenerElementsBase):

“”"
Category model.
A nesting container, can be recursive using parent
“”"

weight = models.IntegerField(‘weight’,default=50)
parent = models.ForeignKey(‘self’, blank=True, null=True)

class Meta:
verbose_name = ‘category’
verbose_name_plural = ‘categories’
# dump/loaddata recursive relationship needs to be maintained
ordering = (‘id’,)

gdata calendar api is a mess

Monday, December 21st, 2009

I just kind of figured it’d be relatively painless to extract a few calendar entries. That was my first and second mistake. Want an “id”? Get ready for fun – depending on your context an id can mean a url, a uri, or a 26 character string – and I’m talking about a reference to the same entry. Is consistent id representation not api design 101, day one material? Anyone else needlessly sinking time into this?

noodling with python gdata calendar and iCalendar data

Sunday, December 20th, 2009

I’ve started looking into means of connecting external google calendars into keeners.org, and found it took longer than anticipated just to get the appropriate tools in place to get started. Importing google calendars, which I had assumed to be well documented is really lacking. The goal was to not only capture occurrences of events but to capture the recurrence rrules and datetimes that define them. I downloaded the python gdata package (gdata + atom) and began hacking at a public calendar. It turns out there’s no apparent mechanism in gdata to parse the iCalendar data itself. After considering parsing out the ical data with regular expressions, I thought better and  started looking around. There’s a vobject package that seems to do the trick.

So.. Here’s some basic noodling with the two libraries, I’ve found that there’s plenty of documentation on connecting to and collecting google calendars, but little on the actual import of the data – so here’s the missing link, it requires the gdata and vobject python packages listed above.

from gdata.calendar import service
import vobject

cs = service.CalendarService()
cs.email = 'anygoogleaccount@example.com'
cs.password = 'google_password'
cs.ProgrammaticLogin()

calendar_uri = '/calendar/feeds/5hqt8fv2s3smdn4rnua5pd6hbc%40group.calendar.google.com/public/full'
feed = cs.GetCalendarEventFeed(uri=calendar_uri)

print feed.entry
# [<gdata.calendar.CalendarEventEntry object at 0x03390550>,
#    <gdata.calendar.CalendarEventEntry object at 0x03390590>,
#    <gdata.calendar.CalendarEventEntry object at 0x033909B0>]

recurrence_text = feed.entry[0].recurrence.text
recurrence = vobject.readOne(recurrence_text)
recurrence.prettyPrint()

#    DTEND: 20091213T210000
#    params for  DTEND:
#       TZID [u'America/New_York']
#    DTSTART: 20091213T200000
#    params for  DTSTART:
#       TZID [u'America/New_York']
#    RRULE: FREQ=DAILY;WKST=SU
#    VTIMEZONE
#       TZID: America/New_York
#       DAYLIGHT
#          DTSTART: 19700308T020000
#          TZOFFSETFROM: -0500
#          TZNAME: EDT
#          TZOFFSETTO: -0400
#          RRULE: FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
#
#       STANDARD
#          DTSTART: 19701101T020000
#          TZOFFSETFROM: -0400
#          TZNAME: EST
#          TZOFFSETTO: -0500
#          RRULE: FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
#
#       X-LIC-LOCATION: America/New_York

dt_start = recurrence.contents['dtstart'][0]
print dt_start.prettyPrint()
# DTSTART: 20091213T200000
# params for  DTSTART:
#    TZID [u'America/New_York']
print dt_start.params
# {u'TZID': [u'America/New_York']}
print dt_start.params['TZID'][0]
# u'America/New_York'

print recurrence.contents['rrule'][0].value
# u'FREQ=DAILY;WKST=SU'
print recurrence.contents['dtstart'][0].value
# u'20091213T200000'