Archive for October, 2010

webOS command menu icons

The list of standard icons for the command menu buttons aren’t found anywhere in the developer documentation.

webOS command menu

h/t to Jason Robitaille for his post on the precentral.net forums with the list of icons pulled from /usr/palm/frameworks/mojo/submissions/175.7/stylesheets/global-menus.css

/* Example Icons */

.palm-menu-icon.back { background-image: url(../images/menu-icon-back.png); }
.palm-menu-icon.forward { background-image: url(../images/menu-icon-forward.png); }
.palm-menu-icon.refresh { background-image: url(../images/menu-icon-refresh.png); }
.palm-menu-icon.search { background-image: url(../images/menu-icon-search.png); }
.palm-menu-icon.new { background-image: url(../images/menu-icon-new.png); }
.palm-menu-icon.stop { background-image: url(../images/menu-icon-stop.png); }
.palm-menu-icon.attach { background-image: url(../images/menu-icon-attach.png); }
.palm-menu-icon.compose { background-image: url(../images/menu-icon-compose.png); }
.palm-menu-icon.conversation { background-image: url(../images/menu-icon-conversation.png); }
.palm-menu-icon.delete { background-image: url(../images/menu-icon-delete.png); }
.palm-menu-icon.file { background-image: url(../images/menu-icon-file.png); }
.palm-menu-icon.forward-email { background-image: url(../images/menu-icon-forward-email.png); }
.palm-menu-icon.info { background-image: url(../images/menu-icon-info.png); }
.palm-menu-icon.priority { background-image: url(../images/menu-icon-priority.png); }
.palm-menu-icon.reply-all { background-image: url(../images/menu-icon-reply-all.png); }
.palm-menu-icon.reply { background-image: url(../images/menu-icon-reply.png); }
.palm-menu-icon.save { background-image: url(../images/menu-icon-save.png); }
.palm-menu-icon.send { background-image: url(../images/menu-icon-send.png); }
.palm-menu-icon.sync { background-image: url(../images/menu-icon-sync.png); }
.palm-menu-icon.edit-profile { background-image: url(../images/menu-icon-edit-profile.png); }
.palm-menu-icon.make-vip { background-image: url(../images/menu-icon-make-vip.png); }
.palm-menu-icon.new-contact { background-image: url(../images/menu-icon-new-contact.png); }
.palm-menu-icon.remove-vip { background-image: url(../images/menu-icon-remove-vip.png); }
.palm-menu-icon.down { background-image: url(../images/menu-icon-down.png); }

Use the name after “.palm-menu-icon.” when setting up the command menu model.

