vector_utils.h (15908B)
1 // 2 // Copyright 2016 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // vector_utils.h: Utility classes implementing various vector operations 7 8 #ifndef COMMON_VECTOR_UTILS_H_ 9 #define COMMON_VECTOR_UTILS_H_ 10 11 #include <cmath> 12 #include <cstddef> 13 #include <ostream> 14 #include <type_traits> 15 16 namespace angle 17 { 18 19 template <size_t Dimension, typename Type> 20 class Vector; 21 22 using Vector2 = Vector<2, float>; 23 using Vector3 = Vector<3, float>; 24 using Vector4 = Vector<4, float>; 25 26 using Vector2I = Vector<2, int>; 27 using Vector3I = Vector<3, int>; 28 using Vector4I = Vector<4, int>; 29 30 using Vector2U = Vector<2, unsigned int>; 31 using Vector3U = Vector<3, unsigned int>; 32 using Vector4U = Vector<4, unsigned int>; 33 34 template <size_t Dimension, typename Type> 35 class VectorBase 36 { 37 public: 38 using VectorN = Vector<Dimension, Type>; 39 40 // Constructors 41 VectorBase() = default; 42 explicit VectorBase(Type element); 43 44 template <typename Type2> 45 VectorBase(const VectorBase<Dimension, Type2> &other); 46 47 template <typename Arg1, typename Arg2, typename... Args> 48 VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args); 49 50 // Access the vector backing storage directly 51 const Type *data() const { return mData; } 52 Type *data() { return mData; } 53 constexpr size_t size() const { return Dimension; } 54 55 // Load or store the pointer from / to raw data 56 static VectorN Load(const Type *source); 57 static void Store(const VectorN &source, Type *destination); 58 59 // Index the vector 60 Type &operator[](size_t i) { return mData[i]; } 61 const Type &operator[](size_t i) const { return mData[i]; } 62 63 // Basic arithmetic operations 64 VectorN operator+() const; 65 VectorN operator-() const; 66 VectorN operator+(const VectorN &other) const; 67 VectorN operator-(const VectorN &other) const; 68 VectorN operator*(const VectorN &other) const; 69 VectorN operator/(const VectorN &other) const; 70 VectorN operator*(Type other) const; 71 VectorN operator/(Type other) const; 72 friend VectorN operator*(Type a, const VectorN &b) { return b * a; } 73 74 // Compound arithmetic operations 75 VectorN &operator+=(const VectorN &other); 76 VectorN &operator-=(const VectorN &other); 77 VectorN &operator*=(const VectorN &other); 78 VectorN &operator/=(const VectorN &other); 79 VectorN &operator*=(Type other); 80 VectorN &operator/=(Type other); 81 82 // Comparison operators 83 bool operator==(const VectorBase<Dimension, Type> &other) const; 84 bool operator!=(const VectorBase<Dimension, Type> &other) const; 85 86 // Other arithmetic operations 87 Type length() const; 88 Type lengthSquared() const; 89 Type dot(const VectorBase<Dimension, Type> &other) const; 90 VectorN normalized() const; 91 92 protected: 93 template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> 94 void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &...args); 95 96 // Some old compilers consider this function an alternative for initWithList(Vector) 97 // when the variant above is more precise. Use SFINAE on the return value to hide 98 // this variant for non-arithmetic types. The return value is still void. 99 template <size_t CurrentIndex, typename OtherType, typename... Args> 100 typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList( 101 OtherType arg1, 102 const Args &...args); 103 104 template <size_t CurrentIndex> 105 void initWithList() const; 106 107 template <size_t Dimension2, typename Type2> 108 friend class VectorBase; 109 110 Type mData[Dimension]; 111 }; 112 113 template <size_t Dimension, typename Type> 114 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector); 115 116 template <typename Type> 117 class Vector<2, Type> : public VectorBase<2, Type> 118 { 119 public: 120 // Import the constructors defined in VectorBase 121 using VectorBase<2, Type>::VectorBase; 122 123 // Element shorthands 124 Type &x() { return this->mData[0]; } 125 Type &y() { return this->mData[1]; } 126 127 const Type &x() const { return this->mData[0]; } 128 const Type &y() const { return this->mData[1]; } 129 }; 130 131 template <typename Type> 132 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector); 133 134 template <typename Type> 135 class Vector<3, Type> : public VectorBase<3, Type> 136 { 137 public: 138 // Import the constructors defined in VectorBase 139 using VectorBase<3, Type>::VectorBase; 140 141 // Additional operations 142 Vector<3, Type> cross(const Vector<3, Type> &other) const; 143 144 // Element shorthands 145 Type &x() { return this->mData[0]; } 146 Type &y() { return this->mData[1]; } 147 Type &z() { return this->mData[2]; } 148 149 const Type &x() const { return this->mData[0]; } 150 const Type &y() const { return this->mData[1]; } 151 const Type &z() const { return this->mData[2]; } 152 }; 153 154 template <typename Type> 155 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector); 156 157 template <typename Type> 158 class Vector<4, Type> : public VectorBase<4, Type> 159 { 160 public: 161 // Import the constructors defined in VectorBase 162 using VectorBase<4, Type>::VectorBase; 163 164 // Element shorthands 165 Type &x() { return this->mData[0]; } 166 Type &y() { return this->mData[1]; } 167 Type &z() { return this->mData[2]; } 168 Type &w() { return this->mData[3]; } 169 170 const Type &x() const { return this->mData[0]; } 171 const Type &y() const { return this->mData[1]; } 172 const Type &z() const { return this->mData[2]; } 173 const Type &w() const { return this->mData[3]; } 174 }; 175 176 template <typename Type> 177 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector); 178 179 // Implementation of constructors and misc operations 180 181 template <size_t Dimension, typename Type> 182 VectorBase<Dimension, Type>::VectorBase(Type element) 183 { 184 for (size_t i = 0; i < Dimension; ++i) 185 { 186 mData[i] = element; 187 } 188 } 189 190 template <size_t Dimension, typename Type> 191 template <typename Type2> 192 VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other) 193 { 194 for (size_t i = 0; i < Dimension; ++i) 195 { 196 mData[i] = static_cast<Type>(other.mData[i]); 197 } 198 } 199 200 // Ideally we would like to have only two constructors: 201 // - a scalar constructor that takes Type as a parameter 202 // - a compound constructor 203 // However if we define the compound constructor for when it has a single arguments, then calling 204 // Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound 205 // constructor with a single argument, which is the copy constructor. We end up with three 206 // constructors: 207 // - the scalar constructor 208 // - the copy constructor 209 // - the compound constructor for two or more arguments, hence the arg1, and arg2 here. 210 template <size_t Dimension, typename Type> 211 template <typename Arg1, typename Arg2, typename... Args> 212 VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args) 213 { 214 initWithList<0>(arg1, arg2, args...); 215 } 216 217 template <size_t Dimension, typename Type> 218 template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> 219 void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1, 220 const Args &...args) 221 { 222 static_assert(CurrentIndex + OtherDimension <= Dimension, 223 "Too much data in the vector constructor."); 224 for (size_t i = 0; i < OtherDimension; ++i) 225 { 226 mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]); 227 } 228 initWithList<CurrentIndex + OtherDimension>(args...); 229 } 230 231 template <size_t Dimension, typename Type> 232 template <size_t CurrentIndex, typename OtherType, typename... Args> 233 typename std::enable_if<std::is_arithmetic<OtherType>::value>::type 234 VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &...args) 235 { 236 static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor."); 237 mData[CurrentIndex] = static_cast<Type>(arg1); 238 initWithList<CurrentIndex + 1>(args...); 239 } 240 241 template <size_t Dimension, typename Type> 242 template <size_t CurrentIndex> 243 void VectorBase<Dimension, Type>::initWithList() const 244 { 245 static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor."); 246 } 247 248 template <size_t Dimension, typename Type> 249 Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source) 250 { 251 Vector<Dimension, Type> result; 252 for (size_t i = 0; i < Dimension; ++i) 253 { 254 result.mData[i] = source[i]; 255 } 256 return result; 257 } 258 259 template <size_t Dimension, typename Type> 260 void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination) 261 { 262 for (size_t i = 0; i < Dimension; ++i) 263 { 264 destination[i] = source.mData[i]; 265 } 266 } 267 268 // Implementation of basic arithmetic operations 269 template <size_t Dimension, typename Type> 270 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const 271 { 272 Vector<Dimension, Type> result; 273 for (size_t i = 0; i < Dimension; ++i) 274 { 275 result.mData[i] = +mData[i]; 276 } 277 return result; 278 } 279 280 template <size_t Dimension, typename Type> 281 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const 282 { 283 Vector<Dimension, Type> result; 284 for (size_t i = 0; i < Dimension; ++i) 285 { 286 result.mData[i] = -mData[i]; 287 } 288 return result; 289 } 290 291 template <size_t Dimension, typename Type> 292 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+( 293 const Vector<Dimension, Type> &other) const 294 { 295 Vector<Dimension, Type> result; 296 for (size_t i = 0; i < Dimension; ++i) 297 { 298 result.mData[i] = mData[i] + other.mData[i]; 299 } 300 return result; 301 } 302 303 template <size_t Dimension, typename Type> 304 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-( 305 const Vector<Dimension, Type> &other) const 306 { 307 Vector<Dimension, Type> result; 308 for (size_t i = 0; i < Dimension; ++i) 309 { 310 result.mData[i] = mData[i] - other.mData[i]; 311 } 312 return result; 313 } 314 315 template <size_t Dimension, typename Type> 316 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*( 317 const Vector<Dimension, Type> &other) const 318 { 319 Vector<Dimension, Type> result; 320 for (size_t i = 0; i < Dimension; ++i) 321 { 322 result.mData[i] = mData[i] * other.mData[i]; 323 } 324 return result; 325 } 326 327 template <size_t Dimension, typename Type> 328 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/( 329 const Vector<Dimension, Type> &other) const 330 { 331 Vector<Dimension, Type> result; 332 for (size_t i = 0; i < Dimension; ++i) 333 { 334 result.mData[i] = mData[i] / other.mData[i]; 335 } 336 return result; 337 } 338 339 template <size_t Dimension, typename Type> 340 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const 341 { 342 Vector<Dimension, Type> result; 343 for (size_t i = 0; i < Dimension; ++i) 344 { 345 result.mData[i] = mData[i] * other; 346 } 347 return result; 348 } 349 350 template <size_t Dimension, typename Type> 351 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const 352 { 353 Vector<Dimension, Type> result; 354 for (size_t i = 0; i < Dimension; ++i) 355 { 356 result.mData[i] = mData[i] / other; 357 } 358 return result; 359 } 360 361 // Implementation of compound arithmetic operations 362 template <size_t Dimension, typename Type> 363 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=( 364 const Vector<Dimension, Type> &other) 365 { 366 for (size_t i = 0; i < Dimension; ++i) 367 { 368 mData[i] += other.mData[i]; 369 } 370 return *static_cast<Vector<Dimension, Type> *>(this); 371 } 372 373 template <size_t Dimension, typename Type> 374 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=( 375 const Vector<Dimension, Type> &other) 376 { 377 for (size_t i = 0; i < Dimension; ++i) 378 { 379 mData[i] -= other.mData[i]; 380 } 381 return *static_cast<Vector<Dimension, Type> *>(this); 382 } 383 384 template <size_t Dimension, typename Type> 385 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=( 386 const Vector<Dimension, Type> &other) 387 { 388 for (size_t i = 0; i < Dimension; ++i) 389 { 390 mData[i] *= other.mData[i]; 391 } 392 return *static_cast<Vector<Dimension, Type> *>(this); 393 } 394 395 template <size_t Dimension, typename Type> 396 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=( 397 const Vector<Dimension, Type> &other) 398 { 399 for (size_t i = 0; i < Dimension; ++i) 400 { 401 mData[i] /= other.mData[i]; 402 } 403 return *static_cast<Vector<Dimension, Type> *>(this); 404 } 405 406 template <size_t Dimension, typename Type> 407 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other) 408 { 409 for (size_t i = 0; i < Dimension; ++i) 410 { 411 mData[i] *= other; 412 } 413 return *static_cast<Vector<Dimension, Type> *>(this); 414 } 415 416 template <size_t Dimension, typename Type> 417 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other) 418 { 419 for (size_t i = 0; i < Dimension; ++i) 420 { 421 mData[i] /= other; 422 } 423 return *static_cast<Vector<Dimension, Type> *>(this); 424 } 425 426 // Implementation of comparison operators 427 template <size_t Dimension, typename Type> 428 bool VectorBase<Dimension, Type>::operator==(const VectorBase<Dimension, Type> &other) const 429 { 430 for (size_t i = 0; i < Dimension; ++i) 431 { 432 if (mData[i] != other.mData[i]) 433 { 434 return false; 435 } 436 } 437 return true; 438 } 439 440 template <size_t Dimension, typename Type> 441 bool VectorBase<Dimension, Type>::operator!=(const VectorBase<Dimension, Type> &other) const 442 { 443 return !(*this == other); 444 } 445 446 // Implementation of other arithmetic operations 447 template <size_t Dimension, typename Type> 448 Type VectorBase<Dimension, Type>::length() const 449 { 450 static_assert(std::is_floating_point<Type>::value, 451 "VectorN::length is only defined for floating point vectors"); 452 return std::sqrt(lengthSquared()); 453 } 454 455 template <size_t Dimension, typename Type> 456 Type VectorBase<Dimension, Type>::lengthSquared() const 457 { 458 return dot(*this); 459 } 460 461 template <size_t Dimension, typename Type> 462 Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const 463 { 464 Type sum = Type(); 465 for (size_t i = 0; i < Dimension; ++i) 466 { 467 sum += mData[i] * other.mData[i]; 468 } 469 return sum; 470 } 471 472 template <size_t Dimension, typename Type> 473 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector) 474 { 475 ostream << "[ "; 476 for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++) 477 { 478 if (elementIdx > 0) 479 { 480 ostream << ", "; 481 } 482 ostream << vector.data()[elementIdx]; 483 } 484 ostream << " ]"; 485 return ostream; 486 } 487 488 template <size_t Dimension, typename Type> 489 Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const 490 { 491 static_assert(std::is_floating_point<Type>::value, 492 "VectorN::normalized is only defined for floating point vectors"); 493 return *this / length(); 494 } 495 496 template <typename Type> 497 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector) 498 { 499 return ostream << static_cast<const VectorBase<2, Type> &>(vector); 500 } 501 502 template <typename Type> 503 Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const 504 { 505 return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), 506 x() * other.y() - y() * other.x()); 507 } 508 509 template <typename Type> 510 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector) 511 { 512 return ostream << static_cast<const VectorBase<3, Type> &>(vector); 513 } 514 515 template <typename Type> 516 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector) 517 { 518 return ostream << static_cast<const VectorBase<4, Type> &>(vector); 519 } 520 521 } // namespace angle 522 523 #endif // COMMON_VECTOR_UTILS_H_