| Yours3lf (74) | |||
|
Hi, I'm writing a math library, and for this I need to implement vector swizzling like in GLSL/HLSL/CG. I've already implemented swizzling when it's done like this: vec2 a = b.yx; However this doesn't work: b.yx = a; I think it might be because get() returns a constant value, and that isn't changed. My question is how can this be implemented? code:
| |||
|
|
|||
| slicedpan (155) | |||
After some messing around I came up with the following code:
This allows you to remove the #defines also, since the = operator is defined in terms of the _swizzle class. Note that if you want to make swizzle operations for vec3 you will need to define 5 extra internal classes and assignment operators, and for a vec4 it will be 23 (I think its (n! - 1) for an n-dimensional vector). | |||
|
|
|||
| xerzi (570) | |
|
xy and yx are turning a copy, defines shouldn't be used like this, what if someone wants to declare a variable xy or yx ? Now they can't. You shouldn't be trying to modify it just to create similar syntax, anyone else trying to read this code will be confused. There's an article somewhere here I think that describes improper and proper uses of the preprocessor and this is definitely improper. If you still want to continue even so: a.yx = b; // not working you are modifying a new vec2, the one constructed in the function yx(), not a. | |
|
|
|
| Yours3lf (74) | |
|
thank you :) it works AND I understand how you did it :D | |
|
|
|
| Yours3lf (74) | |
|
@xerzi I'm aware of that bad preprocessor usage. I would've made it optional. | |
|
|
|
| Yours3lf (74) | |||
I upgraded your method a little bit with templates, so now it only requires 1 class per type (say vec2, vec3 etc).
| |||
|
Last edited on
|
|||
| slicedpan (155) | |
| Nice one! After I wrote that code I was thinking it might be easier to use templates alright, this looks like a great solution. | |
|
|
|
| Yours3lf (74) | |
|
note that you'll need to overload the default constructor as well in case of vec2 a; vec2 b = a; | |
|
|
|
| xerzi (570) | |
|
You are increasing the size of the structure by three fold... Instead of the reference in swizzle you have an array of 2 floats and add the xy, xx, etc... to the union and now you save 3x the space you would have been wasting and decreasing speed by forcing the use of an unneeded pointer. | |
|
|
|
| Yours3lf (74) | |||
|
@xerzi but what will happen in case of: a = b.yx; that would just copy the two floats into a in the same order, right? and how would you implement it, like this?
if implemented like this it gives me invalid array assignment when I try this: a.xy = b.xy; The point is that all these cases should work: a = b; a.xy = b; a = b.xy; a.xy = b.xy; | |||
|
Last edited on
|
|||
| kev82 (319) | |
| Would this not be much better done with a valarray? You can rearrange elements of a valarray as you like by indexing it with a valarray<int>. | |
|
|
|
| Yours3lf (74) | |||
|
@kev82 and can you use that in the above manner? this for example gives me 2, 2, instead of 2, 1
| |||
|
|
|||
| kev82 (319) | |
|
You are modifying the object you are reading from. I assumed in all your examples above, a and b are different objects. If you must do this, then you will have to use a temporary object - I would suggest wrapping the valarray up (you need to anyway as they don't behave with proper c++ semantics) and creating a special assignment function for these cases that assigns to a temp, then does a swap. Assuming you don't want to modify the object you're reading from, then yes, I think it works as you want. | |
|
|
|
| xerzi (570) | |||
More like this:
idk how you want it to handle yy and xx input as that is redundant: a.xx = b.yy; using the above code anyways it'll set the x of a to the y of b, twice. | |||
|
Last edited on
|
|||
| Yours3lf (74) | ||||||
|
@xerzi BIG thank you!!! :D :D I tried it out and this seems to be the best solution of all, simple and usable. The result of combining all our ideas gave birth to the best solution yet. That is how it should perform. I guess the compiler will optimize that out. Note that to make it perform right with vector operations I rather put them in a struct. So they'll perform just as floats. This way this doesn't happen: a.xx += a.yy; --> x += y; x += y; I wrote some test cases:
all of them perform as expected:
@kev82 no, all of the crazy cases should work, whether the same object or not, no matter how the assignment goes like: swizzle = swizzle swizzle = vec vec = swizzle and the same applies to all the operators like +=, -=, *=, /=, +, -, *, / etc. EDIT: ok, so I reread the GLSL specs again about swizzling, and it turns out that it should behave like this:
| ||||||
|
Last edited on
|
||||||
| xerzi (570) | |||
You can add a specialization to swizzle for when A == B:
You'll need to make xx and yy both a swizzle again. | |||
|
Last edited on
|
|||
| Yours3lf (74) | |
| ok, thanks :) | |
|
|
|