Category Archives: code

wavefront OBJ file format parsing with bash

Recently, I needed to extract some vertices from an OBJ file and drop them into my code. Rather than writing a OBJ file parser, I used bash to process the text. Here’s the OBJ file for a simple cube exported from Blender:

# Blender v2.71 (sub 0) OBJ File: ''
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
s off
f 6 2 1
f 7 3 2
f 8 4 3
f 5 1 4
f 2 3 4
f 7 6 5
f 5 6 1
f 6 7 2
f 7 8 3
f 8 5 4
f 1 2 4
f 8 7 5

In bash, I cd to the relevant file and run:

$ cat cube.obj | grep "^v " | cut -c 3- | xargs printf '%.1f,' | xargs printf 'static const float positions[] = { %s };' | pbcopy

Then I go to my source code and Cmd+V to paste:

static const float positions[] = { -1.0,-1.0,1.0,-1.0,-1.0,-1.0,1.0,-1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,1.0,-1.0,1.0,-1.0,1.0,1.0,-1.0,1.0,1.0,1.0, };

Nifty. I’ll likely extend it to extract additional data, compile to a custom binary format, and save it out to a shell script. After that I can call my make binary obj from either the command line or Xcode:

$ mbo cube.obj


Full script to create a binary OBJ file with an interleaved vertex buffer (v/n/uv).

vertices=($(echo "$obj" | grep "^v " | cut -c 3- | xargs printf '%f '))
normals=($(echo "$obj" | grep "^vn " | cut -c 4- | xargs printf '%f '))
uvs=($(echo "$obj" | grep "^vt " | cut -c 3- | xargs printf '%f '))
faces=($(echo "$obj" | grep "^f" | cut -c 3- | tr '/' ' ' | xargs -n 1 expr -1 +))
for (( i = 0 ; i < ${#faces[@]}; i+=3 )) do
vertexFormat=$(printf "%s," "${buffer[@]}")
main="#import <Foundation/Foundation.h>
static float buffer[] = { $vertexFormat };
int main(int argc, const char* argv[]) {
NSData* data = [NSData dataWithBytes:&buffer length:sizeof(buffer)];
[data writeToFile:@\"$2.mbo\" atomically:YES];
return 0;
echo "${main}" > main.m
clang -fobjc-arc main.m -o main_app
rm main.m main_app
echo now add the file to xcode

To use the script:

  1. Copy the text into a file called
  2. chmod +x
  3. ./ cube.obj cube

Then load it into a vertex buffer. Using Metal in this example:

NSURL* modelUrl = [[NSBundle mainBundle] URLForResource:@”cube” withExtension:@”mbo”];

        NSData* modelBinData = [NSData dataWithContentsOfURL:modelUrl];

        _vertexBuffer = [_device newBufferWithBytes:modelBinData.bytes length:modelBinData.length options:MTLResourceOptionCPUCacheModeDefault];

swift curried functions

Ran across this just now and found the comment by Pavol more interesting than curried functions. Yes Pavol! Totally. This is going to be a recurring problem for a lot of imperative programmers beginning to enter the world of functional programming through Swift. ‘Functional first’ is something I have to continually remind myself of. The original (imperative) gist went something like this:


Pavol advocates a more functional approach, without the “minutiae” of loops and temp vars:


Can we continue that train of functional thought? What if we move the separator up the chain, eliminating the function call:


That was an interim step to see if it worked. Now lets wrap it up and bring back that append function, allowing us to pass any separator:


Lastly, to make it even more compact, we can remove some syntax noise in the call to reduce:


Adding Box2D to Xcode

Grab the Box2D folder and drag it into your Xcode project.



Make sure copy items and the correct target are both checked.


In the project build settings, filter by “user”.


Under ‘User Header Search Paths’ add a . for the current directory and select recursive.


Set ‘Always Search User Paths’ to YES.


For the given source file, you need to change the extension to *.mm


Doing so, changes the default type to Objective-C++.


Finally, import Box2D and begin your journey.



It’s hard to find an example using CGDataProviderCreateDirect, so here’s a quick snippet:

static unsigned int* data; // used for manipulating pixel data directly

const void * getBytePointerCallback(void *info)
	return (void*)data;

@implementation SomeView

- (void)createImage
    CGDataProviderDirectCallbacks callbacks;
    callbacks.version = 0;
    callbacks.getBytePointer = getBytePointerCallback;
    callbacks.releaseBytePointer = NULL;
    callbacks.getBytesAtPosition = NULL;
    callbacks.releaseInfo = NULL;
    float w = self.layer.frame.size.width;
    float h = self.layer.frame.size.height;
    w *= [UIScreen mainScreen].scale;
    h *= [UIScreen mainScreen].scale;
    int numComponents = 4;
    uint dataLength = w * h * numComponents;
    data = malloc(dataLength * sizeof(uint)); // TODO: free
    uint r = 255;
    uint g = 0;
    uint b = 0;
    for(int i = 0; i < dataLength; ++i)
        data[i] = 255 << 24 | b << 16 | g << 8 | r;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef bitmapProvider = CGDataProviderCreateDirect(data,dataLength,&callbacks);

    CGImageRef bitmap = CGImageCreate(w,
                                      8,    // bits per component
                                      8*numComponents,  // total bits
                                      w*numComponents,  // bytes per row
    self.layer.contents = (__bridge id)(bitmap);

couchdb reader_acl

I installed CouchDB 1.0.1 with MacPorts 1.9.1 and quickly ran into problems:

  • The ‘attachments’ test hung in Chrome 6.0.472.55. I ran the same test in Firefox 3.6.9 and it worked.
  • The ‘reader_acl’ failed with an exception.
  • I couldn’t create an admin.

The couchdb.log certainly had errors but I couldn’t find a solution online. I tried uninstalling the port and reinstalling with no luck. Eventually I gave up and downloaded CouchDBX. Creating an admin worked but it also had problems running the Test Suite (I had to Force Quit).

Then I tried Homebrew. After installation I ran the Test Suite with 100% success and was able to create an admin! Awesome, now I’ll just add org.apache.couchdb to launchctrl…hmm it’s not under /Library/LaunchDaemons or /opt/local/Library/LaunchDaemons. After a little digging I eventually found it under /usr/local/Cellar/couchdb/1.0.1/Library/LaunchDaemons/. Only a few steps remain:

  • Copy org.apache.couchdb.plist into /Library/LaunchDaemons
  • Change the value under the UserName key to your user short name (hint: look under /Users)
  • sudo launchctl start org.apache.couchdb or you can test it for sure by restarting (shortcut key: Control-Command-Eject)

Everything now appears to be in working order.