1 #ifndef CLUNK_V3_H__ 2 #define CLUNK_V3_H__ 3 4 /* clunk - cross-platform 3D audio API built on top SDL library 5 * Copyright (C) 2007-2014 Netive Media Group 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 #include <clunk/types.h> 23 #include <limits> 24 25 namespace clunk { 26 /*! 27 \brief 3d vector 28 \tparam T type of the axis. usually int or float. 29 */ 30 template <typename T> struct v3 { 31 typedef std::numeric_limits<T> limits_type; 32 33 template<typename V> absv334 static inline V abs(V v) { return v < 0? -v: v; } 35 36 ///x component 37 T x; 38 ///y component 39 T y; 40 ///z component 41 T z; 42 ///default ctor: initializes all components with zeroes. 43 inline v3<T>() : x(0), y(0), z(0) {} 44 ///initializes all components with given values xv345 inline v3<T>(const T x, const T y, const T z) : x(x), y(y), z(z) {} 46 47 ///nullify vector clearv348 inline void clear() { x = y = z = 0; } 49 ///returns true if x == y == z == 0 ? is0v350 inline bool is0() const { 51 T zero = limits_type::epsilon(); 52 return abs(x) <= zero && abs(y) <= zero && abs(z) <= zero; 53 } 54 55 /*! 56 \brief normalizes vector. 57 \return old length of this vector 58 */ normalizev359 inline T normalize() { 60 const T len = length(); 61 if (len == (T)0 || len ==(T)1) 62 return len; 63 64 x /= len; 65 y /= len; 66 z /= len; 67 return len; 68 } 69 70 /*! 71 \brief normalizes vector with given length 72 \param[in] nlen length 73 \return old length of this vector 74 */ 75 normalizev376 inline T normalize(const T nlen) { 77 const T len = length(); 78 if (len == (T)0 || len == nlen) 79 return len; 80 81 x *= nlen / len; 82 y *= nlen / len; 83 z *= nlen / len; 84 return len; 85 } 86 dot_productv387 inline T dot_product(const v3<T> &v) const { 88 return x * v.x + y * v.y + z * v.z; 89 } 90 cross_productv391 inline v3<T> cross_product(const v3<T> &v) const { 92 return v3<T>( 93 y * v.z - z * v.y, 94 z * v.x - x * v.z, 95 x * v.y - y * v.x 96 ); 97 } 98 99 ///returns length of this vector lengthv3100 inline T length() const { 101 const T ql = x * x + y * y + z * z; 102 if (ql == (T)0 || ql == (T)1) 103 return ql; 104 105 return (T)sqrt(ql); 106 } 107 ///returns square of length. To avoid sqrt if needed. quick_lengthv3108 inline T quick_length() const { 109 return (T)(x * x + y * y + z * z); 110 } 111 112 ///converts to vector of another type 113 template <typename T2> convertv3114 inline v3<T2> convert() const { return v3<T2>((T2)x, (T2)y, (T2)z); } 115 116 ///returns distance between two points distancev3117 inline T distance(const v3<T>& other) const { 118 v3<T>d(*this); 119 d -= other; 120 return d.length(); 121 } 122 123 ///return square distance between two points quick_distancev3124 inline T quick_distance(const v3<T>& other) const { 125 const T dx = x - other.x; 126 const T dy = y - other.y; 127 const T dz = z - other.z; 128 return (dx * dx + dy * dy + dz * dz); 129 } 130 131 ///allows v3 be placed in sorted STL container such std::map 132 inline bool operator<(const v3<T> &other) const { 133 if (x != other.x) { 134 return x < other.x; 135 } 136 if (y != other.y) { 137 return y < other.y; 138 } 139 return z < other.z; 140 } 141 142 ///negate all components 143 inline v3<T> operator-() const { 144 return v3<T>(-x, -y, -z); 145 } 146 ///test equality 147 inline bool operator==(const v3<T> &other) const { 148 return x == other.x && y == other.y && z == other.z; 149 } 150 151 ///test inequality 152 inline bool operator!=(const v3<T> &other) const { 153 return x != other.x || y != other.y || z != other.z; 154 } 155 156 ///adds another vector 157 inline v3<T>& operator+=(const v3<T>& other) { 158 x += other.x; y += other.y; z += other.z; 159 return *this; 160 } 161 162 ///substracts another vector 163 inline v3<T>& operator-=(const v3<T>& other) { 164 x -= other.x; y -= other.y; z -= other.z; 165 return *this; 166 } 167 168 ///multiplies another vector 169 inline v3<T>& operator*=(const v3<T>& other) { 170 x *= other.x; y *= other.y; z *= other.z; 171 return *this; 172 } 173 174 ///divide with another vector 175 inline v3<T>& operator/=(const v3<T>& other) { 176 x /= other.x; y /= other.y; z /= other.z; 177 return *this; 178 } 179 ///multiplication 180 inline v3<T> operator*(const v3<T>& other) const { 181 return v3<T>(x * other.x, y * other.y, z * other.z); 182 } 183 ///summing 184 inline v3<T> operator+(const v3<T>& other) const { 185 return v3<T>(x + other.x, y + other.y, z + other.z); 186 } 187 ///substraction 188 inline v3<T> operator-(const v3<T>& other) const { 189 return v3<T>(x - other.x, y - other.y, z - other.z); 190 } 191 ///division 192 inline v3<T> operator/(const v3<T>& other) const { 193 return v3<T>(x / other.x, y / other.y, z / other.z); 194 } 195 ///multiplies all components with constant 196 inline v3<T> operator*(const T& other) const { 197 return v3<T>(x * other, y * other, z * other); 198 } 199 ///sums all components with constant 200 inline v3<T> operator+(const T& other) const { 201 return v3<T>(x + other, y + other, z + other); 202 } 203 ///substracts all components with constant 204 inline v3<T> operator-(const T& other) const { 205 return v3<T>(x - other, y - other, z - other); 206 } 207 ///divides all components by constant 208 inline v3<T> operator/(const T& other) const { 209 return v3<T>(x / other, y / other, z / other); 210 } 211 ///divides this vector by constant 212 inline v3<T>& operator/=(const T& other) { 213 x /= other; 214 y /= other; 215 z /= other; 216 return *this; 217 } 218 219 ///multiplies this vector with constant 220 inline v3<T>& operator*=(const T& other) { 221 x *= other; 222 y *= other; 223 z *= other; 224 return *this; 225 } 226 227 ///sums this vector with constant 228 inline v3<T>& operator+=(const T& other) { 229 x += other; 230 y += other; 231 z += other; 232 return *this; 233 } 234 235 ///substracts this vector with constant 236 inline v3<T>& operator-=(const T& other) { 237 x -= other; 238 y -= other; 239 z -= other; 240 return *this; 241 } 242 243 ///adds constant to the vector 244 inline v3<T> operator+(const T a) { 245 return v3<T>(x + a, y + a, z + a); 246 } 247 248 ///subs constant from the vector 249 inline v3<T> operator-(const T a) { 250 return v3<T>(x - a, y - a, z - a); 251 } 252 253 ///muls constant to the vector 254 inline v3<T> operator*(const T a) { 255 return v3<T>(x * a, y * a, z * a); 256 } 257 258 ///divs constant to the vector 259 inline v3<T> operator/(const T a) { 260 return v3<T>(x / a, y / a, z / a); 261 } 262 }; 263 ///external operator+ 264 template <typename T> 265 inline v3<T> operator+(const T a, const v3<T> &v) { 266 return v3<T>(v.x + a, v.y + a, v.z + a); 267 } 268 269 ///external operator- 270 template <typename T> 271 inline v3<T> operator-(const T a, const v3<T> &v) { 272 return v3<T>(a - v.x, a - v.y, a - v.z); 273 } 274 275 ///external operator* 276 template <typename T> 277 inline v3<T> operator*(const T a, const v3<T> &v) { 278 return v3<T>(v.x * a, v.y * a, v.z * a); 279 } 280 281 ///external operator/ 282 template <typename T> 283 inline v3<T> operator/(const T a, const v3<T> &v) { 284 return v3<T>(a / v.x, a / v.y, a / v.z); 285 } 286 287 typedef v3<float> v3f; 288 289 #if 0 //defined CLUNK_USES_SSE 290 # include <xmmintrin.h> 291 292 template <> 293 class v3<float> { 294 __m128 value; 295 296 public: 297 298 template <int POS> 299 class float_placeholder { 300 __m128 &value; 301 public: 302 inline float_placeholder(__m128 &value) __attribute__((__always_inline__)) : value(value) {} 303 inline float get() const __attribute__((__always_inline__)) { 304 float r[4]; 305 _mm_storeu_ps(r, value); 306 return r[POS]; 307 } 308 inline void set(float v) __attribute__((__always_inline__)) { 309 __m128 mask = _mm_cmpgt_ps(_mm_set_ps(POS == 2?1:0, POS == 1?1:0, POS == 0?1:0, 0), _mm_setzero_ps()); 310 value = _mm_or_ps( 311 _mm_andnot_ps(mask, value), 312 _mm_and_ps(mask, _mm_set1_ps(v)) 313 ); 314 } 315 316 inline operator float() const __attribute__((__always_inline__)) { 317 return get(); 318 } 319 inline const float_placeholder<POS>& operator=(const float_placeholder<POS> &other) __attribute__((__always_inline__)) { 320 set(other.get()); 321 return *this; 322 } 323 324 inline const float_placeholder<POS>& operator=(float v) __attribute__((__always_inline__)) { 325 set(v); 326 return *this; 327 } 328 }; 329 float_placeholder<0> x; 330 float_placeholder<1> y; 331 float_placeholder<2> z; 332 333 inline v3<float>(): value(_mm_setzero_ps()), x(value), y(value), z(value) {} 334 inline v3<float>(__m128 v): value(v), x(value), y(value), z(value) {} 335 inline v3<float>(const float xv, const float yv, const float zv) : 336 value(_mm_set_ps(zv, yv, xv, 0)), x(value), y(value), z(value) {} 337 338 inline void clear() { value = _mm_setzero_ps(); } 339 340 inline const bool is0() const { 341 return (_mm_movemask_ps(_mm_cmpeq_ps(value, _mm_setzero_ps())) & 7 ) == 7; 342 } 343 344 inline const float normalize() { 345 float len = length(); 346 if (len == (float)0 || len ==(float)1) 347 return len; 348 349 value = _mm_div_ps(value, _mm_set1_ps(len)); 350 return len; 351 } 352 353 inline const float normalize(const float nlen) { 354 const float len = length(); 355 if (len == (float)0 || len == nlen) 356 return len; 357 358 __m128 k = _mm_div_ps(_mm_set1_ps(nlen), _mm_set1_ps(len)); 359 value = _mm_div_ps(value, k); 360 return len; 361 } 362 363 inline const float dot_product(const v3<float> &v) const { 364 float fixme[4]; 365 _mm_storeu_ps(fixme, _mm_mul_ps(value, v.value)); 366 return fixme[0] + fixme[1] + fixme[2] + fixme[3]; 367 } 368 369 inline const float length() const { 370 float v[4]; 371 _mm_storeu_ps(v, _mm_mul_ps(value, value)); 372 const float ql = v[0] + v[1] + v[2]; 373 if (ql == 0 || ql == 1.0f) 374 return ql; 375 376 return (float)sqrt(ql); 377 } 378 379 inline float quick_length() const { 380 float v[4]; 381 _mm_storeu_ps(v, _mm_mul_ps(value, value)); 382 return v[0] + v[1] + v[2]; 383 } 384 385 template <typename T2> 386 inline v3<T2> convert() const { 387 float v[4]; 388 _mm_storeu_ps(v, value); 389 return v3<T2>((T2)v[0], (T2)v[1], (T2)v[2]); 390 } 391 392 inline const float distance(const v3<float>& other) const { 393 v3<float>d(*this); 394 d -= other; 395 return d.length(); 396 } 397 398 inline float quick_distance(const v3<float>& other) const { 399 float v[4]; 400 __m128 dv = _mm_sub_ps(value, other.value); 401 _mm_storeu_ps(v, _mm_mul_ps(dv, dv)); 402 return v[0] + v[1] + v[2]; 403 } 404 405 inline const bool operator<(const v3<float> &other) const { 406 int c = _mm_movemask_ps(_mm_cmpneq_ps(value, other.value)); 407 int l = _mm_movemask_ps(_mm_cmplt_ps(value, other.value)); 408 if (c & 1) { 409 return l & 1; 410 } 411 if (c & 2) { 412 return l & 2; 413 } 414 return l & 4; 415 } 416 417 inline const v3<float> operator-() const { 418 return _mm_sub_ps(_mm_setzero_ps(), value); 419 } 420 421 inline const bool operator==(const v3<float> &other) const { 422 int mask = _mm_movemask_ps(_mm_cmpeq_ps(value, other.value)); 423 return (mask & 7) == 7; 424 } 425 426 ///test inequality 427 inline const bool operator!=(const v3<float> &other) const { 428 int mask = _mm_movemask_ps(_mm_cmpeq_ps(value, other.value)); 429 return (mask & 7) != 7; 430 } 431 432 ///adds another vector 433 inline const v3<float>& operator+=(const v3<float>& other) { 434 value = _mm_add_ps(value, other.value); 435 return *this; 436 } 437 438 ///substracts another vector 439 inline const v3<float>& operator-=(const v3<float>& other) { 440 value = _mm_sub_ps(value, other.value); 441 return *this; 442 } 443 444 ///multiplies another vector 445 inline const v3<float>& operator*=(const v3<float>& other) { 446 value = _mm_mul_ps(value, other.value); 447 return *this; 448 } 449 450 ///divide with another vector 451 inline const v3<float>& operator/=(const v3<float>& other) { 452 value = _mm_div_ps(value, other.value); 453 return *this; 454 } 455 ///multiplication 456 inline const v3<float> operator*(const v3<float>& other) const { 457 return v3<float>(_mm_mul_ps(value, other.value)); 458 } 459 ///summing 460 inline const v3<float> operator+(const v3<float>& other) const { 461 return v3<float>(_mm_add_ps(value, other.value)); 462 } 463 ///substraction 464 inline const v3<float> operator-(const v3<float>& other) const { 465 return v3<float>(_mm_sub_ps(value, other.value)); 466 } 467 ///division 468 inline const v3<float> operator/(const v3<float>& other) const { 469 return v3<float>(_mm_div_ps(value, other.value)); 470 } 471 ///multiplies all components with constant 472 inline const v3<float> operator*(const float& other) const { 473 return v3<float>(_mm_mul_ps(value, _mm_set1_ps(other))); 474 } 475 ///sums all components with constant 476 inline const v3<float> operator+(const float& other) const { 477 return v3<float>(_mm_add_ps(value, _mm_set1_ps(other))); 478 } 479 ///substracts all components with constant 480 inline const v3<float> operator-(const float& other) const { 481 return v3<float>(_mm_sub_ps(value, _mm_set1_ps(other))); 482 } 483 ///divides all components by constant 484 inline const v3<float> operator/(const float& other) const { 485 return v3<float>(_mm_div_ps(value, _mm_set1_ps(other))); 486 } 487 ///divides this vector by constant 488 inline const v3<float>& operator/=(const float& other) { 489 value = _mm_div_ps(value, _mm_set1_ps(other)); 490 return *this; 491 } 492 493 ///multiplies this vector with constant 494 inline const v3<float>& operator*=(const float& other) { 495 value = _mm_mul_ps(value, _mm_set1_ps(other)); 496 return *this; 497 } 498 499 ///sums this vector with constant 500 inline const v3<float>& operator+=(const float& other) { 501 value = _mm_add_ps(value, _mm_set1_ps(other)); 502 return *this; 503 } 504 505 ///substracts this vector with constant 506 inline const v3<float>& operator-=(const float& other) { 507 value = _mm_sub_ps(value, _mm_set1_ps(other)); 508 return *this; 509 } 510 511 ///adds constant to the vector 512 inline const v3<float> operator+(const float a) { 513 return v3<float>(_mm_add_ps(value, _mm_set1_ps(a))); 514 } 515 516 ///subs constant from the vector 517 inline const v3<float> operator-(const float a) { 518 return v3<float>(_mm_sub_ps(value, _mm_set1_ps(a))); 519 } 520 521 ///muls constant to the vector 522 inline const v3<float> operator*(const float a) { 523 return v3<float>(_mm_mul_ps(value, _mm_set1_ps(a))); 524 } 525 526 ///divs constant to the vector 527 inline const v3<float> operator/(const float a) { 528 return v3<float>(_mm_div_ps(value, _mm_set1_ps(a))); 529 } 530 }; 531 532 #endif //CLUNK_USES_SSE 533 534 } //namespace clunk 535 536 #endif 537 538