« August 2008 | Main | October 2008 »

September 22, 2008

If it isn't broke don't fix it

I've wasted too many hours over the last couple of days playing with MovableType 4.2 only to find out that I don't really need it. Granted there are some nifty new features in it, but it feels much slower. I attempted to speed it up using mod_perl but met great difficulty. I didn't even get around to making sure that all of my plugins were doing the right thing since half of the ones I had I think I saw on the don't use with MT4 list. Thankfully I did all my upgrade testing in a separate copy of my database and published to a new location so nothing got lost.

If I was starting a brand new blog I'd still strongly consider using MovableType but given all of the customization of templates, plug-ins, and pages I've done to my existing version it was turning into too big of a task without enough gain. Too bad I didn't have that foresight yesterday when I started down this doomed path.

Tags: movabletype neophi

September 15, 2008

Pixel Bender and Conway's Game of Life

When I started reading about Pixel Bender and realized at its core it was a cellular automaton engine I immediately thought of Conway's Game of Life. I started looking into how to use Pixel Bender to render generations in the game of life.

Given that pixel bender is boundless (i.e. defined over an infinite plane of discrete pixel coordinates) I had to introduce the notion of a border pixel to make handling edge cases easier. Since most of the area in a generation is dead I decided to use white for a pixel that is dead (easier on the eyes) and black for a pixel that was alive. My initial attempt at the algorithm ran into a bug with the kernel export for Flash Player feature. After some rewriting I had a working pixel bender kernel that implemented the logic (albeit unoptimized):

