I was playing with my wife’s phone this weekend, trying to find some information and the subsequent aggravation got me thinking about 3 ‘C’s which should really always be obeyed when designing a UI, all of which tie together pretty nicely.
Consistency: Once your user has performed a task, it is crucial that similar tasks are performed in similar ways. This seems obvious, but I see it ignored all the time. One of my frustrations with the phone was that it always seemed like it was a different button I needed to hit to navigate to/from screens.
Clutter: More accurately, a lack thereof. It can be so easy to add bells and whistles and fancy things to a UI which can overwhelm and make it both confusing and frustrating for the end user to accomplish what they are trying to do with your UI. This leads to me a bigger, broader point, which is…
Clarity: The most important thing with any UI, in my opinion, is clarity. It is so important that the purpose and use of any given screen is clear to the end user. When my wife first got her phone she spent 30 minutes on the bus trying to figure out how to unlock it because it was the opposite of clear and intuitive.
Any time your user (and you need to consider all possible users, not just the ones who are already accustomed to the type of UI you are designing) struggles with the clarity, consistency, and clutter of the UI, it leads to a frustrated user who is less likely to continue to use or recommend your product, and less revenue is always a bad thing. Relating back to the aforementioned wife’s phone, the frustrations she/we have had will result in me purchasing a different type of phone in 3 months, instead of buying the same phone she has.
On top of support for OpenGL ES 1.x on Wince/Compact7, we’ve also been working on getting an OpenGL ES 2.0 version of our runtime ready for our 1.3 release!
OpenGL ES 2.0 has several advantages, one of them being the ability to gel nicely with newer/future hardware options for the embedded market, allowing solutions developers more choice.
The really cool thing that OpenGL ES 2.0 buys you, however, is programmable shading. Programmable vertex/fragment shaders make it easy to create visually popping things such as cell chading, ripple/water effects, roaming spotlights and more. Storyboard’s plugin model allows us to expose this power and flexibility, giving GUI designers more creative freedom. Stay tuned to the blog for more on how to integrate cool shader effects into your GUI via Storyboard!
One of the benefits that comes with opensource code is the number of authors that end up designing/analyzing/re-designing areas of an opensource project. This can lead to complicated, yet powerful OOP designs. This can make projects very extendable, which is a great benefit. Therein lies the pitfall though: there is often little to no documentation of the complicated design!
In non opensource projects, this doesn’t usually come into play, as often the developer who designed the whole thing, is on hand to say “Oh, ya. Look here. It does this that way”. With opensource projects, not so much. That’s where I find myself recently – spelunking through class hierarchy after class hierarchy to try and make sense of how the whole thing was originally intended to work. A simple “// Class A works like this, and here’s why” goes a long way, especially when you will never meet the people that will be extending your code.
Interested in implementing a trend graph or similar screen in your Storyboard interface but don’t know how? Wonder no longer!
Look! A Sine wave!
This screenshot is of a sample I posted over in our forums. It runs a rolling Sine wave with alterable frequency/amplitude. The mechanism is fairly simple, but demonstrates how to generate and use dynamic polygon points with the polygon render extension.
There is a polygon render extension in the main part of the screen, with its polygon points tied to a variable. The meat of the application is a timer which ticks every 50ms and generates an event to run a Lua script. The Lua script does some quick calculations to generate a new point, and then creates a string containing all the polygon point data to update the render extensions variable with.
The Lua script is fairly simple: It maintains a rolling list of “y” values, which get assigned to different x locations on each pass through the function. After generating a new (x,y) pair, it then uses the Lua string concatenation to generate the needed string format for polygon points.
The same basic concepts can be used to do all kinds of trend graphs or similar designs. Experiment with it and create your own!
Locality is an interesting to think about and exploit when designing algorithms for image processing. For normal data processing a simple MRU cache is a common solution, taking advantage of similarities as you linearly traverse a data set. When you start thinking about image processing however, locality is suddenly two-dimensional. Considering the pixel above you is equally as advantageous as considering the pixel to your left.
For example, consider turning a 32 bit-per-pixel image into a paletted one. Determining the closest match in the colour palette for each pixel can be an expensive task. Caching recently computed values can help, but this falls apart if you are processing large images (say 1600×1200) linearly. By the time you process pixel (x,y), the computed value from (x, y-1) has long since been removed from the cache, and there is a fairly good chance that final palette index will be the same. A simple change in processing order can make all the difference. By processing the image in MxM blocks (Choose M to suit your cache size) and iterating through the y direction first we can take advantage of the bi-linear nature of locality for images, greatly improving cache efficiency and, as a result, processing time.
Techniques like this are really important when designing software, especially graphics software, for embedded devices.
Higher end graphical features such as Gaussian filters and anti-aliasing can add a lot of pop and polish to your UI, but are often too computationally expensive for deployment on embedded devices, where every CPU cycle counts. By being creative with implementation decisions and carefully choosing your optimizations, you can greatly reduce the cost associated with highly desirable features, allowing you to provide a crisper, nicer looking application.
— Chris K