Geometry/Vec lib swizzle syntax prototype

I have uploaded a small prototype that demonstrates the syntax mentioned in the thread below. It is in the Vault under Math - Geometry as swizzle_demo.zip. http://article.gmane.org/gmane.comp.lib.boost.devel/149076/match=geometry+ve... Here's a small example showing its use: float4 b(1, 2, 3, 4); float4 a = b.xxxx(); // a is now 1, 1, 1, 1 a = b.wwwz(); // a is now 4, 4, 4, 3 a = b.yzzw(); // a is now 2, 3, 3, 4 a = b.wzyx(); // a is now 4, 3, 2, 1 float4 c(10, 20, 30, 40); c.yz() = b.zy(); // c is now 10, 3, 2, 40 This mimics Cg, HLSL, and GLSL syntax closely. The swizzle syntax is implemented as function calls so that it doesn't increase the size of the vector struct (important for using those structs directly for graphics API calls). The prototype code does not implement arithmetic operators for simplicity's sake, but my local copy has it implemented. This isn't meant as a full library, only a demonstration showing that the swizzle syntax can be achieved rather simply using the Boost PP and TypeTraits libraries. One item that could be changed is the multiple template parameters to the classes. In the discussion that took place during the review of Andy Little's library the prospect of heterogeneous vectors took place. In my opinion heterogeneous vectors work with little expense to the library writer and transparently to the user. It would also "just work" with Andy's Quan library, or the other Units library being developed. This is pretty off-topic for the syntax that I am demonstrating, I just wanted to mention that I hadn't removed it from this demo. It is in no way necessary, but removal would require the macros to be changed a little bit. I have only compiled using VS 7.1 and 8.0. I am by no means a PP or template guru, so I would welcome your thoughts and critiques. --Michael Fawcett

Michael Fawcett wrote:
I have uploaded a small prototype that demonstrates the syntax mentioned in the thread below. It is in the Vault under Math - Geometry as swizzle_demo.zip.
http://article.gmane.org/gmane.comp.lib.boost.devel/149076/match=geometry+ve...
Here's a small example showing its use:
float4 b(1, 2, 3, 4);
float4 a = b.xxxx(); // a is now 1, 1, 1, 1 a = b.wwwz(); // a is now 4, 4, 4, 3 a = b.yzzw(); // a is now 2, 3, 3, 4 a = b.wzyx(); // a is now 4, 3, 2, 1
float4 c(10, 20, 30, 40); c.yz() = b.zy(); // c is now 10, 3, 2, 40
<snip>
Very cool! I know nothing about the PP library so it is very hard for me to decipher what the code is doing. If I were to write: float4 red( 1, 0, 0, 1 ); glColor4fv( (float*)&red ); // make color red glColor4fv( (float*)&red.xxxw() ); // make color white would this work? I'm guessing red would and white would not. Thanks, Michael Marcin

On 12/1/06, Michael Marcin <mmarcin@method-solutions.com> wrote:
Very cool! I know nothing about the PP library so it is very hard for me to decipher what the code is doing. If I were to write:
float4 red( 1, 0, 0, 1 ); glColor4fv( (float*)&red ); // make color red glColor4fv( (float*)&red.xxxw() ); // make color white
would this work? I'm guessing red would and white would not.
You are correct. The actual type returned by red.xxxw() wold be vec4<float &>, although that just gave me an idea. What about overloading the address of operator when the underlying type is a reference? Something like (off the top of my head...not well thought out): typename boost::enable_if<boost::is_reference<X>, const boost::remove_reference<X>::type *>::type operator&() const { static vec4<boost::remove_reference<X>::type> nrv; nrv = *this; return nrv.array(); } The actual address to the array of references hardly seems useful, while the behavior you showed seems very useful, and a user can always get around it using boost::address_of. --Michael Fawcett

