april 2007
Apologies for the eight month hiatus! As for the title; that's right, me and my partner Ryan were just awarded with a Wooden Monkey for our animation for CSC418!

We won the award for the best animation 'Unnatural Habitat' (below) in the class, which was pretty cool. Our project was to create an animation engine/framework which we wrote in about three weeks using C++ and OpenGL. It was highly scriptable (using our scene definition language), and supported cubic interpolation, polynomial easing, texture mapping, lighting, materials, and the loading of OBJ meshes into the scene. We even had a real-time editing mode in the program in which you could pose the monkey live. All the models were created in Blender and Max, and the final movie was stitched together with the help of Rhys in Final Cut. Ryan did the monkey/sound effects and I ended up doing the narration.

Our goal was to show the darker side of the wooden monkey. The animation tells the tale of a man who stumbles upon the mythical wooden monkey only to face his demise at the hands of the beast. Seeing as it is quite the unnatural beast, it is only fitting that he is found in the most unnatural habitat. I am still in awe, especially since we actually won the wooden monkey with an animation that features the wooden monkey (must be some recursive self-realization going on!).

Anyways, I hope you enjoy the show! :)

wooden monkey 418 graphics open glThe Wooden Monkey Award

Higher quality version: Unnatural Habitat

Btw, if you ever do anything like this, make sure to spend a day or two to understand how to interpolate 3D rotations using quaternions; we ended up using plain spherical linear interpolation for rotations.

august 2006
After a long year at Alias/Autodesk, my PEY internship is complete! Had lots of fun, learned a ton about professional software development, got to implement some neat features, and met lots of great and talented people. Got to work with all three platforms, and fell for the Mac enough so to convince me to move to OSX personally.

Waking up tomorrow is definitely going to feel different - at least I have a week to wind down before final year starts!

Video of the week: Oh those crazy pandas!

smooth scroll mouse hackMouse innards
I have this standard logitech optical mouse (3 buttons + a wheel) which I happen to like except for one annoying thing - the mouse wheel. Unlike Microsoft mice, the wheel clicks as you are scrolling and each click is almost as loud as a button press itself, which sucks when you're reading / surfing the web at the middle of the night. If you have the same problem as I do, worry not as there's a simple solution (stumbled upon by accident)!

Opening the mouse casing, you'll see something like the image to the right ->
(note: opening your mouse may void your warranty!)

If you take out the wheel by sliding it up, you'll see that there are actually ridges on the inner edge. The metal piece with the coils on the right is a spring for pushing up the wheel after clicking, but the metal piece on the left (circled) is the one which makes contact with the wheel to provide audible feedback when scrolling. If you're like me, you can just take out the left metal piece to remove the clicking altogether (or you could also bend the piece so less force is needed to scroll to the next ridge).

After doing that, you'll have a mouse whose wheel will scroll as smooth as butter! (though it might take a bit of getting used to :)
Also note that this doesn't actually change the resolution of each scroll; even though the scroll is continuous, the still wheel has a set of slits which allows the led inside to register when the wheel is being scrolled - this hasn't changed with the modification.
Good course; learned some new stuff, challenging enough to get you thinking; I think the class was whittled down a quarter by the end of the term :)
june 2006
So, it's been about five days since I've gotten my MacBook Pro, and to put it quite simply, I LOVE it. Everything about it, the way the machine feels, the way it looks, the way it works exactly as you'd expect (like Rhys mentioned, the keyboard really is fantastic).
mac macbook pro keyboard small appleMacBook Pro
OSX is superb, albiet a little bloated (really, 3 gigs for Word and Powerpoint equivalent software?!) which may, in part, be due to the whole universal binary thing. After setting the environment up for the last few days, I think the machine already covers almost 90% of the functionality I had on my PC. Luckily, my machine has no major issues so far, but I'm hoping that Apple will fix some of the more minor things like the Core Duo Whine, and the Seagate Marble-drop sound in the next soft/firm-ware update. Otherwise, I am deeply impressed and am looking forward to finally getting some serious work done away from home!

