Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, December 2, 2011

Swizzle that vector! Part 2

Well, after a long day trapped in the barn cleaning (it looks presentable now!) I return for the second part of implementing swizzling in C++.  I left off at the reasoning for using the functional operator and multiple arguments of a swizzle class, with the tantalizing hint that getting the error checking to work at compile time was weird.

So, here is the problem.  We have a Vec2, that is, a two component vector.  It should only be able to use swizzle components for the two components it has, that is, X and Y.  Something like:

vector2( x, y, x);

is valid but:

vector2( x, z, y );

should not be and ideally should throw some error at compile time.  Also, every vector type can use the swizzle components of the vector types that are smaller than it:

vector3( x, z, y );

It is clear that we can use inheritance to enforce this, but we must be careful.  When I first tried this, I made the mistake of inheriting in the direction that seemed the most logical, but that was in fact wrong.  Your gut instinct is to have the 3 component swizzles inherit from the 2 component swizzles:

class Swizz2;
class Swizz3 : public Swizz2;
class Swizz4 : public Swizz3;

But this does not solve the problem: it would mean that a Vec4 can only use the 4th component swizzle, W.  We are not following the Is A... principle here because we went with what felt natural.  It is correctly written:

class Swizz4;
class Swizz3 : public Swizz4;
class Swizz2 : public Swizz3;

And when we implement the functional operator for a Vec2 or a Vec3:

Vec2 operator() ( Swizz2 const& a, Swizz2 const& b ) const;
Vec2 operator() ( Swizz3 const& a, Swizz3 const& b ) const;

we can be sure that the operator will take only X, Y, and Z components in the Vec3 but only X and Y in the Vec2.

The final step to make all this safe from the user is to lock down the swizzle classes so that no one can alter what they mean (well, at least not easily).  I did this first by making the internal fields that govern how a particular instance of the Swizz2, Swizz3, and Swizz4 classes are used to swap components around private.  The swizzle classes are declared in the header file but omit their implementation, along with a class called SwizzleFactory:

class SwizzleFactory;
class Swizz4;
class Swizz3;
class Swizz2;

This makes it so that any other translation unit can use the classes but cannot do much with them.  In the implementation file, SwizzleFactory is declared a friend of the Swizz# classes, whose only useful constructors are private.  The swizzle components names are also declared in the header file:

extern Swizz2 const x;

/** etc. */

And then defined in the implementation by using the factory methods of a static SwizzleFactory instance:

Swizz2 const x = factory.MakeSwizz2( 1 );

Since the implementation file is the only place where the factory is defined, it is the only place where it can be instantiated. Thus, that translation unit is the only place where the swizzle classes can be defined and the whole system remains very safe from user intervention, unless they do something stupid and ugly.  To top it all off, the whole things lives in the namespace GFX, just in case you really need to use x as a variable name (do not do that).

Swizzle that vector! Part 1

If you have used OpenGL since version 2.0, you should be familiar with GLSL, the incidentally redundant 'Graphics Language Shading Language' (technically 'OpenGL Shading Language', but the "GL" stands for the above, sooooo...).

A nifty feature of GLSL is that it's primitive* linear algebra types, vectors, can use something called 'swizzling' to return a new primitive from the arbitrarily rearranged components of the first.  If you have the 3 component vector "vector1", for example, you can return a vector with the X and Z components swapped thusly:

vector1.zyx;

You can also construct vectors of a different order, that is, a different number of components:

vector1.zzyx;

This is really handy in shaders and linear algebra in general because you sometimes need to do just that, such as switching between coordinate systems.

But of course, C++ does not have this feature itself.  Not that it should, mind you; it is not a linear algebra language.  But when I was working on my own mathematics library for my work on computer graphics, I figured that if my vector package was to be really useful I should try to implement something like swizzling.

That is really difficult, as it turns out.  You cannot use the exact same syntax as GLSL and have something sensible; doing so would require all vector objects to store within themselves a copy of every combination and permutation of their four components as a field, which comes out to something like 4^4 == 256 additional float's per vector.  Memory is cheap these days, but it is not that cheap, not to mention its nauseating.

Some malign the option, but in C++ you can (and should) overload operators for your classes.  Thus, you could use the functional or subscripting operators, () and [], respectively, and have the swizzle combinations as separate, static objects with a name corresponding to the combination. Something like:


/** ... */
static SwizzleClass xyzz;
/** ... */

class Vec4 {
/** ... */
Vec4 operator() ( const SwizzleClass swizz ){ /**...*/ }
/** ... */
};


Which would be sufficient and replicate the functionality as is.  However, I found this method ugly; it felt too much like shoehorning something foreign into C++, the kind of thing a good Lisp programmer might pull if they tried to implement closures into C++ without thinking about it too much.  I was also a little worried about memory swapping; with some 256 static memory objects flying around, it sounded like a recipe for a speed bump**.

I also realized that there was something else I could make it do that GLSL could not: negate individual components.  The syntax in GLSL precludes this because it just stings component names together.  So I instead opted for using the functional operator with multiple arguments.  These arguments would be of a Swizzle class and have the negation operator overloaded so that one may write:

vector1( x, -y, y );

The number of arguments dictates the return type of the operator.  This method also solves a crucial typing issue: a two component vector cannot use swizzles for components it does not have, such as Z or W, but static, named permutations do not easily allow for this check at compile time and instead we would have to either throw exceptions or use a confusing system of classes and a royal mess of operator overloads.  That makes debugging linear algebra code blocks very difficult.  Using individual component swizzles like this allows us to solve that problem using the type system more directly, but the solution itself is a little unintuitive and will be the subject of a later post.

*To be clear, 'primitive' in the programming sense, that is, it is a feature of the core language and not a class or type implemented in it.

**The rule is "profile, then optimize".  I never profiled this option because it was a hassle to write all those permutations up when I was certain it was a bad idea for any number of reasons, memory being only one of them.  It is likely it would not have had dire implications as far as memory goes.

P.S. The HTML generated by this editor is a train wreck when it comes to changing fonts.