On 12/1/06, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 12/1/06, Michael Marcin <mmarcin@method-solutions.com> wrote:
glColor4fv( (float*)&red ); // make color red glColor4fv( (float*)&red.xxxw() ); // make color white
would this work? I'm guessing red would and white would not.
You are correct. The actual type returned by red.xxxw() wold be vec4<float &>, although that just gave me an idea. What about overloading the address of operator when the underlying type is a reference? Something like (off the top of my head...not well thought out):
<snip untested code> I just implemented it locally. There are probably better ways. In particular I dislike the static variable, but I'm not sure how one could do away with it. Ideas are welcome! template <typename X, typename Y, typename Z, typename W> struct vec4; namespace detail { template <typename X, typename Y = X, typename Z = Y, typename W = Z> struct address_of_dispatch { X *operator()(vec4<X, Y, Z, W> &rhs) const { return rhs.array(); } const X *operator()(const vec4<X, Y, Z, W> &rhs) const { return rhs.array(); } }; template <typename X, typename Y, typename Z, typename W> struct address_of_dispatch<X &, Y &, Z &, W &> { X *operator()(vec4<X &, Y &, Z &, W &> &rhs) const { static vec4<X, Y, Z, W> nrv; nrv = rhs; return nrv.array(); } const X *operator()(const vec4<X &, Y &, Z &, W &> &rhs) const { return (*this)(const_cast<vec4<X &, Y &, Z &, W &> &>(rhs)); } }; } // Inside vec4's definition typename boost::remove_reference<X>::type *operator&(void) { return detail::address_of_dispatch<X, Y, Z, W>()(*this); } typename boost::remove_reference<X>::type const *operator&(void) const { return detail::address_of_dispatch<X, Y, Z, W>()(*this); } That works...whether it's the best solution is another story... I'll update the Vault files to include these changes. Thanks for bringing this issue up! --Michael Fawcett

On 12/1/06, Michael Marcin <mmarcin@method-solutions.com> wrote:
If I were to write:
float4 red( 1, 0, 0, 1 ); glColor4fv( (float*)&red ); // make color red glColor4fv( (float*)&red.xxxw() ); // make color white
would this work? I'm guessing red would and white would not.
In another posting it was pointed out that taking the address of a function's return is generally not done for specifically this reason (among others). Should there be any effort to solve this or just leave the swizzle functions as is? We could put a static assert in the address-of operator for when the underlying types are references...but again, I think there is precedent in coding guidelines to not do: &red.xxxw(); // taking the address of a temporary int add(int lhs, int rhs) { int result = lhs + rhs; return result; } int *p = &add(5, 5); This has never been expected to work. IMHO I don't think the swizzle functions should be expected to behave any differently. --Michael Fawcett

Michael Fawcett wrote:
On 12/1/06, Michael Marcin <mmarcin@method-solutions.com> wrote:
If I were to write:
float4 red( 1, 0, 0, 1 ); glColor4fv( (float*)&red ); // make color red glColor4fv( (float*)&red.xxxw() ); // make color white
would this work? I'm guessing red would and white would not.
In another posting it was pointed out that taking the address of a function's return is generally not done for specifically this reason (among others). Should there be any effort to solve this or just leave the swizzle functions as is?
We could put a static assert in the address-of operator for when the underlying types are references...but again, I think there is precedent in coding guidelines to not do:
&red.xxxw(); // taking the address of a temporary
int add(int lhs, int rhs) { int result = lhs + rhs; return result; }
int *p = &add(5, 5);
This has never been expected to work. IMHO I don't think the swizzle functions should be expected to behave any differently.
How about red.xxxw().data()? - Michael Marcin

On 12/4/06, Michael Marcin <mike@mikemarcin.com> wrote:
How about red.xxxw().data()?
Are we just trying to avoid a temporary being made? Even if we manage to hide it behind a member function, a temporary of some sort will still need to be made since it's really a vec4<float &> that's returned, so there's no special knowledge the class has that will enable it to implement data() any better than: float4 white = red.xxxw(); The other option is to remove the write mask functionality and just return a vec4<float> by value, but I really like being able to specify write masks. --Michael Fawcett
participants (3)
-
Michael Fawcett
-
Michael Marcin
-
Michael Marcin