Jump to content
  • Advertisement
Sign in to follow this  
macnihilist

Little program to generate swizzle functions for C++ vector classes

This topic is 4130 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
Advertisement
I programmed something similar, but used the preprocessor to generate all possible permutations. You can download the program from Boost's Vault. It's called swizzle_demo_01.zip.

Boost Vault

Syntax looks like:

vec.zxy();
vec.xy();
vec.zwyx();
// etc...

Share this post


Link to post
Share on other sites
Quote:
Original post by mfawcett
I programmed something similar, but used the preprocessor to generate all possible permutations. You can download the program from Boost's Vault. It's called swizzle_demo_01.zip.


Thanks for the link. It looks by far more elegant than my solution. Although I have to admit that I haven't completely figured out how you did it yet. :)
(I have no experience with the boost preprocessor library.)

Share this post


Link to post
Share on other sites
If you actually use ideas from it, let me know. I've only used it in one product so far (no problems). I'd love to make it better.

Basically, if you can wrap your head around BOOST_PP_SEQ_FOR_EACH_PRODUCT you should be able to grasp what I did. The rest of the macros are simply details to get around the quirks of generating code using macros.

Take a look at Boost.Preprocessor for a pretty big hint as to how it's done.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!