1 /* Copyright 2011 Jukka Jyl�nki
2
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7        http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License. */
14
15 /** @file float4.h
16         @author Jukka Jyl�nki
17         @brief A 4D (x,y,z,w) homogeneous vector. */
18 #pragma once
19
20 #include "../MathBuildConfig.h"
21
22 #ifdef MATH_ENABLE_STL_SUPPORT
23 #include <string>
24 #include <vector>
25 #endif
26 #include "../MathGeoLibFwd.h"
27 #include "float3.h"
28 #include "SSEMath.h"
29 #include "assume.h"
30
31 #ifdef MATH_QT_INTEROP
32 #include <QVector4D>
33 #endif
34 #ifdef MATH_OGRE_INTEROP
35 #include <OgreVector4.h>
36 #endif
37 #ifdef MATH_URHO3D_INTEROP
38 #include <Urho3D/Math/Vector4.h>
39 #endif
40
41 MATH_BEGIN_NAMESPACE
42
43 /// A 3D vector of form (x,y,z,w) in a 4D homogeneous coordinate space.
44 /** This class has two sets of member functions. The functions ending in a suffix '3' operate only on the
45         (x, y, z) part, ignoring the w component (or assuming a value of 0 or 1, where expectable). The functions
46         without the '3' suffix operate on all four elements of the vector. */
47 class ALIGN16 float4
48 {
49 public:
50         enum
51         {
52                 /// Specifies the number of elements in this vector.
53                 Size = 4
54         };
55
56 #if defined(MATH_SIMD)
57         NAMELESS_UNION_BEGIN // Allow nonstandard nameless struct in union extension on MSC.
58
59         union
60         {
61                 struct
62                 {
63 #endif
64                         /// The x component.
65                         /** A float4 is 16 bytes in size. This element lies in the memory offsets 0-3 of this class. */
66                         float x;
67                         /// The y component. [similarOverload: x]
68                         /** This element is packed to the memory offsets 4-7 of this class. */
69                         float y;
70                         /// The z component. [similarOverload: x]
71                         /** This element is packed to the memory offsets 8-11 of this class. */
72                         float z;
73                         /// The w component. [similarOverload: x]
74                         /** This element is packed to the memory offsets 12-15 of this class. */
75                         float w;
76 #if defined(MATH_SIMD)
77                 };
78                 simd4f v;
79         };
80         NAMELESS_UNION_END
81 #endif
82
83         /// The default constructor does not initialize any members of this class.
84         /** This means that the values of the members x, y, z and w are all undefined after creating a new float4 using
85                 this default constructor. Remember to assign to them before use.
86                 @see x, y, z, w. */
87         float4() {}
88
89 #ifdef MATH_EXPLICIT_COPYCTORS
90         /// The float4 copy constructor.
91         /** The copy constructor is a standard default copy-ctor, but it is explicitly written to be able to automatically pick up
92                 this function for script bindings. */
93         float4(const float4 &rhs) { x = rhs.x; y = rhs.y; z = rhs.z; w = rhs.w; }
94 #endif
95
96         /// Constructs a new float4 with the value (x, y, z, w).
97         /** @note If you are constructing a float4 from an array of consecutive values, always prefer calling "float4(ptr);" instead of "float4(ptr[0], ptr[1], ptr[2], ptr[3]);"
98                         because there is a considerable SIMD performance benefit in the first form.
99                 @see x, y, z, w. */
100         float4(float x, float y, float z, float w);
101
102         /// Constructs a new float3 with the value (xyz.x, xyz.y, xyz.z, w).
103         /** @see x, y, z, w. */
104         float4(const float3 &xyz, float w);
105
106         float4(float x, float y, const float2 &zw);
107         float4(float x, const float2 &yz, float w);
108         float4(float x, const float3 &yzw);
109         float4(const float2 &xy, const float2 &zw);
110
111         /// Constructs a new float3 with the value (xy.x, xy.y, z, w).
112         /** @see x, y, z, w. */
113         float4(const float2 &xy, float z, float w);
114
115         /// Constructs this float4 from a C array, to the value (data[0], data[1], data[2], data[3]).
116         /** @param data An array containing four elements for x, y, z and w. This pointer may not be null. */
117         explicit float4(const float *data);
118
119         /// Casts this float4 to a C array.
120         /** This function does not allocate new memory or make a copy of this float4. This function simply
121                 returns a C pointer view to this data structure. Use ptr()[0] to access the x component of this float4,
122                 ptr()[1] to access y, ptr()[2] to access z, and ptr()[3] to access the w component of this float4.
123                 @note Since the returned pointer points to this class, do not dereference the pointer after this
124                         float3 has been deleted. You should never store a copy of the returned pointer.
125                 @note This function is provided for compatibility with other APIs which require raw C pointer access
126                         to vectors. Avoid using this function in general, and instead always use the operator [] of this
127                         class to access the elements of this vector by index.
128                 @return A pointer to the first float element of this class. The data is contiguous in memory.
129                 @see operator [](). */
130         FORCE_INLINE float *ptr() { return &x; }
131         FORCE_INLINE const float *ptr() const return &x; }
132
133         /// Accesses an element of this vector using array notation.
134         /** @param index The element to get. Pass in 0 for x, 1 for y, 2 for z and 3 for w.
135                 @note If you have a non-const instance of this class, you can use this notation to set the elements of
136                         this vector as well, e.g. vec[1] = 10.f; would set the y-component of this vector. */
137         float &operator [](int index) { return At(index); }
138         CONST_WIN32 float operator [](int index) const return At(index); }
139
140         /// Accesses an element of this vector.
141         /** @param index The element to get. Pass in 0 for x, 1 for y, 2 for z and 3 for w.
142                 @note If you have a non-const instance of this class, you can use this notation to set the elements of
143                         this vector as well, e.g. vec.At(1) = 10.f; would set the y-component of this vector. */
144         float &At(int index);
145         CONST_WIN32 float At(int index) const;
146
147         /// Adds two vectors. [indexTitle: operators +,-,*,/]
148         /** This function is identical to the member function Add().
149                 @return float4(x + v.x, y + v.y, z + v.z, w + v.w); */
150         float4 operator +(const float4 &v) const;
151
152         /// Performs an unary negation of this vector. [similarOverload: operator+] [hideIndex]
153         /** This function is identical to the member function Neg().
154                 @return float4(-x, -y, -z, -w). */
155         float4 operator -() const;
156
157         /// Subtracts the given vector from this vector. [similarOverload: operator+] [hideIndex]
158         /** This function is identical to the member function Sub().
159                 @return float4(x - v.x, y - v.y, z - v.z, w - v.w); */
160         float4 operator -(const float4 &v) const;
161
162         /// Multiplies this vector by a scalar. [similarOverload: operator+] [hideIndex]
163         /** This function is identical to the member function Mul().
164                 @return float4(x * scalar, y * scalar, z * scalar, w * scalar); */
165         float4 operator *(float scalar) const;
166
167         /// Divides this vector by a scalar. [similarOverload: operator+] [hideIndex]
168         /** This function is identical to the member function Div().
169                 @return float4(x / scalar, y / scalar, z / scalar, w * scalar); */
170         float4 operator /(float scalar) const;
171
172         /// Unary operator + allows this structure to be used in an expression '+x'.
173         float4 operator +() const return *this; }
174
175         /// Adds a vector to this vector, in-place. [indexTitle: operators +=,-=,*=,/=]
176         /** @return A reference to this. */
177         float4 &operator +=(const float4 &v);
178
179         /// Subtracts a vector from this vector, in-place. [similarOverload: operator+=] [hideIndex]
180         /** @return A reference to this. */
181         float4 &operator -=(const float4 &v);
182
183         /// Multiplies this vector by a scalar, in-place. [similarOverload: operator+=] [hideIndex]
184         /** @note If w != 0, multiplying by a scalar does <b>not</b> have the effect of scaling the length of this 3D vector.
185                 @return A reference to this. */
186         float4 &operator *=(float scalar);
187
188         /// Divides this vector by a scalar, in-place. [similarOverload: operator+=] [hideIndex]
189         /** @return A reference to this. */
190         float4 &operator /=(float scalar);
191
192 #ifdef MATH_ENABLE_UNCOMMON_OPERATIONS
193         // In math textbooks, pointwise multiplication of vectors is not defined within a linear space.
194         // However, in programming it is often useful for e.g. modulating colors via pointwise multiplication.
195         // If you #define MATH_ENABLE_UNCOMMON_OPERATIONS, you'll get these operations upgraded to handy
196         // operator * and / notation and can use vec * vec and vec / vec. Otherwise, use the notation
197         // vec.Mul(vec) and vec.Div(vec) for pointwise notation. MATH_ENABLE_UNCOMMON_OPERATIONS also enables
198         // the operation scalar / vec.
199         float4 operator *(const float4 &vector) const return this->Mul(vector); }
200         float4 operator /(const float4 &vector) const return this->Div(vector); }
201         float4 &operator *=(const float4 &vector) { *this = this->Mul(vector); return *this; }
202         float4 &operator /=(const float4 &vector) { *this = this->Div(vector); return *this; }
203 #endif
204
205         /// Adds a vector to this vector. [IndexTitle: Add/Sub/Mul/Div]
206         /// @return (x+v.x, y+v.y, z+v.z, w+v.w).
207         float4 Add(const float4 &v) const return *this + v; }
208
209         /// Adds the vector (s,s,s,s) to this vector.
210         /// @note Mathematically, the addition of a vector and scalar is not defined in linear space structures,
211         ///      but this function is provided here for syntactical convenience.
212         /// @return (x+s, y+s, z+s, w+s).
213         float4 Add(float s) const;
214
215         /// Subtracts a vector from this vector. [similarOverload: Add] [hideIndex]
216         /// @return (x-v.x, y-v.y, z-v.z, w-v.w).
217         float4 Sub(const float4 &v) const return *this - v; }
218
219         /// Subtracts the vector (s,s,s,s) from this vector. [similarOverload: Add] [hideIndex]
220         /// @note Mathematically, the subtraction of a vector by a scalar is not defined in linear space structures,
221         ///      but this function is provided here for syntactical convenience.
222         /// @return (x-s, y-s, z-s, w-s).
223         float4 Sub(float s) const;
224
225         /// Subtracts this vector from the vector (s,s,s,s). [similarOverload: Add] [hideIndex]
226         /// @note Mathematically, the subtraction of a scalar by a vector is not defined in linear space structures,
227         ///      but this function is provided here for syntactical convenience.
228         /// @return (s-x, s-y, s-z, s-w).
229         float4 SubLeft(float s) const;
230
231         /// Multiplies this vector by a vector, element-wise. [similarOverload: Add] [hideIndex]
232         /// @note Mathematically, the multiplication of two vectors is not defined in linear space structures,
233         ///      but this function is provided here for syntactical convenience.
234         /// @return (x*v.x, y*v.y, z*v.z, w*v.w).
235         float4 Mul(const float4 &v) const;
236
237         /// Multiplies this vector by a scalar. [similarOverload: Add] [hideIndex]
238         /// @note If w != 0, multiplying by a scalar does <b>not</b> have the effect of scaling the length of this 3D vector.
239         /// @return (x*s, y*s, z*s, w*s).
240         float4 Mul(float s) const return *this * s; }
241
242         /// Divides this vector by a vector, element-wise. [similarOverload: Add] [hideIndex]
243         /// @note Mathematically, the division of two vectors is not defined in linear space structures,
244         ///      but this function is provided here for syntactical convenience.
245         /// @return (x/v.x, y/v.y, z/v.z, w/v.w).
246         float4 Div(const float4 &v) const;
247
248         /// Divides this vector by a scalar. [similarOverload: Add] [hideIndex]
249         /// @return (x/s, y/s, z/s, w/s).
250         float4 Div(float s) const return *this / s; }
251         
252         /// Divides the vector (s,s,s,s) by this vector, element-wise. [similarOverload: Add] [hideIndex]
253         /// @note Mathematically, the division of a scalar by a vector is not defined in linear space structures,
254         ///      but this function is provided here for syntactical convenience.
255         /// @return (s/x, s/y, s/z, s/w).
256         float4 DivLeft(float s) const;
257
258         /// Returns the (x, y) part of this vector.
259         float2 xy() const;
260
261         /// Returns the (x, y, z) part of this vector.
262         float3 xyz() const;
263
264         /// Reinterpret-casts the (x, y, z) part of this vector.
265         /** @note This aliases into this float4! Use xyz() to make a copy.
266                 @see xyz() */
267         float3 &Float3Part() { return *reinterpret_cast<float3*>(this); }
268         const float3 &Float3Part() const return *reinterpret_cast<const float3*>(this); }
269
270         /// Performs a swizzled access to this vector.
271         /** For example, Swizzled(2,1,0) return float3(z,y,x). Swizzled(3,3,3,3) returns float4(w,w,w,w).
272                 @param i Chooses the element of this vector to pick for the x value of the returned vector, in the range [0, 3].
273                 @param j Chooses the element of this vector to pick for the y value of the returned vector, in the range [0, 3].
274                 @param k Chooses the element of this vector to pick for the z value of the returned vector, in the range [0, 3].
275                 @param l Chooses the element of this vector to pick for the w value of the returned vector, in the range [0, 3].
276                 @see xyz(). */
277         float4 Swizzled(int i, int j, int k, int l) const;
278         float3 Swizzled(int i, int j, int k) const;
279         float2 Swizzled(int i, int j) const;
280
281         float4 xxxx() const;
282         float4 xxxw() const;
283         float4 yyyy() const;
284         float4 yyyw() const;
285         float4 zzzz() const;
286         float4 zzzw() const;
287         float4 wwww() const;
288
289         /// Returns float4(scalar, scalar, scalar, scalar).
290         /** @see float4::float4(float scalar), SetFromScalar(). */
291         static float4 FromScalar(float scalar);
292
293         /// Returns float4(scalar, scalar, scalar, w).
294         static float4 FromScalar(float scalar, float w);
295
296         /// Sets this float4 to (scalar, scalar, scalar, scalar).
297         /** @see float4::float4(float scalar), FromScalar(). */
298         void SetFromScalar(float scalar);
299
300         /// Sets this float4 to (scalar, scalar, scalar, w).
301         void SetFromScalar(float scalar, float w);
302
303         /// Converts the given vector represented in spherical coordinates to an euclidean vector (x,y,z,w=0) triplet.
304         /** @param azimuth The direction, or yaw, of the vector. This function uses the convention that the X-Z plane is
305                         the 2D horizontal "map" plane, with the vector (0,0,radius) corresponding to the vector in the direction azimuth=0 and inclination=0.
306                         This value is typically in the range [-pi, pi] (, or [0, 2pi]).
307                 @param inclination The elevation, or pitch, of the vector. This function uses the convention that the +Y axis
308                         points towards up, i.e. +Y is the "Zenith direction". This value is typically in the range [-pi/2, pi/2].
309                 @param radius The magnitude of the vector. This is usually >= 0, although passing in the zero vector as radius returns (0,0,0), and passing
310                         in a negative radius mirrors the coordinate along the origin.
311                 @note The returned vector will be a direction vector with w==0.
312                 @see FromSphericalCoordinates, ToSphericalCoordinates, ToSphericalCoordinatesNormalized. */
313         void SetFromSphericalCoordinates(float azimuth, float inclination, float radius);
314         void SetFromSphericalCoordinates(const float3 &spherical) { SetFromSphericalCoordinates(spherical.x, spherical.y, spherical.z); }
315         static MUST_USE_RESULT float4 FromSphericalCoordinates(float azimuth, float inclination, float radius);
316         static MUST_USE_RESULT float4 FromSphericalCoordinates(const float3 &spherical) { return FromSphericalCoordinates(spherical.x, spherical.y, spherical.z); }
317
318         /// Converts the given vector represented in spherical coordinates to an euclidean direction vector.
319         /** @param azimuth The direction, or yaw, of the vector. This function uses the convention that the X-Z plane is
320                         the 2D horizontal "map" plane, with the vector (0,0,radius) corresponding to the vector in the direction azimuth=0 and inclination=0.
321                         This value is typically in the range [-pi, pi] (, or [0, 2pi]).
322                 @param inclination The elevation, or pitch, of the vector. This function uses the convention that the +Y axis
323                         points towards up, i.e. +Y is the "Zenith direction". This value is typically in the range [-pi/2, pi/2]. */
324         void SetFromSphericalCoordinates(float azimuth, float inclination);
325         static MUST_USE_RESULT float4 FromSphericalCoordinates(float azimuth, float inclination);
326
327         /// Converts this euclidean (x,y,z) vector to spherical coordinates representation in the form (azimuth, inclination, radius).
328         /** @note This corresponds to the matrix operation R_y * R_x * (0,0,radius), where R_y is a rotation about the y-axis by azimuth,
329                         and R_x is a rotation about the x-axis by inclination.
330                 @note It is valid for the magnitude of this vector to be (very close to) zero, in which case the return value is the zero vector.
331                 @see FromSphericalCoordinates, SetFromSphericalCoordinates, ToSphericalCoordinatesNormalized. */
332         float3 ToSphericalCoordinates() const;
333
334         /// Converts this normalized euclidean (x,y,z) vector to spherical coordinates representation in the form (azimuth, inclination)
335         /** @note This function requires that this vector is normalized. This function is identical to ToSphericalCoordinates, but is slightly
336                         faster in the case this vector is known to be normalized in advance.
337                 @note This corresponsds to the matrix operation R_y * R_x * (0,0,radius), where R_y is a rotation about the y-axis by azimuth,
338                         and R_x is a rotation about the x-axis by inclination.
339                 @see ToSphericalCoordinates, FromSphericalCoordinates, SetFromSphericalCoordinates. */
340         float2 ToSphericalCoordinatesNormalized() const;
341
342         /// Sets all elements of this vector.
343         /** @see x, y, z, w, At(). */
344         void Set(float x, float y, float z, float w);
345
346         /// Computes the squared length of the (x, y, z) part of this vector.
347         /** Calling this function is faster than calling Length3(), since this function avoids computing a square root.
348                 If you only need to compare lengths to each other, but are not interested in the actual length values,
349                 you can compare by using LengthSq3(), instead of Length3(), since Sqrt() is an order-preserving
350                 (monotonous and non-decreasing) function.
351                 @note This function ignores the w component of this vector.
352                 @return x*x + y*y + z*z.
353                 @see Length3(), LengthSq4(), Length4(), Normalize3(), Normalize4(). */
354         float LengthSq3() const;
355
356         /// Computes the length of the (x, y, z) part of this vector.
357         /** @note This function ignores the w component of this vector.
358                 @return Sqrt(x*x + y*y + z*z).
359                 @see LengthSq3(), LengthSq4(), Length4(), Normalize3(), Normalize4(). */
360         float Length3() const;
361
362         /// Computes the squared length of this vector.
363         /** Calling this function is faster than calling Length4(), since this function avoids computing a square root.
364                 If you only need to compare lengths to each other, but are not interested in the actual length values,
365                 you can compare by using LengthSq4(), instead of Length4(), since Sqrt() is an order-preserving
366                 (monotonous and non-decreasing) function.
367                 @return x*x + y*y + z*z + w*w.
368                 @see Length3(), LengthSq3(), Length4(), Normalize3(), Normalize4(). */
369         float LengthSq4() const;
370         inline float LengthSq() const return LengthSq4(); }
371
372         /// Computes the length of this vector.
373         /** @return Sqrt(x*x + y*y + z*z + w*w).
374                 @see LengthSq3(), Length3(), LengthSq4(), Normalize3(), Normalize4(). */
375         float Length4() const;
376         inline float Length() const return Length4(); }
377         /// Normalizes the (x, y, z) part of this vector.
378         /** @note This function ignores the w component of this vector, retaining whatever value was set there.
379                 @note This function fails silently. If you expect to receive an error message in case the normalization
380                         fails, use the Normalized3() function.
381                 @note This function operates in-place.
382                 @return The old length of this vector, or 0 if normalization failed. In the case of failure,
383                         this vector is set to (1, 0, 0, oldW), so that Normalize() function will never result in an unnormalized vector.
384                 @see Length3(), Length4(), Normalized3(), Normalize4(), Normalized4(). */
385         float Normalize3();
386
387         /// Normalizes this vector.
388         /** @note This function fails silently. If you expect to receive an error message in case the normalization
389                         fails, use the Normalized3() function.
390                 @note This function operates in-place.
391                 @return The old length of this vector, or 0 if normalization failed. In the case of failure,
392                 this vector is set to (1, 0, 0, 0), so that Normalize() function will never result in an unnormalized vector.
393                 @see Length3(), Length4(), Normalize3(), Normalized3(), Normalized4(). */
394         float Normalize4();
395         inline float Normalize() { return Normalize4(); }
396
397         /// Returns a copy of this vector with the (x, y, z) part normalized.
398         /** The w component of this vector is carried over unchanged.
399                 @return A copy of this vector that has the (x, y, z) part normalized, and w set to the same value as in this vector.
400                         If the normalization fails, an error message is printed and the vector (1, 0, 0, oldW) is returned.
401                 @see Length3(), Length4(), Normalize3(), Normalize4(), Normalized4(). */
402         float4 Normalized3() const;
403
404         /// Returns a normalized copy of this vector.
405         /** @return A copy of this vector that has the (x, y, z) part normalized, and w set to the same value as in this vector.
406                         If the normalization fails, an error message is printed and the vector (1, 0, 0, oldW) is returned.
407                 @see Length3(), Length4(), Normalize3(), Normalize4(), Normalized3(). */
408         float4 Normalized4() const;
409         inline float4 Normalized() const return Normalized4(); }
410
411         /// Divides each element by w to produce a float4 of form (x, y, z, 1).
412         /** This function performs the <b>perspective divide</b> or the <b>homogeneous divide</b> on this vector, which is the
413                 process of dividing each element of this vector by w. If the w component of this vector is zero before division, the
414                 result of this vector will be undefined.
415                 @note This function operates in-place.
416                 @see IsWZeroOrOne(). */
417         void NormalizeW();
418
419         /// Returns true if the w component of this float4 is either 0 or 1.
420         /** This is a required condition for several functions to work correctly.
421                 @see NormalizeW(), IsZero3(), IsZero4(), IsNormalized3(), IsNormalized4(). */
422         bool IsWZeroOrOne(float epsilon = 1e-3f) const;
423
424         /// Tests if the (x, y, z) part of this vector is equal to (0,0,0), up to the given epsilon.
425         /** @see NormalizeW(), IsWZeroOrOne(), IsZero4(), IsNormalized3(), IsNormalized4(). */
426         bool IsZero3(float epsilonSq = 1e-6f) const;
427
428         /// Returns true if this vector is equal to (0,0,0,0), up to the given epsilon.
429         /** @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsNormalized3(), IsNormalized4(). */
430         bool IsZero4(float epsilonSq = 1e-6f) const;
431         bool IsZero(float epsilonSq = 1e-6f) const return IsZero4(epsilonSq); }
432
433         /// Tests if the length of the (x, y, z) part of this vector is one, up to the given epsilon.
434         /** @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsZero4(), IsNormalized4(). */
435         bool IsNormalized3(float epsilonSq = 1e-5f) const;
436
437         /// Returns true if the length of this vector is 1, up to the given epsilon.
438         /** This function takes into account all the four components of this vector when calculating the norm.
439                 @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsZero4(), IsNormalized3(). */
440         bool IsNormalized4(float epsilonSq = 1e-5f) const;
441         bool IsNormalized(float epsilonSq = 1e-5f) const return IsNormalized4(epsilonSq); }
442
443         /// Multiplies the (x, y, z) part of this vector by the given scalar.
444         /** Sets this vector to (x*scalar, y*scalar, z*scalar, w).
445                 @note This function operates in-place.
446                 @see Length3(), Mul(), ScaleToLength3(), ScaledToLength3(). */
447         void Scale3(float scalar);
448
449         /// Scales the (x, y, z) part of this vector so that its new length is as given.
450         /** This is effectively the same as normalizing the vector first and then multiplying by newLength.
451                 @return False if the length of this vector is zero, and the vector could not be scaled to the specified length.
452                 @see Length3(), Mul(), Scale3(), ScaledToLength3(). */
453         float ScaleToLength3(float newLength);
454
455         float ScaleToLength(float newLength);
456
457         /// Returns a scaled copy of this vector which has its new length as given.
458         /** This function assumes the length of this vector is not zero.
459                 @see Length3(), Mul(), Scale3(), ScaleToLength3(). */
460         float4 ScaledToLength3(float newLength) const;
461         float4 ScaledToLength(float newLength) const;
462
463         /// Tests if this vector contains valid finite elements.
464         bool IsFinite() const;
465
466         /// Tests if the (x, y, z) parts of two vectors are perpendicular to each other.
467         bool IsPerpendicular3(const float4 &other, float epsilonSq = 1e-8f) const;
468
469         bool IsPerpendicular(const float4 &other, float epsilonSq = 1e-8f) const;
470
471         /// Makes the given vectors linearly independent.
472         /** This function directly follows the Gram-Schmidt procedure on the input vectors.
473         The vector a is kept unmodified, and vector b is modified to be perpendicular to a.
474         Finally, if specified, the vector c is adjusted to be perpendicular to a and b.
475         @note If any of the input vectors is zero, then the resulting set of vectors cannot be made orthogonal.
476         @see AreOrthogonal(), Orthonormalize(), AreOrthonormal(). */
477         static void Orthogonalize(const float4 &a, float4 &b);
478         static void Orthogonalize(const float4 &a, float4 &b, float4 &c);
479
480         /// Returns true if the given vectors are orthogonal to each other.
481         /** @see Orthogonalize(), Orthonormalize(), AreOrthonormal(), AreCollinear(). */
482         static MUST_USE_RESULT bool AreOrthogonal(const float4 &a, const float4 &b, float epsilon = 1e-3f);
483         static MUST_USE_RESULT bool AreOrthogonal(const float4 &a, const float4 &b, const float4 &c, float epsilon = 1e-3f);
484
485         /// Tests if the points p1, p2 and p3 lie on a straight line, up to the given epsilon.
486         /** @see AreOrthogonal(), AreOrthonormal(), Line::AreCollinear(). */
487         static MUST_USE_RESULT bool AreCollinear(const float4 &p1, const float4 &p2, const float4 &p3, float epsilon = 1e-7f);
488
489         /// Makes the given vectors linearly independent and normalized in length.
490         /** This function directly follows the Gram-Schmidt procedure on the input vectors.
491         The vector a is first normalized, and vector b is modified to be perpendicular to a, and also normalized.
492         Finally, if specified, the vector c is adjusted to be perpendicular to a and b, and normalized.
493         @note If any of the input vectors is zero, then the resulting set of vectors cannot be made orthonormal.
494         @see Orthogonalize(), AreOrthogonal(), AreOrthonormal(). */
495         static void Orthonormalize(float4 &a, float4 &b);
496         static void Orthonormalize(float4 &a, float4 &b, float4 &c);
497
498         /// Returns true if the given direction vectors are orthogonal to each other and all of length 1.
499         /** @note As 4D vectors, the w component is included in the computations, so call this function only for direction vectors for which w=0.
500                 @see Orthogonalize(), AreOrthogonal(), Orthonormalize(), AreCollinear(). */
501         static MUST_USE_RESULT bool AreOrthonormal(const float4 &a, const float4 &b, float epsilon = 1e-3f);
502         static MUST_USE_RESULT bool AreOrthonormal(const float4 &a, const float4 &b, const float4 &c, float epsilon = 1e-3f);
503
504 #ifdef MATH_ENABLE_STL_SUPPORT
505         /// Returns "(x, y, z, w)".
506         std::string ToString() const;
507
508         /// Returns "x,y,z,w". This is the preferred format for the float4 if it has to be serialized to a string for machine transfer.
509         std::string SerializeToString() const;
510
511         /// Returns a string of C++ code that can be used to construct this object. Useful for generating test cases from badly behaving objects.
512         std::string SerializeToCodeString() const;
513 #endif
514
515         /// Parses a string that is of form "x,y,z,w" or "(x,y,z,w)" or "(x;y;z;w)" or "x y z w" to a new float4.
516         static float4 FromString(const char *str, const char **outEndStr = 0);
517 #ifdef MATH_ENABLE_STL_SUPPORT
518         static float4 FromString(const std::string &str) { return FromString(str.c_str()); }
519 #endif
520
521         /// @return x + y + z + w.
522         float SumOfElements() const;
523
524         /// @return x * y * z * w.
525         float ProductOfElements() const;
526
527         /// @return (x+y+z+w)/4.
528         float AverageOfElements() const;
529
530         /// @return Min(x, y, z, w).
531         /** @see MinElementIndex(). */
532         float MinElement() const;
533
534         /// Returns the index that has the smallest value in this vector.
535         /** @see MinElement(). */
536         int MinElementIndex() const;
537
538         /// @return Max(x, y, z, w).
539         /** @see MaxElementIndex(). */
540         float MaxElement() const;
541
542         /// Returns the index that has the smallest value in this vector.
543         /** @see MaxElement(). */
544         int MaxElementIndex() const;
545
546         /// Takes the element-wise absolute value of this vector.
547         /** @return float4(|x|, |y|, |z|, |w|).
548                 @see Neg3(), Neg4(). */
549         float4 Abs() const;
550
551         /// Returns a copy of this vector with the x, y and z elements negated.
552         /** @return float4(-x, -y, -z, w).
553                 @see Abs(), Neg4(). */
554         float4 Neg3() const;
555
556         /// Returns a copy of this vector with each element negated.
557         /** @return float4(-x, -y, -z, -w).
558                 @see Abs(), Neg3(). */
559         float4 Neg4() const;
560
561         /// Computes the element-wise reciprocal of the three first elements of this vector.
562         /** This function returns a new vector where the x, y and z elements of the original vector are replaced by
563                 the values 1/x, 1/y and 1/z.
564                 @return float4(1/x, 1/y, 1/z, w). */
565         float4 Recip3() const;
566
567         /// Computes the element-wise reciprocal of this vector.
568         /** This function returns a new vector where each element x of the original vector is replaced by the value 1/x.
569                 This function operates on all four elements of this vector.
570                 @return float4(1/x, 1/y, 1/z, 1/w). */
571         float4 Recip4() const;
572
573         /// Computes the element-wise reciprocal of this vector using a fast approximation (SSE rcp instruction).
574         /** This function returns a new vector where each element x of the original vector is replaced by the value 1/x.
575                 This function operates on all four elements of this vector.
576                 @return float4(1/x, 1/y, 1/z, 1/w). */
577         float4 RecipFast4() const;
578
579         /// Returns an element-wise minimum of this and the vector (ceil, ceil, ceil, ceil).
580         /** Each element that is larger than ceil is replaced by ceil. */
581         float4 Min(float ceil) const;
582
583         /// Returns an element-wise minimum of this and the given vector.
584         /** Each element that is larger than ceil is replaced by ceil.
585                 @see Max(), Clamp(). */
586         float4 Min(const float4 &ceil) const;
587
588         /// Returns an element-wise maximum of this and the vector (floor, floor, floor, floor).
589         /** Each element that is smaller than floor is replaced by floor. */
590         float4 Max(float floor) const;
591
592         /// Returns an element-wise maximum of this and the given vector.
593         /** Each element that is smaller than floor is replaced by floor.
594                 @see Min(), Clamp(). */
595         float4 Max(const float4 &floor) const;
596
597         /// Returns a vector that has floor <= this[i] <= ceil for each element.
598         float4 Clamp(float floor, float ceil) const;
599
600         /// Limits each element of this vector between the corresponding elements in floor and ceil.
601         /** @see Min(), Max(), Clamp01(). */
602         float4 Clamp(const float4 &floor, const float4 &ceil) const;
603
604         /// Limits each element of this vector in the range [0, 1].
605         /** @see Min(), Max(), Clamp(). */
606         float4 Clamp01() const;
607
608         /// Linearly interpolates between this and the vector b.
609         /** This function assumes that the w components of this and the other vector are equal.
610                 @param b The target endpoint to lerp towards to.
611                 @param t The interpolation weight, in the range [0, 1].
612                 Lerp(b, 0) returns this vector, Lerp(b, 1) returns the vector b.
613                 Lerp(b, 0.5) returns the vector half-way in between the two vectors, and so on. */
614         float4 Lerp(const float4 &b, float t) const;
615         static float4 Lerp(const float4 &a, const float4 &b, float t);
616
617         /// Computes the squared distance between the (x, y, z) parts of this and the given float4.
618         /** @note This function ignores the w component of this and rhs vector (assumes w=0 or w=1 are the same for both vectors).
619                 @see Distance3(), Length3Sq(), Length3().
620                 @return (x-rhs.x)^2 + (y-rhs.y)^2 + (z-rhs.z)^2. */
621         float Distance3Sq(const float4 &rhs) const;
622
623         /// Computes the distance between the (x, y, z) parts of this and the given float4.
624         /** @note This function ignores the w component of this and rhs vector (assumes w=0 or w=1 are the same for both vectors).
625                 @see Distance3Sq(), Length3Sq(), Length3().
626                 @return Sqrt((x-rhs.x)^2 + (y-rhs.y)^2 + (z-rhs.z)^2). */
627         float Distance3(const float4 &rhs) const;
628
629         /// Computes the squared distance between this and the given float4.
630         /** @note This function computes the square of the Euclidean distance of the two vectors in 4D space (taking into account the w component).
631                 @see Distance4Sq(), Distance3(), Distance3Sq(), Length3Sq(), Length3().
632                 @return (x-rhs.x)^2 + (y-rhs.y)^2 + (z-rhs.z)^2 + (w-rhs.w)^2. */
633         float Distance4Sq(const float4 &rhs) const;
634         inline float DistanceSq(const float4 &rhs) const return Distance4Sq(rhs); }
635
636         /// Computes the distance between this and the given float4.
637         /** @note This function computes the Euclidean distance of the two vectors in 4D space (taking into account the w component).
638                 @see Distance4Sq(), Distance3(), Distance3Sq(), Length3Sq(), Length3().
639                 @return Sqrt((x-rhs.x)^2 + (y-rhs.y)^2 + (z-rhs.z)^2 + (w-rhs.w)^2). */
640         float Distance4(const float4 &rhs) const;
641         inline float Distance(const float4 &rhs) const return Distance4(rhs); }
642
643         /// Computes the dot product of the (x, y, z) parts of this and the given float4.
644         /** @note This function ignores the w component of this vector (assumes w=0).
645                 @see Dot4(), Cross3(). */
646         float Dot3(const float3 &rhs) const;
647         float Dot3(const float4 &rhs) const;
648
649         /// Computes the dot product of this and the given float4, taking into account the w component.
650         /** @see Dot3(), Cross3(). */
651         float Dot4(const float4 &rhs) const;
652
653         inline float Dot(const float4 &rhs) const return Dot4(rhs); }
654
655         /// Computes the cross product of the (x, y, z) parts of this and the given vector. Returns a vector with w=0.
656         /** @see Dot3(), Dot4(). */
657         float4 Cross3(const float3 &rhs) const;
658         float4 Cross3(const float4 &rhs) const;
659
660         float4 Cross(const float4 &rhs) const return Cross3(rhs); }
661
662         /// Computes the outer product of this and the given vector.
663         float4x4 OuterProduct(const float4 &rhs) const;
664
665         /// Returns a new normalized direction vector that points as close as possible towards the given hint vector.
666         float4 Perpendicular3(const float3 &hint = float3(0,1,0), const float3 &hint2 = float3(0,0,1)) const;
667         float4 Perpendicular(const float4 &hint = float4(0,1,0,0), const float4 &hint2 = float4(0,0,1,0)) const;
668
669         /// Returns another vector that is perpendicular to this vector and the vector returned by Perpendicular3(hint).
670         /** @todo Enforce that (x: this, y: Perpendicular3(), z: AnotherPerpendicular3) form a right-handed basis.
671                 @see Perpendicular3(). */
672         float4 AnotherPerpendicular3(const float3 &hint = float3(0,1,0), const float3 &hint2 = float3(0,0,1)) const;
673         float4 AnotherPerpendicular(const float4 &hint = float4(0,1,0,0), const float4 &hint2 = float4(0,0,1,0)) const;
674
675         // Completes this vector to generate a perpendicular basis.
676         /** This function computes two new vectors b and c which are both orthogonal to this vector and to each other.
677                 That is, the set { this, b, c} is an orthogonal set. The vectors b and c that are outputted are also normalized.
678                 @param outB [out] Receives vector b.
679                 @param outC [out] Receives vector c.
680                 @note When calling this function, this vector should not be zero! */
681         void PerpendicularBasis(float4 &outB, float4 &outC) const;
682
683         /// Generates a random vector that is perpendicular to this vector.
684         /** The distribution is uniformly random. */
685         float4 RandomPerpendicular(LCG &rng) const;
686
687         /// Returns this vector reflected about a plane with the given normal.
688         /** By convention, both this and the reflected vector point away from the plane with the given normal.
689                 @note This function ignores the w component of this vector (assumes w=0). */
690         float4 Reflect3(const float3 &normal) const;
691         float4 Reflect(const float4 &normal) const;
692
693         float4 Refract(const float4 &normal, float negativeSideRefractionIndex, float positiveSideRefractionIndex) const;
694
695         /// Returns the angle between this vector and the specified vector, in radians.
696         /** @note This function takes into account that this vector or the other vector can be unnormalized, and
697                         normalizes the computations.
698                 @note This function ignores the w component of this vector (assumes w=0).
699                 @see Dot3(), AngleBetweenNorm3(), AngleBetween4(), AngleBetweenNorm4(). */
700         float AngleBetween3(const float4 &other) const;
701
702         /// Returns the angle between this vector and the specified normalized vector, in radians.
703         /** @note This vector must be normalized to call this function.
704                 @note This function ignores the w component of this vector (assumes w=0).
705                 @see Dot3(), AngleBetween3(), AngleBetween4(), AngleBetweenNorm4(). */
706         float AngleBetweenNorm3(const float4 &normalizedVector) const;
707
708         /// Returns the angle between this vector and the specified vector, in radians.
709         /** @note This function takes into account that this vector or the other vector can be unnormalized, and normalizes the computations.
710                 @see Dot3(), AngleBetween3(), AngleBetweenNorm3(), AngleBetweenNorm4(). */
711         float AngleBetween4(const float4 &other) const;
712
713         /// Returns the angle between this vector and the specified normalized vector, in radians.
714         /** @note This vector must be normalized to call this function.
715                 @see Dot3(), AngleBetween3(), AngleBetweenNorm3(), AngleBetween4(). */
716         float AngleBetweenNorm4(const float4 &normalizedVector) const;
717
718         /// Projects this vector onto the given vector.
719         /** @note This function treats this and target vector as direction vectors.
720                 @note This function ignores the w component of this vector (assumes w=0 or 1) and returns it unmodified.
721                 @see ProjectToNorm3(). */
722         float4 ProjectTo3(const float3 &target) const;
723
724         float4 ProjectTo(const float4 &target) const;
725
726         /// Projects this vector onto the given vector.
727         /** @param target The direction vector to project onto. This vector must be normalized.
728                 @note This function treats this and target vector as direction vectors.
729                 @note This function ignores the w component of this vector (assumes w=0 or 1) and returns it unmodified.
730                 @see ProjectTo3(). */
731         float4 ProjectToNorm3(const float3 &target) const;
732
733         float4 ProjectToNorm(const float4 &target) const;
734
735         /// Returns true if this vector is equal to the given vector, up to given per-element epsilon.
736         bool Equals(const float4 &other, float epsilon = 1e-3f) const;
737         bool Equals(float x, float y, float z, float w, float epsilon = 1e-3f) const;
738
739         /// Compares whether this float4 and the given float4 are identical bit-by-bit in the underlying representation.
740         /** @note Prefer using this over e.g. memcmp, since there can be SSE-related padding in the structures. */
741         bool BitEquals(const float4 &other) const;
742
743         /// Generates a direction vector of the given length pointing at a uniformly random direction.
744         /* The w-component for the returned vector is 0.
745         @see RandomSphere(), RandomBox(). */
746         static MUST_USE_RESULT float4 RandomDir(LCG &lcg, float length = 1.f);
747         /// Generates a random point inside a sphere.
748         /** The returned point is generated uniformly inside the sphere.
749         @see RandomDir(), RandomBox(). */
750         static MUST_USE_RESULT float4 RandomSphere(LCG &lcg, const float4 &center, float radius);
751         /// Generates a random point inside an axis-aligned box.
752         /** The returned point is generated uniformly inside the box.
753         @see RandomDir(), RandomSphere(). */
754         static MUST_USE_RESULT float4 RandomBox(LCG &lcg, float xmin, float xmax, float ymin, float ymax, float zmin, float zmax);
755         static MUST_USE_RESULT float4 RandomBox(LCG &lcg, const float4 &minValues, const float4 &maxValues);
756
757         /// Returns a random float3 with each entry randomized between the range [minElem, maxElem].
758         static MUST_USE_RESULT float4 RandomBox(LCG &lcg, float minElem, float maxElem);
759
760         /// Returns a random float4 with each entry randomized between the range [minElem, maxElem].
761         /** Warning: The vectors returned by this function generally have w != 0 or 1, so they don't do not represent
762                 well-formed 3D points or direction vectors.
763                 This function is mostly used for testing and debugging purposes only. */
764         static float4 RandomGeneral(LCG &lcg, float minElem, float maxElem);
765
766         /// Specifies a compile-time constant float4 with value (0, 0, 0, 0).
767         /** @note Due to static data initialization order being undefined in C++, do NOT use this
768                         member to initialize other static data in other compilation units! */
769         static const float4 zero;
770
771         /// Specifies a compile-time constant float4 with value (1, 1, 1, 1). [similarOverload: zero]
772         /** @note Due to static data initialization order being undefined in C++, do NOT use this
773                         member to initialize other static data in other compilation units! */
774         static const float4 one;
775
776         /// Specifies a compile-time constant float4 with value (1, 0, 0, 0).
777         /** @note Due to static data initialization order being undefined in C++, do NOT use this
778                         member to initialize other static data in other compilation units! */
779         static const float4 unitX;
780
781         /// Specifies a compile-time constant float4 with value (0, 1, 0, 0). [similarOverload: unitX]
782         /** @note Due to static data initialization order being undefined in C++, do NOT use this
783                         member to initialize other static data in other compilation units! */
784         static const float4 unitY;
785
786         /// Specifies a compile-time constant float4 with value (0, 0, 1, 0). [similarOverload: unitX]
787         /** @note Due to static data initialization order being undefined in C++, do NOT use this
788                         member to initialize other static data in other compilation units! */
789         static const float4 unitZ;
790
791         /// Specifies a compile-time constant float4 with value (0, 0, 0, 1). [similarOverload: unitX]
792         /** @note Due to static data initialization order being undefined in C++, do NOT use this
793                         member to initialize other static data in other compilation units! */
794         static const float4 unitW;
795
796         /// A compile-time constant float4 with value (NaN, NaN, NaN, NaN).
797         /** For this constant, each element has the value of quiet NaN, or Not-A-Number.
798                 @note Never compare a float4 to this value! Due to how IEEE floats work, "nan == nan" returns false!
799                           That is, nothing is equal to NaN, not even NaN itself!
800                 @note Due to static data initialization order being undefined in C++, do NOT use this
801                         member to initialize other static data in other compilation units! */
802         static const float4 nan;
803
804         /// A compile-time constant float4 with value (+infinity, +infinity, +infinity, +infinity). [similarOverload: nan]
805         /** @note Due to static data initialization order being undefined in C++, do NOT use this
806                         member to initialize other static data in other compilation units! */
807         static const float4 inf;
808
809 #ifdef MATH_OGRE_INTEROP
810         float4(const Ogre::Vector4 &other): x(other.x), y(other.y), z(other.z), w(other.w) {}
811         float4 &operator =(const Ogre::Vector4 &other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
812         operator Ogre::Vector4() const return Ogre::Vector4(x, y, z, w); }
813 #endif
814 #ifdef MATH_QT_INTEROP
815         float4(const QVector4D &other):x(other.x()), y(other.y()), z(other.z()), w(other.w()) {}
816         operator QVector4D() const return QVector4D(x, y, z, w); }
817         operator QString() const return "float4(" + QString::number(x) + "," + QString::number(y) + "," + QString::number(z) + "," + QString::number(w) + ")"; }
818         QString toString() const return (QString)*this; }
819         QVector4D ToQVector4D() const return QVector4D(x, y, z, w); }
820         static float4 FromQVector4D(const QVector4D &v) { return (float4)v; }
821         static float4 FromString(const QString &str) { return FromString(str.toStdString()); }
822 #endif
823 #ifdef MATH_BULLET_INTEROP
824         // Bullet uses the same btVector3 class for both 3- and 4 -tuples (due to SSE).
825         float4(const btVector3 &other):x(other.x()), y(other.y()), z(other.z()), w(other.w()) {}
826         operator btVector3() const { btVector3 v(x, y, z); v.setW(w); return v; }
827 #endif
828 #ifdef MATH_URHO3D_INTEROP
829         float4(const Urho3D::Vector4 &other) : x(other.x_), y(other.y_), z(other.z_), w(other.w_) {}
830         operator Urho3D::Vector4() const return Urho3D::Vector4(x, y, z, w); }
831 #endif
832
833 #ifdef MATH_SIMD
834         float4(simd4f vec):v(vec) {}
835
836         ///\todo All the _SSE() functions will be deleted in favor of C SSE API.
837         simd4f Swizzled_SSE(int i, int j, int k, int l) const;
838         simd4f LengthSq3_SSE() const;
839         simd4f Length3_SSE() const;
840         simd4f LengthSq4_SSE() const;
841         simd4f Length4_SSE() const;
842         simd4f Normalize4_SSE();
843         void Normalize3_Fast_SSE();
844         void Normalize4_Fast_SSE();
845         void NormalizeW_SSE();
846         simd4f SumOfElements_SSE() const;
847
848         inline float4 &operator =(simd4f vec) { v = vec; return *this; }
849
850         inline operator simd4f() const return v; }
851 #endif
852 };
853
854 struct float4_storage
855 {
856         float x,y,z,w;
857         float4_storage(){}
858         float4_storage(const float4 &rhs)
859         {
860                 *reinterpret_cast<float4*>(this) = rhs;
861         }
862         operator float4() const return *reinterpret_cast<const float4*>(this); }
863 };
864
865 #ifdef MATH_ENABLE_STL_SUPPORT
866 /// Prints this float4 to the given stream.
867 std::ostream &operator <<(std::ostream &out, const float4 &rhs);
868 #endif
869
870 /// Multiplies the x, y, z and w components of the vector by the given scalar. Note that if w != 0,
871 /// this does NOT scale the length of the homogeneous 3D vector.
872 float4 operator *(float scalar, const float4 &rhs);
873
874 #ifdef MATH_ENABLE_UNCOMMON_OPERATIONS
875 inline float4 operator /(float scalar, const float4 &rhs) { return float4::FromScalar(scalar) / rhs; }
876 #endif
877
878 inline float Dot3(const float4 &a, const float4 &b) { return a.Dot3(b); }
879 inline float Dot4(const float4 &a, const float4 &b) { return a.Dot4(b); }
880 inline float Dot(const float4 &a, const float4 &b) { return a.Dot(b); }
881 inline float4 Cross3(const float4 &a, const float4 &b) { return a.Cross3(b); }
882 inline float4 Cross(const float4 &a, const float4 &b) { return a.Cross(b); }
883 inline float4 Abs(const float4 &a) { return a.Abs(); }
884 inline float Length3(const float4 &a) { return a.Length3(); }
885 inline float Length4(const float4 &a) { return a.Length4(); }
886 inline float Distance3(const float4 &a, const float4 &b) { return a.Distance3(b); }
887 inline float Distance4(const float4 &a, const float4 &b) { return a.Distance4(b); }
888 inline float4 Min(const float4 &a, const float4 &b) { return a.Min(b); }
889 inline float4 Max(const float4 &a, const float4 &b) { return a.Max(b); }
890 inline float4 Clamp(const float4 &a, float floor, float ceil) { return a.Clamp(floor, ceil); }
891 inline float4 Clamp(const float4 &a, const float4 &floor, const float4 &ceil) { return a.Clamp(floor, ceil); }
892 inline float4 Clamp01(const float4 &a) { return a.Clamp01(); }
893 inline float4 Lerp(const float4 &a, const float4 &b, float t) { return a.Lerp(b, t); }
894
895 #ifdef MATH_QT_INTEROP
896 Q_DECLARE_METATYPE(float4)
897 Q_DECLARE_METATYPE(float4*)
898 #endif
899
900 MATH_END_NAMESPACE

Go back to previous page