hyperlogic.org
A witty saying proves nothing. -Voltaire

MacOSX App Bundle Hell

There are two ways to create an app bundle on MacOSX, the Easy and the Ugly.

The easy way is just to use XCode. Done.

The problem is sometimes you can't.

In my case I'm building an app that builds other apps. I can't assume the user has XCode installed. I'm also using MacPorts to build the libraries my app depends on. I need to make sure that these dylibs get bundled with the app before I distribute it.

Disclaimer: I'm totally unqualified to write this post, everything in is has been gleamed from Apple docs, picking apart existing apps and trial and error. It works for me, but is most likely wrong. Please email me if you have any corrections.

First thing you should know is that an app bundle is just a directory. Let's examine the structure of a hypothetical foo.app.

foo.app/
    Contents/
        Info.plist
        MacOS/
            foo
        Resources/
            foo.icns

Info.plist is a plain XML file. You can edit it with a text editor or the Property List Editor app that comes bundled with XCode. (It's in /Developer/Applications/Utilities/ directory).

The key things you need to include are:

CFBundleName - The name of the app.

CFBundleIcon - An Icon file assumed to be in Contents/Resources dir. Use the Icon Composer app to create the icon. (It's also in the /Developer/Applications/Utilities/ directory) You can just drag and drop a png onto it's window and should automatically generate the mip-levels for you.

CFBundleExecutable - Name of the executable file assumed to be in Contents/MacOS/ sub-folder.

There are lots more options, the ones listed above are only the bare minimum. Here's some Apple documentation on the Info.plist file and App bundle structure.

Also, Here's a sample Info.plist.

<?xml version="1.0" encoding="UTF-8"?>
!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleGetInfoString</key>
  <string>Foo</string>
  <key>CFBundleExecutable</key>
  <string>foo</string>
  <key>CFBundleIdentifier</key>
  <string>com.your-company-name.www</string>
  <key>CFBundleName</key>
  <string>foo</string>
  <key>CFBundleIconFile</key>
  <string>foo.icns</string>
  <key>CFBundleShortVersionString</key>
  <string>0.01</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundlePackageType</key>
  <string>APPL</string>
  <key>IFMajorVersion</key>
  <integer>0</integer>
  <key>IFMinorVersion</key>
  <integer>1</integer>
</dict>
</plist>

In a perfect world you could just drop your executable into the Contents/MacOS/ dir and be done. However, if your app has any non-standard dylib dependencies it won't work. Like Windows, MacOS comes with it's own special kind of DLL Hell.

If you're using MacPorts to build libraries that you link against, the locations of the the dylibs will be hard-coded into your executable. If you run the app on a machine that has the dylibs in the exact same location, it will run fine. However, most users won't have them installed; when they double-click your app it will just crash.

Before you distribute you executable you'll need to collect all the dylibs it loads and copy them into the app bundle. You will also need to edit the executable so that it will look for the dylibs in the correct place. i.e. where you copied them to.

Hand editing an executable sounds dangerous right? Luckily there are command line tools to help.

otool -L executable_name

This command will list all the dylibs that your app depends on. If you see any that are NOT in the System/Library or usr/lib folder, those are the ones you'll need to copy into the app bundle. Copy them into the /Contents/MacOS/ folder. Next you'll need to edit the executable to use the new dylibs.

First, you need to make sure that you link using the -headerpad_max_install_names flag. This just makes sure that if the new dylib path is longer then the previous one, there will be room for it.

Second, use the install_name_tool to change each dylib path.

install_name_tool -change existing_path_to_dylib @executable_path/blah.dylib executable_name

As a practical example, Let's say your app uses libSDL, and otool lists it's location as "/opt/local/lib/libSDL-1.2.0.dylib".

First copy it into the app bundle.

cp /opt/local/lib/libSDL-1.2.0.dylib foo.app/Contents/MacOS/

Then edit the executable to use the new location (NOTE: make sure you built it with the -headerpad_max_install_names flag)

install_name_tool -change /opt/local/lib/libSDL-1.2.0.dylib @executable_path/libSDL-1.2.0.dylib foo.app/Contents/MacOS/foo

Whew, we're almost done. Now there's a small issue with the current working directory.

When you start your app the current directory will be the directory above where the application is located. For example: If you place the foo.app in the /Applcations folder then the current directory when you launch the app will be the /Applications folder. Not the /Applications/foo.app/Contents/MacOS/ as you might expect.

You can alter your app to account for this, or you can use this magic little launcher script that will change the current directory and launch your app.

#!/bin/bash
cd "${0%/*}"
./foo

Make sure you adjust the Info.plist file so that CFBundleExecutable points to the launch script and not to the previous executable.

Ok, all done now. Luckily, once you know all this stuff you bury it in a build script.

Jump Tuning

I was flipping through an old Game Developer magazine and found an interesting article about jump physics. (Nov 2009, Inner Product: by Mick West). It's a good article, It made me want to share an insight on character jump tuning that I've gained while working on various games.

Jumps can be represented as a function of time.

x(t) = v_x * t
y(t) = v_y * t + (g * t^2) /2

x(t) is the horizontal component and y(t) is the vertical component of the jump. In our coordinate system, x is forward and y is up. So that means vx and vy should be positive and g should be negative.

As a programmer, it's very easy for me to expose vx, vy and g as parameters for each kind of jump in the game.

  • vx - The initial horizontal speed.
  • vy - The initial vertical speed
  • g - Gravity (-9.8 m/s2 is real-world gravity).

The game designers can then adjust these values to tune the jump to their liking. The problem is, designers don't really know what the initial speeds and gravity should be to get the effect they want. All they really care about are answering the following questions:

  • How far can the character jump? So, they can make gaps that can't be jumped across.
  • How high can the character jump? So, they can make obstacles that can just barely be jumped over.
  • How long does a jump take? So, they know what the response time is between when the player hits the jump button and when they regain control on the ground.

Oh, yeah and they'll want to change the answer to each one of these questions without effecting the others.

What we have here, is a typical case of: Easy for the programmer, hard for the designer.

Picture of a Eddie Deezen

A much more convenient set of tuning parameters would be:

  • h - jump height
  • a - hang time
  • d - jump distance

These three make a good choice because they are orthogonal. i.e. Making a change to hang time does not affect the height of the jump or the jump distance.

So now, how do we translate these numbers into parameters we can plug into our motion equation?

The jump height (h) is the distance from the ground at the apex of the jump. The apex is the point in the path where the vertical velocity is zero. i.e. the point at which the character hangs in mid-air. So if we can find this apex, we can figure out the jump height.

This is our vertical function of motion.

y(t) = v_y * t + (g * t^2) /2

If we differentiate it with respect to time, we get a new function y'(t) which represents the instantaneous vertical speed of the character at time t.

y'(t) = vy + g * t

Set this equal to zero, and solve for t to get:

t_a = -v_y / g

This ta is the time the character hangs in mid air. So if we plug this time into our motion equation we'll get the height at the apex. i.e. the jump height (h) we're looking for.

y(t_a) = y(\frac{-v_y}{g}) = v_y(\frac{-v_y}{g}) + \frac{g(\frac{-v_y}{g})^2}{2}

Simplifying:

h = \frac{-v_y^2}{2g}

Now lets figure out the hang time of the jump. The apex of the jump occurs half-way through the jump, so it stands to reason that the hang time is just twice the apex time. This works because the parabola is symmetric about its apex.

a = 2t_a = \frac{-2v_y}{g}

We're assuming the character is jumping on flat ground, so, the hang time (a) is when the character lands. If we plug in the hang time (a) into the horizontal motion equation we'll get the final jump distance d.

x(a) = v_xa = v_x(\frac{-2v_y}{g})

d = \frac{-2v_xv_y}{g}

Ok, now we have 3 equations:

h = \frac{-v_y^2}{2g}, a = \frac{-2v_y}{g}, d = \frac{-2v_xv_y}{g}

If we take the first two equations and solve them as a system (two equations, two unknowns), we get:

g = \frac{-8h}{a^2}

and

v_y = \frac{4h}{a}

if we plug those into the third equation we get:

v_x = \frac{d}{a}

Now we have a way of computing what our initial velocity (vx, vy) and gravity (g) should be in order to get the motion described by h, a and d.

v_x = \frac{d}{a}, v_y = \frac{4h}{a}, g = \frac{-8h}{a^2}

We're done. We've made the designers happy by giving them a set of orthogonal controls that map directly to the things they care about most.

Well, until they ask for air steering and double jumps that is.

No quaternions were harmed...

Here's a video I made comparing two methods of quaternion interpolation.

Enjoy!

Best Bug Ever

Guess what I just wasted an afternoon on?

copy = new char[strlen(orig+1)];
strcpy(copy, orig);

Which should have been.

copy = new char[strlen(orig)+1];
strcpy(copy, orig);

I think I need to bump up my emacs font size... or stop coding in C++.

Stealth Git Guide

The Git Vision Control System is usually seen as a way to share code between many distributed programmers. However, most companies are already using and prefer to use a centralized control system such as Subversion or Perforce. Git is still a powerful tool even when you only use it on your own machine.

You can use Git like a ninja, managing complex changes locally, then only checking in clean working code to the shared depot. No one even has to know you are using it at all.

Here are some scenarios where I've found Git handy.

The Quick Fix

How often have you found yourself in this situation? You're midway through on a new feature, and suddenly you need to drop everything to fix something that's blocking the entire team. But the code on your machine is torn apart and broken. You need to quickly get the latest code in order to make the fix.

Git has several ways of accomplishing this. The easiest is git-stash.

> git stash
Saved working directory and index state "WIP on master: 2717a6c... new files"
HEAD is now at 2717a6c new files
(To restore them type "git stash apply")

This saves a patch of your local changes. Now you can sync to the latest shared code and make your bug fixes. Once you've submitted your fix to the shared repository, restore your previous progress using:

> get stash apply

This method works fine if there aren't big differences between the shared depot and your local work. I prefer to use another method if the differences are big.

The Big Change

When you're working on a feature that could take as long as a week to implement, other people are working on the same code, unaware of your pending feature. If you wait until your work is complete before you integrate their changes you'll have a ton of hairy conflicts to resolve.

With Git you can make a local branch of your feature work. This gives you the ability to integrate coworkers changes early and often, saving you pain later.

Here's how I setup my workflow. I have two local branches depot and feature.

At least once a day, I update my depot branch with the current state of the shared repository. If perforce is holding shared depot, this can be done as follows.

> git checkout depot
> p4 sync -f
> git add .
> git submit -a -m "daily sync"

This step can easily be automated.

I'll then use Git to merge the latest changes from the depot branch into my feature branch.

> git checkout feature
> git merge depot

Because this happens at least daily, the conflicts should be small and easy to manage.

Once the work on the feature branch is complete and fully tested it can be directly submitted into the shared repository. At that point, there really isn't any more need to keep the feature branch up to date. I just leave it and create new feature branches as needed.

A/B Comparison

Branches are also useful for quick comparisons between two code snapshots. I've used this often when doing performance tuning. Use git checkout to switch between the original code and an optimized version.

These are just some of the Git features that can be done locally. Even without the networking it's a very useful tool.

Ruby Templates and C++

I've been using a weird technique that helps me eliminate boiler plate C++ code. Templates. Not the C++ kind, but the web kind. Specifically, Ruby's ERB. It's like a pre-processor on steroids. You can embed Ruby code into a file, and when processed, the code is executed and replaced with the result.

It's mainly used inside of web frameworks like Ruby on Rails to generate HTML which is then sent to a web browser. However, there's no law that says it can only be used on HTML files.

Lately, I've been using ERB inside of C++ files as a code generation tool.

Here's an example where ERB templates can be useful. Look at the following Enemy class, with a message handler method.

class Enemy
{
    public:
	enum MessageType { APPLY_DAMAGE_TYPE, LOUD_SOUND_ALERT_TYPE };
	void HandleMessage(MessageType type, void* msg);
};

void Enemy::HandleMessage(MessageType type, void* msg)
{
    switch (type)
    {
    case DAMAGE_TYPE: 
        ApplyDamage((ApplyDamageMessage*)msg); 
        break;

    case LOUD_SOUND_ALERT_TYPE:
        LoudSoundAlert((LoundSoundAlertMessage*)msg);
        break;

        ...
    }
}

During development, message types are added, renamed and removed. Each time someone changes the code, four things need to be kept in sync:

  • The enum value
  • The case label
  • The function dispatch
  • The message cast.
Besides being a tedious typing chore, it's error prone. There are all sorts of dangerous errors the compiler will happily ignore. What if you mismatch a tag and a function call? What if you forget to add a break?

If you instead use ERB to generate the code you can prevent those errors.

<%# This defines a Ruby array which contains all the message types %>
<% msg_types = ['apply_damage', 'loud_sound_alert'] %>

class Enemy
{
    public:
    enum MessageType {
      <%# The message types get converted to enum values here %>
      <%= msg_types.map {|type| type.upcase + "_TYPE"}.join(", ") %>
    };
    void HandleMessage(MessageType type, void* msg);
};

<%# Here's a template of what each case label will look like %>
<% template = <<-CODE
   case LABEL: 
        FUNCTION((MESSAGE*)msg); 
        break;
CODE

# Helper function that converts variables like_this into variables LikeThis.
def humpbackize type
  type.split("_").map {|word| word.capitalize}.join
end
%>

void Enemy::HandleMessage(MessageType type, void* msg)
{
    switch (type)
    {
    <%# expand out a case label for each message type %>
    <% msg_types.each do |type| %>
    <%= template.gsub(/LABEL/, type.upcase + "_TYPE").
                 gsub(/FUNCTION/, humpbackize(type)).
                 gsub(/MESSAGE/, humpbackize(type) + "Message") %>
    <% end %>
    }
}

To add a new message just add it to the message_type array and implement the handler function. All the enum values, case labels & dispatching are all kept in sync.

You will have to integrate this into your build process, but it's not difficult. Just shell out to the erb executable.

It's not all roses, though. It's significantly harder to read then straight C++ code. Even if you know both languages well. Also, You might have to give up some syntax highlighting. Most editors can't handle mixing languages like this.

I've used this technique on personal projects and it has paid off. It's a great way to apply the DRY principle to your C++ code.

Circull Touch

My brother, Bill, graciously allowed me access to the Comp Core Lab touch table. I was able to get the prototype build of Circull running on it. Considering that it's meant to be an iphone app, I'd been thinking about the touch controls for a while but wasn't sure how they would feel.

I was quite happy how it turned out.

Although, my elevator pitch needs some work.

Cactus is my hero

I had a great time at this years GDC Indie Games Summit. Although, I felt it was light on tech details, there was a double dose of inspiration. Hearing about the success of World of Goo, AudioSurf and Crayon Physics Deluxe was just the validation I was hoping for. While difficult, it is possible to succeed as a small or even one man team, if you've got the drive and the talent, and of course luck helps too.

The stand out presentation for me was by Cactus, a mysterious, artistic & prolific game designer. One of the defining characteristics of his games, besides being awesome, is that they are developed very rapidly, in as little as 4 hours. That's what the talk was about. The presentation was made with the same framework he writes his games in, filled with the same quirky, endearing graphics of his games.

Overall, I was very impressed and inspired.

Go Go Gadget Rails

Aww, yeah.

After months of epic procrastination this site is now officially Web 2.0. It's got Ruby and the Rails, that all the cool kids are using. It's backed up, version controlled and hosted on the cloud. It's got a database back-end, wicked AJAX support and slick DOM manipulation.

Uh, now what?

History of the .bss Section

Every once and a while I stumble upon some arcane programming term and I think to myself: Why in the hell did they name it that? To deliberately confuse people? WTF?

Turns out most of the time they're just following in someone else's foot steps. Take the most recent example I ran into while doing work for the PS3 SPU's.

The SPU only has 256K of memory. So, it's very important to know the size of everything, including your code. Sony uses gcc, so it turns out they use a hacked up version of the GNU binutils size program.

Take a look at the output from the size command.

$ size /bin/sh
   text    data     bss     dec     hex filename
 712739   37524   21832  772095   bc7ff /bin/sh

Text I can understand, they're the actual instructions. Data I can understand as well, those are the global variables.

But what the hell is a bss?

After a bit of searching I turned up the answer, it's where the uninitialized globals go. Because they aren't initialized they don't end up in the actual executable file. That's why looking at the actual executable size isn't a good estimate of how much code space your program will take up.

But why bss?

After a google search I turned up this gem of a quote from Dennis Ritchie.

Actually the acronym (in the sense we took it up; it may have other credible etymologies) is "Block Started by Symbol." It was a pseudo-op in FAP (Fortran Assembly [-er?] Program), an assembler for the IBM 704-709-7090-7094 machines. It defined its label and set aside space for a given number of words.

That goes way back. The 704 was introduced in 1954. It still used fucking vacuum tubes. It was the size of a room. Core memory was brand spanking new. Introducing us to such terms as "core dump".

IBM 704, It's HUGE

From the IBM 704 to the Playstation 3, it's humbling to know that even in the fast paced world of computer software, concepts that were coined 50 years ago still apply today.

Interwebs; Engage

Woot! I'm on the internet now.

It's kind of refreshing to spend some time figuring out how all this stuff works. Like, the HTML & the CSS.

Seriously, 13 year old girls know more HTML then I do, or did. Look out.

Currently, everything's static. Fear my emacs skills. I know right? How 1999. Eventually, I'll get the dynamic web-page thing going; as soon as I decide what platform to go with.

I'm leaning toward Rails, but we'll see if I can stay focused enough to learn a whole new language, on top of all the other web concepts I'm clueless about.

Anyhow, should be fun.