this.cmdMenuModel = {
visible: true,
items: [
{items:[{label: $L('Add'), icon:'new', command:'
cmd-add'}]},
{items:[{label: $L('Refresh'), icon:'refresh', command:'
cmd-refresh'}]}
]
};

VirtualBox updates

I love VirtualBox, but come on, implement an automated updater already!

virtualbox update

Gaussian blur on an HTML5 canvas

I’m actually going to present more than the actual gaussian blur implementation, also showing how to setup a simple animation controller and lightweight pixel shader system, allowing for defining the final color of a pixel on a per-pixel basis and allowing other effects to easily be plugged into the system. Be warned, this stuff is slow. This is all CPU processing (atop JavaScript no-less), there’s, sadly, no GPU hardware acceleration here. If your thinking about doing this on high-resolution images or writing effects that require a ton of passes over the image, you’re going bring the browser to a crawl, even on a fairly high-end system.

gaussian blur on HTML5 canvas element

I can’t embed JavaScript within this post, so you’ll have to go here to view the result (obviously, you’ll need an HTML 5 capable browser). For those who are curious, the very cool test image used is of a bird of paradise flower by the Agricultural Research Service.

So, first things first, the HTML, which is very simple. There’s 2 canvas element, one will hold the source image and the other will be the destination for the post-processed image. The width and height attributes on the canvas elements are set to the width and height of the image.

<!DOCTYPE html>
<html>
<head>
<title>HTML5 Blur FX</title>

<
script type="text/javascript">
// JS code will go here!
</
script>

</
head>
<body>
<canvas id="cvs-source" width="72" height="50">
</canvas>

<canvas id="cvs-dest" width="72" height="50">
</canvas>
</body>
</html>

Next, load the test image onto the source canvas (cvs-source) and setup the destination canvas (cvs-dest) as a blank image, which will occur when the page is loaded. Ignore the reference to the FXController object for now.

window.onload = function ()
{
var img = new Image();
img.onload =
function ()
{
// setup source
var ctxSource = document.getElementById('cvs-source').getContext('2d');
ctxSource.drawImage(img, 0, 0);

// setup destination
var cvsElement = document.getElementById('cvs-dest');
var ctxDest = cvsElement.getContext('2d');

var width = parseInt(cvsElement.getAttribute("width"));
var height = parseInt(cvsElement.getAttribute("height"));

ctxDest.createImageData(width, height);

var theShader = Shader.gaussBlur;
var fxCtrlr = new FXController(ctxSource, ctxDest, theShader, width, height, 10, 10);
fxCtrlr.init();
}

img.src =
'test3.png';
}

Stepping away from the actual code for a minute, it’s important to note how to actually modify the pixels on a canvas element:

  • Get the 2d context of the element by calling getContext(‘2d’) on the DOM element.
  • Call CanvasRenderingContext2D.getImageData(…) to get a buffer with the pixels in RGBA format.
  • To commit changes to the pixels onto a canvas, call CanvasRenderingContext2D.putImageData(…) with the buffer of modified pixels.
var ctxSource = document.getElementById('cvs-source').getContext('2d');
var imageData = ctxSource.getImageData(0, 0, width, height);


ctxDest.putImageData(bufWrite, 0, 0);

Back to the actual code. One of the very simple and primitive operations needed is to set a pixel to a color:

// GraphicsCore object
var GraphicsCore = {};
GraphicsCore.setPixel =
function (imageData, index, r, g, b, a)
{
imageData.data[index + 0] = r;
imageData.data[index + 1] = g;
imageData.data[index + 2] = b;
imageData.data[index + 3] = a;
}

I didn’t implement a corresponding getPixel() function because, as you’ll see, it’s very clean and easy to get the a pixel directly from the buffer and wasn’t worth invoking a function call.

The FXController object is (for the most part) the animation controller.

// FXController object
function FXController(_ctxSource, _ctxDest, _theShader, _width, _height, _fps, _maxFrames)
{
this.ctxSource = _ctxSource;
this.ctxDest = _ctxDest;
this.theShader = _theShader;
this.width = _width;
this.height = _height;
this.fps = _fps;
this.curFrame = 1; // [1, ...]
this.maxFrames = _maxFrames;
this.numPassesPerFrame = _theShader.numPassesRequired;
this.invervalPtr = null;

this.shaderFunc = function (fxCtrlr, passNum, frameNum, maxFrames)
{
Shader.run(fxCtrlr.ctxSource, fxCtrlr.ctxDest, fxCtrlr.width, fxCtrlr.height, fxCtrlr.theShader, passNum, frameNum, maxFrames);
}

this.init = function ()
{
var fxCtrlr = this;
var runFunc = function () { fxCtrlr.run(fxCtrlr); }

this.invervalPtr = setInterval(runFunc, 1000.0 / this.fps);
}

this.unInit = function()
{
clearInterval(
this.invervalPtr);
this.invervalPtr = null;
}

this.run = function (sender /*FXController*/)
{
for (var pn = 1; pn <= sender.numPassesPerFrame; pn++) {
sender.shaderFunc(sender, pn, sender.curFrame, sender.maxFrames);
}

sender.curFrame++;
if (sender.curFrame > sender.maxFrames) {
sender.unInit();
}
}
}

Most of what going on here is simply holding values which are passed to Shader.run(…). However, a few important things are being setup:

  • FXController.run(…) will be called at a certain number of frames per seconds (this.fps), until this.maxFrames is hit.
  • For each frame, Shader.run(…) will be called for each pass necessary (this.numPassesPerFrame). Certain effects will require more passes than other, for example, the gaussian blur implementation will require 2 passes.

The Shader object, the core of which is within Shader.run(…),

// Shader object
// Note: Shader.<shader_name>.numPassesRequired must be defined
var Shader = {};
Shader.run =
function (ctxSource, ctxDest, width, height, shaderFunc, passNum, frameNum, maxFrames)
{
//
// netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); // REMOVE ME BEFORE DEPLOYMENT
//

var bufWrite = ctxDest.getImageData(0, 0, width, height);

var imageData = null;
if (passNum == 1 && frameNum == 1) {
imageData = ctxSource.getImageData(0, 0, width, height);
}
else {
imageData = ctxDest.getImageData(0, 0, width, height);
}

for (var y = 0; y < height; y++) {

for (var x = 0; x < width; x++) {

var index = (x + y * imageData.width) << 2;
shaderFunc(imageData, bufWrite, index, x, y, imageData.data[index + 0], imageData.data[index + 1], imageData.data[index + 2], imageData.data[index + 3], passNum, frameNum, maxFrames);
}
}

ctxDest.putImageData(bufWrite, 0, 0);
}

(The UniversalBrowserRead privilege is necessary to run this locally in Firefox)

Shader.run(…) will setup the source and destination buffers, iterate over every pixel, compute the pixel index, get the pixel color, call shaderFunc(…) with all the necessary params, and finally commit any changes to the destination buffer (bufWrite). Note, the source canvas is only used for the first frame, first pass; in all other cases whatever is rendered on the destination canvas is used. This allows for certain effects (such as the gaussian blur) in which the effect can be progressively applied again and again, in a feedback loop, to produce updated iterations of the effect (in the case of a gaussian blur, the image is blurred more and more).

The code presented so far lays the framework to allow for writing a shader, plugging it into the system, and watching the result. Before, getting to the more complex gaussian blur filter, here’s a much simpler one: a single-pass, per-pixel image fade-in.

// fade in shader
Shader.fadeInShader =
function (imageData, bufWrite, index, x, y, r, g, b, a, passNum, frameNum, maxFrames)
{
var dt = frameNum/maxFrames; // [0, 1]
GraphicsCore.setPixel(bufWrite, index, r, g, b, dt * 255);
}
Shader.fadeInShader.numPassesRequired = 1;

(Shader..numPassesRequired is required for every shader, as FXController will query the value to determine how many times to call Shader.run(…) per frame.)

The shader function allows us to define what the final color of a pixel will be, given a set of input parameters, on a pixel-by-pixel basis, the core of what a pixel shader system is and allowing for a amazing degree of flexibility.

Finally, the gaussian blur shader. I won’t go into too many details here. If you’re interested in how a guassian blur is actually done, this article on gamedev.net is probably the best out there (esp. for transitioning from theory to practice), and the code here is almost a direct translation of what’s up there. Also note that bitshifts are used to do the power-of-2 divisions and multiplications.

// gaussian blur filter
Shader.gaussFact = Array(1, 6, 15, 20, 15, 6, 1);
Shader.gaussSum = 64;
// not used, >> 6 bitshift used in Shader.gaussBlur()
Shader.gaussWidth = 7;

Shader.gaussBlur =
function (imageData, bufWrite, index, x, y, r, g, b, a, passNum, frameNum, maxFrames)
{
if (passNum == 1 && (x <= 0 || x >= imageData.width - 1)) {
GraphicsCore.setPixel(bufWrite, index, r, g, b, a);
return;
}

if (passNum == 2 && (y <= 0 || y >= imageData.height - 1)) {
GraphicsCore.setPixel(bufWrite, index, r, g, b, a);
return;
}

var readBuf = imageData;
var writeBuf = bufWrite;

var sumR = 0;
var sumG = 0;
var sumB = 0;
var sumA = 0;

for (var k = 0; k < Shader.gaussWidth; k++) {

var nx = x;
var ny = y;

if (passNum == 1) { nx = (x - ((Shader.gaussWidth - 1) >> 1) + k); }
else if (passNum == 2) { ny = (y - ((Shader.gaussWidth - 1) >> 1) + k); }
else { }

// wrap around if we're trying to read pixels beyond the edge
if (nx < 0) { nx = readBuf.width + nx; }
if (ny < 0) { ny = readBuf.height + ny; }
if (nx >= readBuf.width) { nx = nx - readBuf.width; }
if (ny >= readBuf.height) { ny = ny - readBuf.height; }

var pxi = (nx + ny * readBuf.width) << 2;
var pxR = readBuf.data[pxi];
var pxG = readBuf.data[pxi + 1];
var pxB = readBuf.data[pxi + 2];
var pxA = readBuf.data[pxi + 3];

// little hack to make alpha=0 pixels look a bit better
// Note, the proper way to handle the alpha channel is to premultiply, blur, "unpremultiply"
if (pxA == 0) {
pxR = 255;
pxG = 255;
pxB = 255;
pxA = 255;
}

sumR += pxR * Shader.gaussFact[k];
sumG += pxG * Shader.gaussFact[k];
sumB += pxB * Shader.gaussFact[k];
sumA += pxA * Shader.gaussFact[k];
}

GraphicsCore.setPixel(writeBuf, index, sumR >> 6, sumG >> 6, sumB >> 6, sumA >> 6);
}
Shader.gaussBlur.numPassesRequired = 2;

The blur is done with a 3×3 convolution filter, over 2 passes. In the first pass, neighboring pixels are sampled and blurred along the x-axis. In the second pass, the same is done along the y-axis.

A few simple conditionals allow for wrapping around and sampling from the other side of the bitmap, if there’s an attempt to sample beyond the edges.

Note the little hack for transparent/translucent pixels; this is not the proper way to do this (and simply makes the error more grey-ish instead of black-ish), but I didn’t want to deal with premultiplying the alpha, so I’ve left it out.

The demo + all code is up @ http://aautar.digital-radiation.com/HTML5-BlurFX/

progTools and Adobe Air

I made a little app to get my feet wet with Adobe Air. progTools just packages together a few common functions I find myself using frequently. You can get it my clicking the install badge (one of the very cool aspects of Adobe Air) below.

[airbadge]progTools, http://aautar.digital-radiation.com/apps/progTools.air,1.2,http://aautar.digital-radiation.com/progTools-air-badge/logo-badge.png[/airbadge]

(h/t to Peter Elst for the AIR Badge WordPress plugin)

What’s offered:

  • Conversion to/from a Unix timestamp
  • MD5 hash on a string
  • MD5 hash on a file
  • SHA1 hash on a string

progTools 1.2

Not too impressive, and only the MD5 file hash really utilizes a desktop feature of the Air framework, but it is somewhat useful and, at least in my case, I won’t end up going to Paj’s Home to use the javascript md5 implementation demo quite as often. Note, Paj’s MD5 library was used and I slightly modified core_md5() for the file hash to deal with hashing successive blocks. I’ll post the code soon.

I initially dismissed Air, back when it was Apollo, as I didn’t see the value in having yet another proprietary framework which didn’t really offer much beyond what was capable within a browser, aside from local file access. A few additions to the framework and a few realizations on my part have shifted my views:

  • Air supports HTML/CSS for layout and styling. Looking into cross-platform GUI frameworks, I’ve played around with WinForms (cross platform with Mono), Qt, Gtk, and wxWidgets. I’ve been disappointed to various degrees with all of them. It hit me that the most flexible and powerful cross-platform layout and styling framework out there is the HTML/CSS combo. It’s not perfect (e.g. floats, vertical centering) but it’s pretty damn good.
  • Support in Air 2 for sockets and interaction with native applications. This vastly opens the field for the types of applications possible with Air.
  • Market support from Adobe. The Air Marketplace is perhaps not too impressive, but it’s a major step in the right direction for desktop apps. Both Microsoft and Apple have their own stores planned, but with the success of such catalogs on smartphones for years now, why did it take so long to figure it out?
  • Install badges. They’re cool and important as they provide a bridge between the web and the desktop. Odd, but it seems Adobe more-so than Microsoft or Apple seems to understand the web-desktop relationship. Again, why is Adobe, a company that was fairly divorced from the desktop application space, the first to figure out that this was something important or at least the first to actually build it.

Now it’s not all sunshine and roses. Making an HTML/AJAX app in Air brings up a problem every AJAX developer has likely faced at some point. Javascript is slow… very slow. JavaScriptCore/Nitro, V8, Chakra, Tracemonkey… it doesn’t really matter (though performance improvements are being made), once your volume of data grows you’ll cringe at how slow things become. Coming from C++, C#, or even PHP, it’s painful to witness. In progTools a file only a few megabytes large will noticeably stall the application (I didn’t do the call asynchronously, but that’s besides the point). ActionScript is perhaps better and interop to a native executable could also alleviate the issue, but ultimately I’d simply like a faster JavaScript engine.

A second issue, relevant but not specific to Adobe Air, is code signing; you’ll notice the scary warning when installing progTools. Code signing is bullshit. Expensive bullshit. Yet, every platform developer is requiring it due to some misguided attempt at security. If you want to install progTools, the chain of trust is between me » this web server » you. Sticking a certificate authority in this chain is nonsense – a typical user will not know the CA and cannot establish any level of trust with some random, corporate CA.

Coding signing simply punishes small developers and establishes a new industry to leech from our wallets. In addition, as this user on StackOverflow asserts, it may well hamper the success of Air:

When you visit a site that lets you download an AIR app, it pops up big red screaming warnings about the imminent trashing of your computer, the theft of your identity and a life of torment[1]. Unless, of course, all the bedroom programmers decide to cough up the ongoing cost of certification.

User encouragement FAIL. Hobby developer encouragement FAIL. Technophobe terrorficiation avoidance FAIL.

I love AIR, but I don’t know what they were thinking with the installer. Laywers’ office moved closer to the developers’ over at HQ or something?

Anyways, I’m done ranting. I’ll eventually suck it up and get a certificate as I’m powerless to do anything else.

As for Air, I’ve just scratched the surface, but I’m impressed.

oh, and if you’d like to see something added to progTools, just let me know.

The Great British Euler diagram

I finally understand…

The Great British Venn diagram

h/t to Things Of Interest, where you’ll also find a nice explanation to go along with the diagram.

Ultramarines bolt pistol prop

An amazing design by Volpin Props of a Warhammer 40K, Ultramarines bolt pistol.

ultramarines bolt pistol

Keeping your data with a startup

There are 2 outcomes for most successful startups: they get acquired by a larger company or they have an IPO. In general, an IPO is rare. The more likely case is that a profitable or otherwise attractive company will be acquired. If it seems odd that these are the only 2 options, realize that once a company takes money from an investor the values of the shares are expected to gain massive increases in value, very quickly; a small development house or consulting shop can’t produce such gains.

Acquisition being the likely outcome, a disturbing trend seems to be developing in this new era of cloud services.

When a company is acquired, it doesn’t always get to simply continue functioning as-is, serving it’s customers. The acquirer may shutdown the startup in order to integrate its technology into its own offerings or simply to eliminate it as a competitor. In the case of startups that store, maintain, and handle users’ data this leaves customers with with a painful (translation: time, money, and stress) migration path (assuming there is one) to get their data out and onto another service or their own PCs or servers.

A few specific cases I’ve come across so far:

  • DabbleDB, Smallthought Systems, acquired by Twitter. I was actually searching for this in order to recommend it to someone. After learning of the acquisition, I realized what a mistake it would have been to recommend this to a user only to have them deal with the present data migration issues.
  • Etherpad acquired by Google. Service that allowed for real-time, collaborative text editing; its functionality now integrated into Google Docs.
  • Plannr acquired by Google. I wasn’t interested in the service. I simply came across it in a post on reddit.

SlashXML (C++ version)

The C++ code for SlashXML is now up, it’s in the /cpp folder within the repository. The C++ version supports most of the functionality the C# version does; maintaining multiple codebases is very difficult!

The C++ version also has 2 dependencies: TinyXML, an awesome, light weight XML parser, and AString, a not-so-lightweight UTF-8 string class. I know not everyone might be crazy about using AString, especially as it’s fairly bloated; I fucked around with things like custom numeric to string conversions with this class – unnecessary stuff, and it’s probably slower than using sprintf. However, it’s well encapsulated in it’s own namespace. I’ll try to have something more elegant in the future.


Load an XML document from a file

SlashXMLReader    xmlreader;
xmlreader.LoadXMLFile(
"test.xml");


Load an XML document from a string

SlashXMLReader    xmlreader;
std::vector<
unsigned char> xmlData;
// copy octets from string into xmlData here
xmlreader.LoadXMLData(xmlData);


Retrieve data from an element

SlashXMLString data = xmlreader.GetData("root/child");


Retrieve data from an indexed element

SlashXMLString data = xmlreader.GetData("root/child[2]");


Get the number of child nodes under an element

int numKids = xmlreader.GetNumChildren("root", "child");

The SlashXMLReader::LoadXMLData() method is kinda messed up and bizarre. I don’t even remember what was going thru my mind there.

Project Vertigo

A game project myself and, artist, Scott Reid are working on. We’re both desperately pressed for time and this project has been moving at a snail’s pace. We’re actively seeking an additional programmer and/or artist. If your interested, have the skills, and can devote the time get in touch with me. A few screenshots and concept art pieces are shown below, see the project page for more.

fyi, this is project which Firefly 3 is being built around.

project vertigo screenshot

project vertigo screenshot

project vertigo concept art

project vertigo concept art

project vertigo concept art