Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #ifndef EZ_TOOLS_VEC4
4 : : #define EZ_TOOLS_VEC4
5 : : #endif // EZ_TOOLS_VEC4
6 : :
7 : : /*
8 : : MIT License
9 : :
10 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
11 : :
12 : : Permission is hereby granted, free of charge, to any person obtaining a copy
13 : : of this software and associated documentation files (the "Software"), to deal
14 : : in the Software without restriction, including without limitation the rights
15 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 : : copies of the Software, and to permit persons to whom the Software is
17 : : furnished to do so, subject to the following conditions:
18 : :
19 : : The above copyright notice and this permission notice shall be included in all
20 : : copies or substantial portions of the Software.
21 : :
22 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 : : SOFTWARE.
29 : : */
30 : :
31 : : // ezVec4 is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
32 : :
33 : : #include <cmath>
34 : : #include <string>
35 : : #include <vector>
36 : : #include <type_traits>
37 : :
38 : : namespace ez {
39 : :
40 : : // Restrict the template to relevant types only (e.g., disable bool)
41 : : template <typename T>
42 : : struct vec4 {
43 : : static_assert(!std::is_same<T, bool>::value, "vec4 cannot be instantiated with bool type");
44 : :
45 : : T x = 0;
46 : : T y = 0;
47 : : T z = 0;
48 : : T w = 0;
49 : :
50 : : // Default constructor
51 : 24 : vec4() = default;
52 : :
53 : : // Constructor with type conversion
54 : : template <typename U>
55 : : vec4(const vec4<U>& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)), w(static_cast<T>(a.w)) {}
56 : :
57 : : // Constructor with type conversion
58 : : template <typename U>
59 : : vec4(const U& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)), w(static_cast<T>(a.w)) {}
60 : :
61 : : // Constructor using vec2 components
62 : : vec4(const vec2<T>& xy, const vec2<T>& zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
63 : :
64 : : // Constructor using vec3 and a scalar
65 : : vec4(const vec3<T>& xyz, T w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
66 : :
67 : : // Constructor with a single scalar for all components
68 : : vec4(T xyzw) : x(xyzw), y(xyzw), z(xyzw), w(xyzw) {}
69 : :
70 : : // Constructor with specific values
71 : 246 : vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
72 : :
73 : : // Constructor from a string
74 : : vec4(const std::string& vec, char c = ';', vec4<T>* def = nullptr) {
75 : : if (def) {
76 : : x = def->x;
77 : : y = def->y;
78 : : z = def->z;
79 : : w = def->w;
80 : : }
81 : : std::vector<T> result = str::stringToNumberVector<T>(vec, c);
82 : : const size_t s = result.size();
83 : : if (s > 0)
84 : : x = result[0];
85 : : if (s > 1)
86 : : y = result[1];
87 : : if (s > 2)
88 : : z = result[2];
89 : : if (s > 3)
90 : : w = result[3];
91 : : }
92 : :
93 : : // Alternate constructor from a string with size checking
94 : : vec4(const std::string& vec, char c = ';', int n = 4, vec4<T>* def = nullptr) {
95 : : if (def) {
96 : : x = def->x;
97 : : y = def->y;
98 : : z = def->z;
99 : : w = def->w;
100 : : }
101 : : std::vector<T> result = str::stringToNumberVector<T>(vec, c);
102 : : const size_t s = result.size();
103 : : if (static_cast<int>(s) != n) {
104 : : if (s == 1) {
105 : : x = y = z = w = result[0];
106 : : } else if (s == 2) {
107 : : x = y = result[0];
108 : : z = w = result[1];
109 : : } else if (s == 3) {
110 : : x = result[0];
111 : : y = result[1];
112 : : z = result[2];
113 : : }
114 : : } else {
115 : : if (s > 0)
116 : : x = result[0];
117 : : if (s > 1)
118 : : y = result[1];
119 : : if (s > 2)
120 : : z = result[2];
121 : : if (s > 3)
122 : : w = result[3];
123 : : }
124 : : }
125 : :
126 : : // Indexing operator
127 : : T& operator[](size_t i) { return (&x)[i]; }
128 : :
129 : : // Offset the vector
130 : 6 : vec4 Offset(T vX, T vY, T vZ, T vW) const { return vec4(x + vX, y + vY, z + vZ, w + vW); }
131 : :
132 : : // Set the vector's components
133 : 6 : void Set(T vX, T vY, T vZ, T vW) {
134 : 6 : x = vX;
135 : 6 : y = vY;
136 : 6 : z = vZ;
137 : 6 : w = vW;
138 : 6 : }
139 : :
140 : : // Negation operator
141 : 2 : vec4 operator-() const {
142 : 2 : static_assert(std::is_signed<T>::value, "Negate is only valid for signed types");
143 : 2 : return vec4(-x, -y, -z, -w);
144 : 2 : }
145 : :
146 : : // Logical NOT operator, only for integral types
147 : 2 : vec4 operator!() const {
148 : 2 : static_assert(std::is_integral<T>::value, "Logical NOT is only valid for integral types");
149 : 2 : return vec4(!x, !y, !z, !w);
150 : 2 : }
151 : :
152 : : // Extract 2D and 3D vectors from 4D vector
153 : 6 : vec2<T> xy() const { return vec2<T>(x, y); }
154 : :
155 : 6 : vec3<T> xyz() const { return vec3<T>(x, y, z); }
156 : :
157 : 6 : vec2<T> zw() const { return vec2<T>(z, w); }
158 : :
159 : : operator vec2<T>() const { return vec2<T>(x, y); }
160 : :
161 : : operator vec3<T>() const { return vec3<T>(x, y, z); }
162 : :
163 : : // Pre-increment and pre-decrement operators
164 : 6 : vec4& operator++() {
165 : 6 : ++x;
166 : 6 : ++y;
167 : 6 : ++z;
168 : 6 : ++w;
169 : 6 : return *this;
170 : 6 : }
171 : :
172 : 6 : vec4& operator--() {
173 : 6 : --x;
174 : 6 : --y;
175 : 6 : --z;
176 : 6 : --w;
177 : 6 : return *this;
178 : 6 : }
179 : :
180 : : // Post-increment and post-decrement operators
181 : : vec4 operator++(int) {
182 : : vec4 tmp = *this;
183 : : ++*this;
184 : : return tmp;
185 : : }
186 : :
187 : : vec4 operator--(int) {
188 : : vec4 tmp = *this;
189 : : --*this;
190 : : return tmp;
191 : : }
192 : :
193 : : // Compound assignment operators
194 : : void operator+=(T a) {
195 : : x += a;
196 : : y += a;
197 : : z += a;
198 : : w += a;
199 : : }
200 : :
201 : : void operator+=(const vec4& v) {
202 : : x += v.x;
203 : : y += v.y;
204 : : z += v.z;
205 : : w += v.w;
206 : : }
207 : :
208 : : void operator-=(T a) {
209 : : x -= a;
210 : : y -= a;
211 : : z -= a;
212 : : w -= a;
213 : : }
214 : :
215 : : void operator-=(const vec4& v) {
216 : : x -= v.x;
217 : : y -= v.y;
218 : : z -= v.z;
219 : : w -= v.w;
220 : : }
221 : :
222 : : void operator*=(T a) {
223 : : x *= a;
224 : : y *= a;
225 : : z *= a;
226 : : w *= a;
227 : : }
228 : :
229 : : void operator*=(const vec4& v) {
230 : : x *= v.x;
231 : : y *= v.y;
232 : : z *= v.z;
233 : : w *= v.w;
234 : : }
235 : :
236 : : void operator/=(T a) {
237 : : x /= a;
238 : : y /= a;
239 : : z /= a;
240 : : w /= a;
241 : : }
242 : :
243 : : void operator/=(const vec4& v) {
244 : : x /= v.x;
245 : : y /= v.y;
246 : : z /= v.z;
247 : : w /= v.w;
248 : : }
249 : :
250 : : // Size and position operations
251 : : vec2<T> SizeLBRT() const { return vec2<T>(z - x, w - y); } // Considers vec4 as a rectangle with LBRT (Left, Bottom, Right, Top)
252 : :
253 : : vec2<T> pos() const { return xy(); }
254 : :
255 : : vec2<T> size() const { return zw(); }
256 : :
257 : : // Length of the vector
258 : 6 : T length() const { return static_cast<T>(ez::sqrt(lengthSquared())); }
259 : :
260 : : // Squared length of the vector
261 : 6 : T lengthSquared() const { return x * x + y * y + z * z + w * w; }
262 : :
263 : : // Normalize the vector
264 : 2 : T normalize() {
265 : 2 : T _length = length();
266 [ - + ][ - + ]: 2 : if (_length < std::numeric_limits<T>::epsilon())
267 : 0 : return static_cast<T>(0);
268 : 2 : T _invLength = static_cast<T>(1) / _length;
269 : 2 : x *= _invLength;
270 : 2 : y *= _invLength;
271 : 2 : z *= _invLength;
272 : 2 : w *= _invLength;
273 : 2 : return _length;
274 : 2 : }
275 : :
276 : : // Get a normalized copy of the vector
277 : : vec4 GetNormalized() const {
278 : : vec4 n = *this;
279 : : n.normalize();
280 : : return n;
281 : : }
282 : :
283 : : // Check if all components are zero (AND)
284 [ + + ][ + + ]: 12 : bool emptyAND() const { return x == static_cast<T>(0) && y == static_cast<T>(0) && z == static_cast<T>(0) && w == static_cast<T>(0); }
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
285 : :
286 : : // Check if any component is zero (OR)
287 [ + + ][ + + ]: 12 : bool emptyOR() const { return x == static_cast<T>(0) || y == static_cast<T>(0) || z == static_cast<T>(0) || w == static_cast<T>(0); }
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
288 : :
289 : : // Sum of components
290 : 6 : T sum() const { return x + y + z + w; }
291 : :
292 : : // Sum of absolute values of components
293 : 4 : T sumAbs() const { return ez::abs(x) + ez::abs(y) + ez::abs(z) + ez::abs(w); }
294 : :
295 : : // Convert to string
296 : 6 : std::string string(char c = ';') const { return ez::str::toStr(x) + c + ez::str::toStr(y) + c + ez::str::toStr(z) + c + ez::str::toStr(w); }
297 : :
298 : : // Minimum component
299 : 6 : T mini() const { return ez::mini(x, ez::mini(y, ez::mini(z, w))); }
300 : :
301 : : // Maximum component
302 : 6 : T maxi() const { return ez::maxi(x, ez::maxi(y, ez::maxi(z, w))); }
303 : : };
304 : :
305 : : // Operators for vec4
306 : : template <typename T>
307 : : inline vec4<T> operator+(vec4<T> v, T f) {
308 : : return vec4<T>(v.x + f, v.y + f, v.z + f, v.w + f);
309 : : }
310 : :
311 : : template <typename T>
312 : : inline vec4<T> operator+(T f, vec4<T> v) {
313 : : return vec4<T>(v.x + f, v.y + f, v.z + f, v.w + f);
314 : : }
315 : :
316 : : template <typename T>
317 : 6 : inline vec4<T> operator+(vec4<T> v, const vec4<T>& f) {
318 : 6 : return vec4<T>(v.x + f.x, v.y + f.y, v.z + f.z, v.w + f.w);
319 : 6 : }
320 : :
321 : : template <typename T>
322 : : inline vec4<T> operator-(vec4<T> v, T f) {
323 : : return vec4<T>(v.x - f, v.y - f, v.z - f, v.w - f);
324 : : }
325 : :
326 : : template <typename T>
327 : : inline vec4<T> operator-(T f, vec4<T> v) {
328 : : return vec4<T>(f - v.x, f - v.y, f - v.z, f - v.w);
329 : : }
330 : :
331 : : template <typename T>
332 : 6 : inline vec4<T> operator-(vec4<T> v, const vec4<T>& f) {
333 : 6 : return vec4<T>(v.x - f.x, v.y - f.y, v.z - f.z, v.w - f.w);
334 : 6 : }
335 : :
336 : : template <typename T>
337 : 6 : inline vec4<T> operator*(vec4<T> v, T f) {
338 : 6 : return vec4<T>(v.x * f, v.y * f, v.z * f, v.w * f);
339 : 6 : }
340 : :
341 : : template <typename T>
342 : : inline vec4<T> operator*(T f, vec4<T> v) {
343 : : return vec4<T>(v.x * f, v.y * f, v.z * f, v.w * f);
344 : : }
345 : :
346 : : template <typename T>
347 : : inline vec4<T> operator*(vec4<T> v, const vec4<T>& f) {
348 : : return vec4<T>(v.x * f.x, v.y * f.y, v.z * f.z, v.w * f.w);
349 : : }
350 : :
351 : : template <typename T>
352 : 6 : inline vec4<T> operator/(vec4<T> v, T f) {
353 : 6 : return vec4<T>(v.x / f, v.y / f, v.z / f, v.w / f);
354 : 6 : }
355 : :
356 : : template <typename T>
357 : : inline vec4<T> operator/(T f, vec4<T> v) {
358 : : return vec4<T>(f / v.x, f / v.y, f / v.z, f / v.w);
359 : : }
360 : :
361 : : template <typename T>
362 : : inline vec4<T> operator/(vec4<T> v, const vec4<T>& f) {
363 : : return vec4<T>(v.x / f.x, v.y / f.y, v.z / f.z, v.w / f.w);
364 : : }
365 : :
366 : : // Comparison operators
367 : : template <typename T>
368 : : inline bool operator<(vec4<T> v, const vec4<T>& f) {
369 : : return v.x < f.x && v.y < f.y && v.z < f.z && v.w < f.w;
370 : : }
371 : :
372 : : template <typename T>
373 : : inline bool operator<(vec4<T> v, T f) {
374 : : return v.x < f && v.y < f && v.z < f && v.w < f;
375 : : }
376 : :
377 : : template <typename T>
378 : : inline bool operator<(T f, vec4<T> v) {
379 : : return f < v.x && f < v.y && f < v.z && f < v.w;
380 : : }
381 : :
382 : : template <typename T>
383 : : inline bool operator>(vec4<T> v, const vec4<T>& f) {
384 : : return v.x > f.x && v.y > f.y && v.z > f.z && v.w > f.w;
385 : : }
386 : :
387 : : template <typename T>
388 : : inline bool operator>(vec4<T> v, T f) {
389 : : return v.x > f && v.y > f && v.z > f && v.w > f;
390 : : }
391 : :
392 : : template <typename T>
393 : : inline bool operator>(T f, vec4<T> v) {
394 : : return f > v.x && f > v.y && f > v.z && f > v.w;
395 : : }
396 : :
397 : : template <typename T>
398 : : inline bool operator<=(vec4<T> v, const vec4<T>& f) {
399 : : return v.x <= f.x && v.y <= f.y && v.z <= f.z && v.w <= f.w;
400 : : }
401 : :
402 : : template <typename T>
403 : : inline bool operator<=(vec4<T> v, T f) {
404 : : return v.x <= f && v.y <= f && v.z <= f && v.w <= f;
405 : : }
406 : :
407 : : template <typename T>
408 : : inline bool operator<=(T f, vec4<T> v) {
409 : : return f <= v.x && f <= v.y && f <= v.z && f <= v.w;
410 : : }
411 : :
412 : : template <typename T>
413 : : inline bool operator>=(vec4<T> v, const vec4<T>& f) {
414 : : return v.x >= f.x && v.y >= f.y && v.z >= f.z && v.w >= f.w;
415 : : }
416 : :
417 : : template <typename T>
418 : : inline bool operator>=(vec4<T> v, T f) {
419 : : return v.x >= f && v.y >= f && v.z >= f && v.w >= f;
420 : : }
421 : :
422 : : template <typename T>
423 : : inline bool operator>=(T f, vec4<T> v) {
424 : : return f >= v.x && f >= v.y && f >= v.z && f >= v.w;
425 : : }
426 : :
427 : : template <typename T>
428 : 10 : inline bool operator==(vec4<T> v, const vec4<T>& f) {
429 [ + + ][ + + ]: 10 : return v.x == f.x && v.y == f.y && v.z == f.z && v.w == f.w;
[ + + ][ + + ]
[ + + ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
430 : 10 : }
431 : :
432 : : template <typename T>
433 : : inline bool operator==(vec4<T> v, T f) {
434 : : return v.x == f && v.y == f && v.z == f && v.w == f;
435 : : }
436 : :
437 : : template <typename T>
438 : : inline bool operator==(T f, vec4<T> v) {
439 : : return f == v.x && f == v.y && f == v.z && f == v.w;
440 : : }
441 : :
442 : : template <typename T>
443 : : inline bool operator!=(vec4<T> v, const vec4<T>& f) {
444 : : return v.x != f.x || v.y != f.y || v.z != f.z || v.w != f.w;
445 : : }
446 : :
447 : : template <typename T>
448 : : inline bool operator!=(vec4<T> v, T f) {
449 : : return v.x != f || v.y != f || v.z != f || v.w != f;
450 : : }
451 : :
452 : : template <typename T>
453 : : inline bool operator!=(T f, vec4<T> v) {
454 : : return f != v.x || f != v.y || f != v.z || f != v.w;
455 : : }
456 : :
457 : : // Utility functions
458 : : template <typename T>
459 : : inline vec4<T> mini(vec4<T> a, vec4<T> b) {
460 : : return vec4<T>(ez::mini(a.x, b.x), ez::mini(a.y, b.y), ez::mini(a.z, b.z), ez::mini(a.w, b.w));
461 : : }
462 : :
463 : : template <typename T>
464 : : inline vec4<T> maxi(vec4<T> a, vec4<T> b) {
465 : : return vec4<T>(ez::maxi(a.x, b.x), ez::maxi(a.y, b.y), ez::maxi(a.z, b.z), ez::maxi(a.w, b.w));
466 : : }
467 : :
468 : : template <typename T>
469 : : inline vec4<T> floor(vec4<T> a) {
470 : : return vec4<T>(ez::floor(a.x), ez::floor(a.y), ez::floor(a.z), ez::floor(a.w));
471 : : }
472 : :
473 : : template <typename T>
474 : : inline vec4<T> ceil(vec4<T> a) {
475 : : return vec4<T>(ez::ceil(a.x), ez::ceil(a.y), ez::ceil(a.z), ez::ceil(a.w));
476 : : }
477 : :
478 : : template <typename T>
479 : : inline vec4<T> abs(vec4<T> a) {
480 : : return vec4<T>(ez::abs(a.x), ez::abs(a.y), ez::abs(a.z), ez::abs(a.w));
481 : : }
482 : :
483 : : template <typename T>
484 : : inline vec4<T> sign(vec4<T> a) {
485 : : return vec4<T>(a.x < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
486 : : a.y < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
487 : : a.z < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
488 : : a.w < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1));
489 : : }
490 : :
491 : : template <typename T>
492 : : inline vec4<T> sin(vec4<T> a) {
493 : : return vec4<T>(ez::sin(a.x), ez::sin(a.y), ez::sin(a.z), ez::sin(a.w));
494 : : }
495 : :
496 : : template <typename T>
497 : : inline vec4<T> cos(vec4<T> a) {
498 : : return vec4<T>(ez::cos(a.x), ez::cos(a.y), ez::cos(a.z), ez::cos(a.w));
499 : : }
500 : :
501 : : template <typename T>
502 : : inline vec4<T> tan(vec4<T> a) {
503 : : return vec4<T>(ez::tan(a.x), ez::tan(a.y), ez::tan(a.z), ez::tan(a.w));
504 : : }
505 : :
506 : : // Type aliases for common vector types
507 : : using dvec4 = vec4<double>;
508 : : using fvec4 = vec4<float>;
509 : : using f32vec4 = vec4<float>;
510 : : using f64vec4 = vec4<double>;
511 : : using bvec4 = vec4<bool>;
512 : : using ivec4 = vec4<int>;
513 : : using i8vec4 = vec4<int8_t>;
514 : : using i16vec4 = vec4<int16_t>;
515 : : using i32vec4 = vec4<int32_t>;
516 : : using i64vec4 = vec4<int64_t>;
517 : : using u8vec4 = vec4<uint8_t>;
518 : : using u16vec4 = vec4<uint16_t>;
519 : : using uvec4 = vec4<uint32_t>;
520 : : using u32vec4 = vec4<uint32_t>;
521 : : using u64vec4 = vec4<uint64_t>;
522 : :
523 : : // Specialization for float validation
524 : 0 : inline bool valid(const fvec4& a) {
525 : 0 : return floatIsValid(a.x) && floatIsValid(a.y) && floatIsValid(a.z) && floatIsValid(a.w);
526 : 0 : }
527 : :
528 : : // Float-specific comparison operators
529 : 5 : inline bool operator==(const fvec4& v, const fvec4& f) {
530 [ + + ][ + + ]: 5 : return isEqual(f.x, v.x) && isEqual(f.y, v.y) && isEqual(f.z, v.z) && isEqual(f.w, v.w);
[ + - ][ + + ]
531 : 5 : }
532 : :
533 : 0 : inline bool operator!=(const fvec4& v, const fvec4& f) {
534 : 0 : return isDifferent(f.x, v.x) || isDifferent(f.y, v.y) || isDifferent(f.z, v.z) || isDifferent(f.w, v.w);
535 : 0 : }
536 : :
537 : : template <typename T>
538 : : inline std::istream& operator>>(std::istream& vIn, vec4<T>& vType) {
539 : : char separator;
540 : : if (vIn >> vType.x >> separator >> vType.y >> separator >> vType.z >> separator >> vType.w) {
541 : : if (separator != ';') {
542 : : vIn.setstate(std::ios::failbit);
543 : : }
544 : : }
545 : : return vIn;
546 : : }
547 : :
548 : : template <typename T>
549 : : inline std::ostream& operator<<(std::ostream& vOut, const vec4<T>& vType) {
550 : : vOut << vType.x << ";" << vType.y << ";" << vType.z << ";" << vType.w;
551 : : return vOut;
552 : : }
553 : :
554 : : } // namespace ez
|