Whew, what a day; worked, picked up groceries, then ran to catch the subway to Kipling to get to the ikea at Etobicoke. I arrived a Kipling, and waited to be picked up by the ikea shuttle at the wrong spot (bad directions) for about half an hour. Eventually, I took the 44 south, and ran five blocks to make it just 10 minutes before closing time. Goodness, that place is huge (which probably explains the need to have their own cafeteria), but I managed to find my table with the help of a couple yellow-shirted helpers. [I also couldn't help but notice that of the two dozen (or so) ikea girls I saw there, roughly 90% are short and blonde. Perhaps they import them along with the furniture from Sweden?] Definately looking forward to going back to pick up some much needed utensils [they have everything, no?].

Long story short, I had hoped to post something a little more substantial today, but spent much of the day running around and have yet to put everything together. Also, my brother's graduation is coming up, and the parents will be visiting for a couple days, so most of this and next week will be computer free. Also gotta make it seem like we're somewhat capable of taking care of ourselves before they arrive :) [which of course we are!]

Function headers are generally pretty easy to understand right? In most cases, yes, but the use of proper function headers can sometimes be a little confusing. At the same time, the use of such headers are necessary in accurately defining the function, which can speak volumes about what it actually does as well as the code which is calling it.
Take these for example:
void testFuncA();            
// easy, testFuncA() is a function which takes no arguments, and returns nothing upon completion

int testFuncB(int in);
// not bad, testFuncB() is a function which takes an integer value as an argument, and returns another integer upon completion

int& testFuncC(int * arg1, int& out2);
// ok, so testFuncC() is a function which takes a pointer to an integer as input, and (looking at the variable names) returns an int reference to some member integer (by use of the reference which implies it can not be returning a value allocated on the stack), as well as a second return value whose reference was passed into the second parameter.

virtual void testFuncD() const;
// throwing in some simple keywords now. testFuncD() is a virtual member function (which can be overrided by derived classes), which is const (it does not alter any member variables of the class defining this function).

virtual void testFuncE(int * const arg1, const string * arg2);
// even more wackiness. Notice how we have 'int * const test' and 'const string *'. These two mean completely different things, and in C++, you actually read the declaration backwards. As in, "arg1 is a const pointer to an integer". And as a const pointer, you can't change the value of arg1, but you can still change the value which arg1 points at. The second argument implies that "arg2 is a pointer to a string which is const" which means that arg2 can't be used to call any non-const member function in class string.

friend bool testFuncF(const int& arg1, const int& arg2);
// a friend member function, another topic for another time ;O). Inputs are references to integers which are constant, which means that arg1 and arg2 can't actually be set as a return value like in testFuncC().

virtual const int * testFuncG(const int * const arg1) = 0;
// the big one. testFuncG() is a pure virtual function with argument arg1, which is a const pointer to an integer which is const - meaning that you can change arg1's value nor whatever integer arg1 points to. Pure virtual functions are often used in abstract base classes to provide definition only for deriving classes (kinda like Java interfaces). Finally, we see that it returns a pointer to an integer which is const - which again implies that this is a pointer to some member function or heap-allocated variable whose value can not be changed via the pointer returned.

As you can see above, some function headers in C++ can be slightly confusing especially when using numerous keywords. As most C++ references recommend, it is best to write functions with as little impact as possible. This means using consts whenever possible, especially for member functions, as well as taking notice of simple return and argument optimizations. We can see that a few of the functions above take and return integers. This is fine as they are primitive data types, but once you begin passing large objects around, it is wise to use references or pointers whenever possible.

Quick short post today as I still need to write up the 373 assignment by thursday!

may 2006
Haven't written a technical post in a while (none after someone accidentally screwed up his database last year :( ), so I figured I should restart with something simple. Today's post deals with a relatively simple construct not native to C++ itself, but often found in many languages, like Java (almost completely transparent), Objective-C, and even low level APIs/architectures like Win32 and COM. Handles.

Handles in are a logical layer above the raw data which is often used to help users manage large blocks of shared data, as well as to consolidate access to limited resources. The benefits of handles are that they are lightweight and can often be used transparently once they are initialized. There are still issues associated with using handles - user management is still required, but these are often considered valid trade offs for some of the bigger problem you would run into otherwise.