<languageVersion : 1.0;>
// $Id: GameOfLife.pbk 57 2008-09-16 02:55:33Z danielr $
kernel GameOfLife
<   namespace : "Daniel Rinehart";
vendor : "NeoPhi.com";
version : 1;
description : "Conway's Game of Life";
>
{
    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        pixel4 border = pixel4(1.0, 0.0, 0.0, 1.0);
        pixel4 dead = pixel4(1.0, 1.0, 1.0, 1.0);
        pixel4 alive = pixel4(0.0, 0.0, 0.0, 1.0);

        pixel4 me = sampleNearest(src, outCoord());

        // default to no change in pixel
        dst = me;

        // I would like to write "all(equal(border, me))" but that's buggy in Flash
        if (!((border.r == me.r) && (border.g == me.g) && (border.b == me.b)))
        {
            int aliveNeighborCount = 0;
            float2 offset = float2(pixelSize(src).x, pixelSize(src).y);

            // Find out how many of my neighbors are alive
            // left
            pixel4 test = sampleNearest(src, outCoord() + (offset * float2(-1.0, 0.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // upper left
            test = sampleNearest(src, outCoord() + (offset * float2(-1.0, -1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // up
            test = sampleNearest(src, outCoord() + (offset * float2(0.0, -1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // upper right
            test = sampleNearest(src, outCoord() + (offset * float2(1.0, -1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // right
            test = sampleNearest(src, outCoord() + (offset * float2(1.0, 0.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // lower right
            test = sampleNearest(src, outCoord() + (offset * float2(1.0, 1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // down
            test = sampleNearest(src, outCoord() + (offset * float2(0.0, 1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }
            // lower left
            test = sampleNearest(src, outCoord() + (offset * float2(-1.0, 1.0)));
            if ((alive.r == test.r) && (alive.g == test.g) && (alive.b == test.b))
            {
                aliveNeighborCount++;
            }

            // As per: http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
            // 1. Any live cell with fewer than two live neighbours dies, as if by loneliness.
            // 2. Any live cell with more than three live neighbours dies, as if by overcrowding.
            // 3. Any live cell with two or three live neighbours lives, unchanged, to the next generation.
            if (((alive.r == me.r) && (alive.g == me.g) && (alive.b == me.b)) && ((aliveNeighborCount < 2) || (aliveNeighborCount > 3)))
            {
                dst = dead;
            }
            // 4. Any dead cell with exactly three live neighbours comes to life.
            if (((dead.r == me.r) && (dead.g == me.g) && (dead.b == me.b)) && (aliveNeighborCount == 3))
            {
                dst = alive;
            }
        }
    }
}

Now with a working filter I used some of the recent posts by Mike Chambers on how to embed a pixel bender kernel into MXML. However, since I wasn't using it as a filter and wanted more control over the flow I leveraged the ShaderJob class.

var shader:Shader = new Shader(new gameOfLife() as ByteArray);
shader.data.src.input = current;
var result:BitmapData = new BitmapData(current.width, current.height);
var shaderJob:ShaderJob = new ShaderJob(shader, result, current.width, current.height);
shaderJob.addEventListener(ShaderEvent.COMPLETE, handleShaderDone);
shaderJob.start();

Slap a minimal UI around it and you have (click to launch, view-source enabled, Flash Player 10 required):

Tags: flex gameoflife pixelbender

The Time Traveler's Wife

Yesterday I read Audrey Niffenegger's "The Time Traveler's Wife". It is by far one of the most entertaining books I've read in a long time. Stories that deal with time travel often times get bogged down in the science behind the time travel or worrying about the various paradoxes that it can produce. This book mostly avoids those subjects and instead focuses on the two main characters and their time traveling love story.

Time travel in this book is a result of a odd genetic disorder. Enough said. One only travels in time with one's own genetic material, but memories are part of that. Enough said. The primary paradox of time travel explored is the issue of free will. While it is addressed multiple times the book doesn't get bogged down with exploring the issue and instead quickly reaches the conclusion that you can't change anything. The main character is able to travel both forward and backward in time but randomly with some preference for important events. A wonderful twist that is used to great effect throughout the story.

However, despite all the nifty time traveling aspects of the story they are primarily there to serve the love story. A love story of longing. Longing but knowing. Maybe not always knowing exactly but longing knowing that something will come to pass. With love comes sorrow but neither is written with melodrama, which makes it very approachable. Overall a wonderful book that I highly recommend.

Tags: book timetravel

September 13, 2008

Critical Mass

Philip Ball's "Critical Mass" is an exploration of how one thing leads to another. I found the book to be a laborious read and overall wouldn't recommend it. While it touches on interesting topics such as phase transitions, power laws, self-organizing patterns, collective motions, and scale-free networks, the book isn't cohesive. It is bookended with the thought of using the laws of nature to guide and predict human nature. While there maybe corollary between the two, I didn't find any of the law applications that persuasive.

The use of modeling, particularly the chapter on traffic has merit, but again didn't feel like it derived from natural laws, it was more simplistic rules producing complex emergent behavior. Other models explored, such as the axis versus allies assignment, felt like the model was tweaked to get the desired result bringing into question the validity of the entire exercise. Some models, like predicting market crashes, clearly have an observer effect as noted on page 236.

When the book is talking strictly about natural phenomena (meta-stable states, one way flows), and not trying to relate it to human behavior and affairs, it makes for okay reading. The problem is that between the good scientific bits, the author's diversions into politics, policy, and people feel preachy and self-righteous. Given the length of the book I'm sure everyone is bound to find some nugget of usefulness in it, but slogging through the rest to find that bit doesn't seem worth it.

Tags: book science

September 9, 2008

Making Applications With Degrafa and ObjectHandles

Marc Hughes spoke at the Boston Flex User Group on Making Applications With Degrafa and ObjectHandles.

All of the talk materials are available on his blog.

Degrafa Introduction

Declarative graphics for MXML.. Based on surface that you draw things on. Surface has standard flex styles and placement. Surface is a Flex shape so you can apply filters, etc. Placed on a surface: Strokes, Fills, Geometry (the shapes). Multiple shapes are drawn in the z-index as defined in MXML. Wide variety of shapes (circle, rectangle, arc, etc.). Has repeater for most types of shapes. Can define objects outside of surface and use them anywhere. VectorFill recently added which allows complex shape composition. Since everything is a flash object can use tween on them. TweenMax is one example. Does support style sheet properties for most options and even creating entire surfaces in CSS.

Degrafa has some bases classes for doing skinning. GraphicBorderSkin is one example to define a skin for a component like a button. GeometryComposition allows defining how each state in the skin behaves.

ObjectHandles Introduction

ObjectHandles utility classes for doing real time object manipulation (move, resize, etc.). Background done in Degrafa. Objects to be manipulated extend: ObjectHandles <- BaseShape <- (SquareShape, CircleShape, etc.). CircleShape uses Degrafa to display itself. ObjectHandlesCanvas is a way to group ObjectHandle objects to enable keyboard support and easier z-index ordering. ObjectHandle objects dispatch various events like "Object Moving" and "Object Moved", once for during and once for after. SelectionManager is a singleton and an ObjectHandles class that manges the currently selected object. Rotation maybe added in the future (works in version 13 but not in latest).

ObjectHandles can't be composed into an existing object. Must be the base class.

Able to change the style of the handles through skinning.

ObjectHandles 2.0 is coming in the future that has better handle handling (get around scaling issues).

Tags: degrafa flex objecthandles