g-truc / glm

OpenGL Mathematics (GLM)
https://glm.g-truc.net
Other
8.98k stars 2.09k forks source link

Assigning to swizzle fails #786

Open hmarthinsen opened 6 years ago

hmarthinsen commented 6 years ago

Compiling this short program fails:

#define GLM_FORCE_SWIZZLE
#define GLM_FORCE_MESSAGES
#include <glm/glm.hpp>

int main()
{
    glm::vec3 a(1, 2, 3);
    glm::vec3 b(4, 5, 6);

    a.xy = b.xy;
}

Here are the error messages:

In file included from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:35:0,
                 from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/glm.hpp:90,
                 from swizzletest.cpp:3:
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/../simd/platform.h:63:49: note: #pragma message: GLM: Linux platform detected
 #  pragma message("GLM: Linux platform detected")
                                                 ^
In file included from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/glm.hpp:90:0,
                 from swizzletest.cpp:3:
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:42:41: note: #pragma message: GLM: version 0.9.9.1
 # pragma message ("GLM: version 0.9.9.1")
                                         ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:57:47: note: #pragma message: GLM: GCC compiler detected
 #  pragma message("GLM: GCC compiler detected")
                                               ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:88:39: note: #pragma message: GLM: 64 bits model
 #  pragma message("GLM: 64 bits model")
                                       ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:111:46: note: #pragma message: GLM: SSE2 instruction set
 #  pragma message("GLM: SSE2 instruction set")
                                              ^
In file included from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/glm.hpp:90:0,
                 from swizzletest.cpp:3:
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:232:31: note: #pragma message: GLM: C++14
 #  pragma message("GLM: C++14")
                               ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:567:53: note: #pragma message: GLM: Swizzling operators enabled
 #  pragma message("GLM: Swizzling operators enabled")
                                                     ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:618:63: note: #pragma message: GLM: Depth clip space: negative one to one
 #  pragma message("GLM: Depth clip space: negative one to one")
                                                               ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:640:57: note: #pragma message: GLM: Coordinate system: right handed
 #  pragma message("GLM: Coordinate system: right handed")
                                                         ^
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/setup.hpp:744:108: note: #pragma message: GLM: .length() returns glm::length_t, a typedef of int following the GLSL specification
 #  pragma message("GLM: .length() returns glm::length_t, a typedef of int following the GLSL specification")
                                                                                                            ^
In file included from swizzletest.cpp:3:0:
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/glm.hpp:103:46: note: #pragma message: GLM: Core library included
 # pragma message("GLM: Core library included")
                                              ^
In file included from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/func_integer.inl:4:0,
                 from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/integer.hpp:211,
                 from /home/hakonm/Programming/modhot-base/thirdparty/glm/glm/glm.hpp:126,
                 from swizzletest.cpp:3:
/home/hakonm/Programming/modhot-base/thirdparty/glm/glm/detail/../ext/vec1.hpp:27:56: note: #pragma message: GLM: GLM_EXT_vec1 extension included
 # pragma message("GLM: GLM_EXT_vec1 extension included")
                                                        ^
swizzletest.cpp: In function ‘int main()’:
swizzletest.cpp:10:7: error: invalid use of member function ‘glm::vec<2, T, Q> glm::vec<3, T, Q>::xy() const [with T = float; glm::qualifier Q = (glm::qualifier)0u]’ (did you forget the ‘()’ ?)
     a.xy = b.xy;
     ~~^~
Groovounet commented 6 years ago

Thanks for the report.

a.xy = b.xy; is an historical issue in GLM swizzle implementation. Unless I am mistaken, even on previous versions, this code would compile but fail to do the assignment. This is due to some specific constructor rules (used by the swizzle operator implementation) where we can't assign if the types are the same on both sides of the assignment operators.

It's correct that this is not tested in GLM because I think I gave up on left side swizzle operators which are very complicated to implement for very little use.

Are you using left side swizzle operators in your project?

hmarthinsen commented 6 years ago

Yes, I'm using left (and right) side swizzles in my project, e.g. like this:

a.x += tmp.x;
b.yz -= tmp.yz;

where a, b, and tmp are glm::vec3s. This code compiled yesterday. Chapter 2 of the manual says that

vec4 A;
vec2 B;
B.yx = A.wy;

is legal code. I tried compiling it and this gives the same compilation error as in my first example.

Groovounet commented 6 years ago

Ok, I'll investigate.

Both case you mention used to be something that worked, only:

vec4 A;
vec2 B;
B.yx = A.yx;

was the issue case and as far as I remember didn't have any known solution unfortunately...

hmarthinsen commented 6 years ago

I think silently doing nothing in the a.xy = b.xy case is quite bad. I think this is unexpected behaviour. Could you at least give a compiler warning in this case?

Groovounet commented 6 years ago

I can confirm that a.xy = b.xy is not working as expected. Actually only the first component get copied. I have no idea if throwing a warning or an error is possible.

I'll investigate further to either have an option to disable left side swizzle operator or better document this case.

Thanks, Christophe

tigert1998 commented 5 years ago

I can confirm that a.xy = b.xy is not working as expected. Actually only the first component get copied. I have no idea if throwing a warning or an error is possible.

I'll investigate further to either have an option to disable left side swizzle operator or better document this case.

Thanks, Christophe

Would you think it an appropriate way to implement swizzle with std::tuple?

tigert1998 commented 5 years ago

Because c++ does not have a getter or setter for a member, may be the only way is to implement two functions.

void set_xy(vec2);
vec2 xy();

And it's the same with other combinations such as yx.

axxel commented 5 years ago

I saw a cppcon talk by Valentin Galea: https://www.youtube.com/watch?v=8FoAxasNssA. He seems to have taken another approach at the swizzling problem (no unions and no member functions) with the explicit goal of supporting GLSL swizzles exactly as they are. Given a c++17 compiler, maybe adopting that approach would be worth a consideration?