Lets start with a quick example of why we may need handles:
// Note: not going out of my way to handle exceptions or catch errors below.
// this is a limited case, probably wouldn't be written like this, but you'll
// get the idea (hopefully).

//
// Lets just say that we have a large buffer which we fill with characters from
//    a file. We'll be storing a reference per file we parse. Class is pretty
//    lightweight no?
//
class LargeBufferObject
{
public:
    // constructor to load data from the input stream into the buffer
    LargeBufferObject(const ifstream&);
    // copy constructor
    LargeBufferObject(const LargeBufferObject&);
    // destructor
    ~LargeBufferObject();

    // assignment operator
    LargeBufferObject& operator =(const LargeBufferObject&);

    // public accessors
    const char * buffer() const;
    void setBuffer(char *);

private:
    char * fBuffer;
};

//
// # stl includes...
//
int main(int argc, const char* argv[])
{
    map< string, LargeBufferObject > fileParsedMap;

    for (int i = 0; i < argc; ++i) {
        string fileName(argv[i]);

        // let the large buffer object load from file
        ifstream file(fileName);
        LargeBufferObject fileBuffer(file);

        fileParsedMap.insert(pair< string, LargeBufferObject >(fileName, fileBuffer));
    }
}

Looking at what code we have, we see that filenames are passed into the program as command line arguments and loaded into their respective buffers. A map is used to keep a mapping between the filenames and their parsed buffers. Pretty straight forward right? Not quite. The initial problems lie with how we decide to implement the copy constructor and assignment operator(s), which we will look at first:
LargeBufferObject::LargeBufferObject(const LargeBufferObject&);
LargeBufferObject& LargeBufferObject::operator =(const LargeBufferObject&);
void LargeBufferObject::setBuffer(char *);

At first glance, we see that the map container takes a string as a key, and a LargeBufferObject as a value. We may then realize that insertion into the map actually creates a copy of the LargeBufferObject when the key-value pair is created. At this point, either the copy constructor will be called for the creation of a new LargeBufferObject or the assignment operator is called. For all intensive purposes, lets say that both of them call setBuffer() with the existing buffer pointer. There are really only two ways that we can implement setBuffer(): 1. a deep copy of the buffer contents, and 2. a shallow copy of the buffer pointer reference itself. If we decide to do a full copy of the buffer, we end up with two copies of the same data allocated on every insert, and every assignment of a non-reference LargeBufferObject. While it is possible to use this method by strictly passing pointers and references to the LargeBufferObject, it takes significant programmer time to track and ensure that all references to the object are always valid before use, and is deallocated when no other parts of the program need access to it. This becomes even more difficult to manage as the size of your program grows. While hard, this is not so bad a problem as things will still work albeit, inefficiently if users aren't careful.

So, some of you are probably thinking, Hey!, why not just copy the char pointer on assignment? Something like:
LargeBufferObject& LargeBufferObject::operator =(const LargeBufferObject& lbo)
{
    // calloc old buffer
    if (fBuffer != NULL)
        delete fBuffer;

    // set new buffer
    fBuffer = lbo.fBuffer;
}
LargeBufferObject::~LargeBufferObject()
{
    // calloc buffer
    if (fBuffer != NULL)
        delete fBuffer;
}

Which is much more efficient right? After all, the buffer is freed when not in use, and set on assignment.
Wrong! Take this example for instance:
void testFunc(LargeBufferObject& curBuffer)
{
    // ok, we are only copying the buffer char *
    LargeBufferObject tempRefToCurBuffer = curBuffer;

    // do something like, oh I don't know, get the length of the buffer?
    int i = strlen(temp.buffer());
}

int main()
{
    LargeBufferObject aLBO(ifstream("a.txt"));
    testFunc(a);

    // I dunno, lets allocate some vars on the heap for fun
    int * a = new int(10);
    float * b = new float(1.0f);

    // oh crap! possible heisenbug!
    printf("%s", aLBO.buffer());
}

See the problem? It's not very easy to spot.
Looking at the code, we see that testFunc() takes a reference to a LargeBufferObject (which is great), but the problem lies in the local variable 'temp' which is allocated on the stack. The LargeBufferObject 'temp' copies the current buffer's pointer reference on assignment ... (you see where this is going no?) ... and when testFunc() returns, all local variables are destroyed and the destructor for temp is called, which in turn, deletes fBuffer! Unfortunately, fBuffer is the exact same pointer which aLBO holds, so now, aLBO's buffer pointer unknowingly points to an undefined address in memory.

