/xbmc/screensavers/rsxs-0.9/src/hyperspace/spline.cc

http://github.com/xbmc/xbmc · C++ · 155 lines · 95 code · 22 blank · 38 comment · 4 complexity · e4d143141fa89ae05061152a114f0e5b MD5 · raw file

  1. /*
  2. * Really Slick XScreenSavers
  3. * Copyright (C) 2002-2006 Michael Chapman
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *****************************************************************************
  19. *
  20. * This is a Linux port of the Really Slick Screensavers,
  21. * Copyright (C) 2005 Terence M. Welsh, available from www.reallyslick.com
  22. */
  23. #include <common.hh>
  24. #include <spline.hh>
  25. #include <vector.hh>
  26. namespace Spline {
  27. unsigned int points;
  28. float step;
  29. std::vector<float> _phase;
  30. std::vector<float> _rate;
  31. std::vector<Vector> _moveXYZ;
  32. std::vector<Vector> _baseXYZ;
  33. std::vector<Vector> _XYZ;
  34. std::vector<Vector> _baseDir;
  35. std::vector<Vector> _dir;
  36. Vector interpolate(const Vector&, const Vector&, const Vector&, const Vector&, float);
  37. };
  38. void Spline::init(unsigned int length) {
  39. // 6 is the minimum number of points necessary for a tunnel to have one segment
  40. points = (length < 6 ? 6 : length);
  41. step = 0.0f;
  42. stdx::construct_n(_phase, points);
  43. stdx::construct_n(_rate, points);
  44. stdx::construct_n(_moveXYZ, points);
  45. stdx::construct_n(_baseXYZ, points);
  46. stdx::construct_n(_XYZ, points);
  47. stdx::construct_n(_baseDir, points);
  48. stdx::construct_n(_dir, points);
  49. _baseXYZ[points - 2].z() = 4.0f;
  50. for (unsigned int i = 0; i < points; ++i)
  51. makeNewPoint();
  52. }
  53. void Spline::makeNewPoint() {
  54. // shift points to rear of path
  55. std::rotate(_baseXYZ.begin(), _baseXYZ.begin() + 1, _baseXYZ.end());
  56. std::rotate(_moveXYZ.begin(), _moveXYZ.begin() + 1, _moveXYZ.end());
  57. std::rotate(_XYZ.begin(), _XYZ.begin() + 1, _XYZ.end());
  58. std::rotate(_phase.begin(), _phase.begin() + 1, _phase.end());
  59. std::rotate(_rate.begin(), _rate.begin() + 1, _rate.end());
  60. // make vector to new point
  61. int lastPoint = points - 1;
  62. float tempX = _baseXYZ[lastPoint - 1].x() - _baseXYZ[lastPoint - 2].x();
  63. float tempZ = _baseXYZ[lastPoint - 1].z() - _baseXYZ[lastPoint - 2].z();
  64. // find good angle
  65. float turnAngle;
  66. float pathAngle = std::atan2(tempX, tempZ);
  67. float distSquared =
  68. _baseXYZ[lastPoint].x() * _baseXYZ[lastPoint].x() +
  69. _baseXYZ[lastPoint].z() * _baseXYZ[lastPoint].z();
  70. if (distSquared > 10000.0f) {
  71. float angleToCenter = std::atan2(-_baseXYZ[lastPoint].x(), -_baseXYZ[lastPoint].z());
  72. turnAngle = angleToCenter - pathAngle;
  73. if (turnAngle > M_PI)
  74. turnAngle -= M_PI * 2.0f;
  75. if (turnAngle < -M_PI)
  76. turnAngle += M_PI * 2.0f;
  77. turnAngle = Common::clamp(turnAngle, -0.7f, 0.7f);
  78. } else
  79. turnAngle = Common::randomFloat(1.4f) - 0.7f;
  80. // rotate new point to some new position
  81. float ca = std::cos(turnAngle);
  82. float sa = std::cos(turnAngle);
  83. _baseXYZ[lastPoint].set(tempX * ca + tempZ * sa, 0.0f, tempX * -sa + tempZ * ca);
  84. // normalize and set length of vector
  85. // make it at least length 2, which is the grid size of the goo
  86. float lengthener = (Common::randomFloat(6.0f) + 2.0f) / _baseXYZ[lastPoint].length();
  87. _baseXYZ[lastPoint] *= lengthener;
  88. // make new movement vector proportional to base vector
  89. _moveXYZ[lastPoint].set(
  90. Common::randomFloat(0.25f) * -_baseXYZ[lastPoint].z(),
  91. 0.3f,
  92. Common::randomFloat(0.25f) * -_baseXYZ[lastPoint].x()
  93. );
  94. // add vector to previous point to get new point
  95. _baseXYZ[lastPoint] += Vector(
  96. _baseXYZ[lastPoint - 1].x(),
  97. 0.0f,
  98. _baseXYZ[lastPoint - 1].z()
  99. );
  100. // make new phase and movement rate
  101. _phase[lastPoint] = Common::randomFloat(M_PI * 2);
  102. _rate[lastPoint] = Common::randomFloat(1.0f);
  103. // reset base direction vectors
  104. _baseDir.front() = _baseXYZ[1] - _baseXYZ[points - 1];
  105. std::transform(
  106. _baseXYZ.begin() + 2, _baseXYZ.end(),
  107. _baseXYZ.begin(), _baseDir.begin() + 1,
  108. std::minus<Vector>()
  109. );
  110. _baseDir.back() = _baseXYZ[0] - _baseXYZ[points - 2];
  111. }
  112. Vector Spline::at(unsigned int section, float where) {
  113. section = Common::clamp(section, 1u, points - 3);
  114. return interpolate(_XYZ[section - 1], _XYZ[section], _XYZ[section + 1], _XYZ[section + 2], where);
  115. }
  116. Vector Spline::direction(unsigned int section, float where) {
  117. section = Common::clamp(section, 1u, points - 3);
  118. Vector direction(interpolate(_dir[section - 1], _dir[section], _dir[section + 1], _dir[section + 2], where));
  119. direction.normalize();
  120. return direction;
  121. }
  122. // Here's a little calculus that takes 4 points
  123. // and interpolates smoothly between the second and third
  124. // depending on the value of where which can be 0.0 to 1.0.
  125. // The slope at b is estimated using a and c. The slope at c
  126. // is estimated using b and d.
  127. Vector Spline::interpolate(const Vector& a, const Vector& b, const Vector& c, const Vector& d, float where) {
  128. return
  129. (((b * 3.0f) + d - a - (c * 3.0f)) * (where * where * where)) * 0.5f +
  130. (((a * 2.0f) - (b * 5.0f) + (c * 4.0f) - d) * (where * where)) * 0.5f +
  131. ((c - a) * where) * 0.5f +
  132. b;
  133. }