Hi all - just wanted to share a neat little program I wrote today, maybe some of you will find it useful. It generates swizzle functions for C++ vector classes that allow you to use swizzles similar to those available in high-level shading languages.
I was experimenting with templates and macros, but all my solutions either had an ugly syntax or were a bit unsafe (I don't really like macros named 'xy'...). So I decided to use explicit functions like 'v.yxz()' and wrote the program below to generate them. I only conducted some small unit tests with my vector classes so far, but the functions seem to work pretty well.
The program should work for most vector classes, regardless of the underlying scalar type. All you have to do is to adjust the strings to match your needs.
The program will generate files containing the (inline) function definitions. These files can easily be included in our vector class, e.g.:
class MyVector3
{
public:
// ...blabla...
#include "Vector3Swizzles.inc"
};
Here is the program (a bit lengthy but since it's only one source file I think it's ok to post it here):
#include <iostream>
#include <sstream>
#include <fstream>
#define MIN_DIM 2
#define MAX_DIM 4
static const bool writeToStdOut = true;
static const bool writeToFiles = true;
// Files to which the functions for a particular class should be written.
static const char* fileNames[ MAX_DIM ] =
{
"Dummy",
"Vector2Swizzles.inc",
"Vector3Swizzles.inc",
"Vector4Swizzles.inc"
};
// Names of vector types to generate code for.
// Works also with class templates.
static const char* vectorTypeNames[ MAX_DIM ] =
{
"Dummy",
"Vector2",
"Vector3",
"Vector4"
};
// These are the strings used to access single components of the vector.
// You can also use operators [] and (), like "(*this)[0]".
static const char* vectorAccessors[ MAX_DIM ] =
{
"x",
"y",
"z",
"w"
};
// These are the letters used to generate names for the swizzle functions.
static const char* swizzleAccessors[ MAX_DIM ] =
{
"x",
"y",
"z",
"w"
};
// Optional prefix for the swizzle functions.
static const char* swizzlePrefix = "";
// Writes a definition of a swizzle function to a stream
// stream: ostream to write to
// dim: dimension of result
// p: permutation
void defineFunction( std::ostream& stream, int dim, int p[MAX_DIM] )
{
stream << "const " << vectorTypeNames[dim-1] << " ";
stream << swizzlePrefix;
for( int i=0; i<dim; ++i )
stream << swizzleAccessors[ p ];
stream << "() const" << std::endl;
stream << "{ return " << vectorTypeNames[dim-1] << "( ";
for( int i=0; i<dim; ++i )
{
stream << vectorAccessors[ p ];
stream << ( ( i < dim-1 ) ? ", " : " ); }" );
}
stream << std::endl;
stream << std::endl;
}
// Helper to enumerate all permuations of dimension 'dim'.
// vecdim is the dimension of the base vector.
void recurse( std::ostream& stream, int vecdim, int dim, int p[MAX_DIM], int recp )
{
if( recp == dim )
{
defineFunction( stream, dim, p );
}
else
{
for( int i = 0; i < vecdim; ++i )
{
recurse( stream, vecdim, dim, p, recp+1 );
p[ recp ] = ( p[ recp ] + 1 ) % vecdim ;
}
}
}
int main( int argc, char** argv )
{
// for all vector classes...
for( int vecDim = MIN_DIM; vecDim <= MAX_DIM; ++vecDim )
{
std::stringstream ss;
ss << "// " << fileNames[vecDim-1] << ": Swizzles for " << vectorTypeNames[vecDim-1] << std::endl;
ss << std::endl;
// ... generate all valid permutations...
for( int dim = MIN_DIM; dim <= vecDim; ++dim )
{
int p[MAX_DIM] = { 0,0,0,0 };
recurse( ss, vecDim, dim, p, 0 );
}
// ... and write out the function definitions.
if( writeToStdOut )
{
std::cout << ss.str();
std::cin.get();
}
if( writeToFiles )
{
std::ofstream ofs( fileNames[vecDim-1] );
if( ofs.is_open() )
ofs << ss.str();
ofs.close();
}
}
return 0;
}
You can also download a VS solution from http://karsten-schwenk.de/downloads/swizzle_generator.zip.
EDIT: D'oh! I knew I was missing something. Hope it's correct now.
[Edited by - macnihilist on May 1, 2008 10:40:27 AM]