When we return, the allocation of more memory on the heap may or may not overwrite memory within the range of the buffer address. So, when you go and print aLBO's buffer, if the system has not overwritten the new data in the same memory address as the old buffer, then print will be OK. But if it does, then you will get corrupted output. The fact that the corruption happens occasionally but not always, is what makes this issue so potentially bastardly :).

So, looking at it, either way of implementing LargeBufferObject results in serious problems. If only there were an easy way to pass references whenever possible, cloning only when necessary! Sure enough, for mere mortal programmers such as myself, handles provide a simple, efficient and shoot-and-forget approach to the problem.
(For the sake of keeping this post within reasonable limits, I will be taking a look at only reference-counted handles today.)

Looking at the results above, using a reference-counted handle to manage the buffer indirectly looks to be a pretty good approach. Unlike the first implementation of LargeBufferObject, we still want to copy references (as they are usually used more frequently), making deep copies only when necessary. Luckily for us, use of handles is pretty transparent after initialization. For example:
class LargeBufferObject
{
public:

    // :
    // Same functions as above
    // :

    // deep copy operation
    LargeBufferObject clone() const;

private:
    Handle< char * > fBuffer;
};

//
// Where Handle<> is a template for a reference-counted handle.
//
template< class T >
class Handle
{
public:
    Handle();
    Handle(T *);
    Handle(const Handle&);
    ~Handle();

    Handle& operator =(const Handle&);
    T& operator *() const;
    T* operator ->() const;
    operator bool() const;

private:
    T * fPtr;
    int * fRefCount;
}

As you can see, implementation of the dereference operators will allow us to use the handle just as if it were the data itself, and the bool() conversion operator will allow us to quickly query the state of the handle (valid or not). The most important things we need to look at are the copy constructor/assignment operator and the destructor. All newly constructed handles begin with a reference count of 1 (to itself). When a new handle is created which refers to an old handle, we increment the reference count of the assigned handle, and decrement the reference count of the current handle as such:
template< class T >
Handle<T>& Handle<T>::operator =(const Handle& other)
{
    // ensure that we are not copying ourselves
    if (&other != this) {

        // increment the other handle reference count because this handle will now refer to the same data as
        // the other handle
        ++(*other.fRefCount);

        // remember to decrement the current reference count, now that we are no longer refering to our data,
        // deleting if we were the last reference
        if (--(*fRefCount) <= 0) {
            delete fRefCount;
            delete fPtr;
        }

        // copy the other handle
        fRefCount = other.fRefCount;
        fPtr = other.fPtr;
    }

    // return self ref.
    return (*this);
}

Likewise, in the destructor, we decrement the current reference count, and delete the data if we are the last known reference to it. The only left to do after this, would be to implement LargeBufferObject::clone() to make a deep copy of the handle's buffer data when ever we actually request it. As with most automatic memory management schemes, downsides include having less control over when deallocation takes place (an issue if deallocation includes expensive tasks such as writing to disk) as well as the possibility that certain handles are never ever released. No, handles are not the end-all to memory management issues, but they provide easy, straight forward control over all types of shared data. It also (almost perfectly) facilitates the use of semaphores and read-write locks in multi threaded applications.

For those who have better things to do than roll out their own handler/smart pointers, the boost C++ libraries has it's own implementation of shared_ptr<> (and weak_ptr<>) which seems fairly straight forward to use. You can find the library here

The new MacBooks are finally out today, but not even close to the specs which I had hoped. Mainly, the glossy screen (nice as a mirrors or for watching dvds but no good for coding/reading text for extended periods of time), and the lack of discrete graphics (even the x1300/x1400 would have been great for the higher end models). Not to mention that it almost weighs as much as the 15" MacBook Pro, and the black colored model (at least it does not have a glossy piano finish!) carries a $200 premium.

Gah, guess I'll have to start considering it's larger, more problem plagued, brother. Either that or stick with Windows!

« back to latest news next page »