cameraSpline.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "T3D/cameraSpline.h"
  23. #include "console/console.h"
  24. #include "gfx/gfxDevice.h"
  25. //-----------------------------------------------------------------------------
  26. CameraSpline::Knot::Knot(const Knot &k)
  27. {
  28. mPosition = k.mPosition;
  29. mRotation = k.mRotation;
  30. mSpeed = k.mSpeed;
  31. mType = k.mType;
  32. mPath = k.mPath;
  33. prev = NULL; next = NULL;
  34. }
  35. CameraSpline::Knot::Knot(const Point3F &p, const QuatF &r, F32 s, Knot::Type type, Knot::Path path)
  36. {
  37. mPosition = p;
  38. mRotation = r;
  39. mSpeed = s;
  40. mType = type;
  41. mPath = path;
  42. prev = NULL; next = NULL;
  43. }
  44. //-----------------------------------------------------------------------------
  45. CameraSpline::CameraSpline()
  46. {
  47. mFront = NULL;
  48. mSize = 0;
  49. mIsMapDirty = true;
  50. VECTOR_SET_ASSOCIATION(mTimeMap);
  51. }
  52. CameraSpline::~CameraSpline()
  53. {
  54. removeAll();
  55. }
  56. void CameraSpline::push_back(Knot *w)
  57. {
  58. if (!mFront)
  59. {
  60. mFront = w;
  61. w->next = w;
  62. w->prev = w;
  63. }
  64. else
  65. {
  66. Knot *before = back();
  67. Knot *after = before->next;
  68. w->next = before->next;
  69. w->prev = before;
  70. after->prev = w;
  71. before->next = w;
  72. }
  73. ++mSize;
  74. mIsMapDirty = true;
  75. }
  76. CameraSpline::Knot* CameraSpline::getKnot(S32 i)
  77. {
  78. Knot *k = mFront;
  79. while(i--)
  80. k = k->next;
  81. return k;
  82. }
  83. CameraSpline::Knot* CameraSpline::remove(Knot *w)
  84. {
  85. if (w->next == mFront && w->prev == mFront)
  86. mFront = NULL;
  87. else
  88. {
  89. w->prev->next = w->next;
  90. w->next->prev = w->prev;
  91. if (mFront == w)
  92. mFront = w->next;
  93. }
  94. --mSize;
  95. mIsMapDirty = true;
  96. return w;
  97. }
  98. void CameraSpline::removeAll()
  99. {
  100. while(front())
  101. delete remove(front());
  102. mSize = 0;
  103. }
  104. //-----------------------------------------------------------------------------
  105. static bool gBuilding = false;
  106. void CameraSpline::buildTimeMap()
  107. {
  108. if (!mIsMapDirty)
  109. return;
  110. gBuilding = true;
  111. mTimeMap.clear();
  112. mTimeMap.reserve(size()*3); // preallocate
  113. // Initial node and knot value..
  114. TimeMap map;
  115. map.mTime = 0;
  116. map.mDistance = 0;
  117. mTimeMap.push_back(map);
  118. Knot ka,kj,ki;
  119. value(0, &kj, true);
  120. F32 length = 0.0f;
  121. ka = kj;
  122. // Loop through the knots and add nodes. Nodes are added for every knot and
  123. // whenever the spline length and segment length deviate by epsilon.
  124. F32 epsilon = Con::getFloatVariable("CameraSpline::epsilon", 0.90f);
  125. const F32 Step = 0.05f;
  126. F32 lt = 0,time = 0;
  127. do
  128. {
  129. if ((time += Step) > F32(mSize - 1))
  130. time = (F32)mSize - 1.0f;
  131. value(time, &ki, true);
  132. length += (ki.mPosition - kj.mPosition).len();
  133. F32 segment = (ki.mPosition - ka.mPosition).len();
  134. if ((segment / length) < epsilon || time == (mSize - 1) || mFloor(lt) != mFloor(time))
  135. {
  136. map.mTime = time;
  137. map.mDistance = length;
  138. mTimeMap.push_back(map);
  139. ka = ki;
  140. }
  141. kj = ki;
  142. lt = time;
  143. }
  144. while (time < mSize - 1);
  145. mIsMapDirty = false;
  146. gBuilding = false;
  147. }
  148. //-----------------------------------------------------------------------------
  149. void CameraSpline::renderTimeMap()
  150. {
  151. buildTimeMap();
  152. gBuilding = true;
  153. // Build vertex buffer
  154. GFXVertexBufferHandle<GFXVertexPC> vb;
  155. vb.set(GFX, mTimeMap.size(), GFXBufferTypeVolatile);
  156. void *ptr = vb.lock();
  157. if(!ptr) return;
  158. MRandomLCG random(1376312589 * (uintptr_t)this);
  159. S32 index = 0;
  160. for(Vector<TimeMap>::iterator itr=mTimeMap.begin(); itr != mTimeMap.end(); itr++)
  161. {
  162. Knot a;
  163. value(itr->mTime, &a, true);
  164. S32 cr = random.randI(0,255);
  165. S32 cg = random.randI(0,255);
  166. S32 cb = random.randI(0,255);
  167. vb[index].color.set(cr, cg, cb);
  168. vb[index].point.set(a.mPosition.x, a.mPosition.y, a.mPosition.z);
  169. index++;
  170. }
  171. gBuilding = false;
  172. vb.unlock();
  173. // Render the buffer
  174. GFX->pushWorldMatrix();
  175. GFX->setupGenericShaders();
  176. GFX->setVertexBuffer(vb);
  177. GFX->drawPrimitive(GFXLineStrip,0,index);
  178. GFX->popWorldMatrix();
  179. }
  180. //-----------------------------------------------------------------------------
  181. F32 CameraSpline::advanceTime(F32 t, S32 delta_ms)
  182. {
  183. buildTimeMap();
  184. Knot k;
  185. value(t, &k, false);
  186. F32 dist = getDistance(t) + k.mSpeed * (F32(delta_ms) / 1000.0f);
  187. return getTime(dist);
  188. }
  189. F32 CameraSpline::advanceDist(F32 t, F32 meters)
  190. {
  191. buildTimeMap();
  192. F32 dist = getDistance(t) + meters;
  193. return getTime(dist);
  194. }
  195. F32 CameraSpline::getDistance(F32 t)
  196. {
  197. if (mSize <= 1)
  198. return 0;
  199. // Find the nodes spanning the time
  200. Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
  201. for (; end < (mTimeMap.end() - 1) && end->mTime < t; end++) { }
  202. start = end - 1;
  203. // Interpolate between the two nodes
  204. F32 i = (t - start->mTime) / (end->mTime - start->mTime);
  205. return start->mDistance + (end->mDistance - start->mDistance) * i;
  206. }
  207. F32 CameraSpline::getTime(F32 d)
  208. {
  209. if (mSize <= 1)
  210. return 0;
  211. // Find nodes spanning the distance
  212. Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
  213. for (; end < (mTimeMap.end() - 1) && end->mDistance < d; end++) { }
  214. start = end - 1;
  215. // Check for duplicate points..
  216. F32 seg = end->mDistance - start->mDistance;
  217. if (!seg)
  218. return end->mTime;
  219. // Interpolate between the two nodes
  220. F32 i = (d - start->mDistance) / (end->mDistance - start->mDistance);
  221. return start->mTime + (end->mTime - start->mTime) * i;
  222. }
  223. //-----------------------------------------------------------------------------
  224. void CameraSpline::value(F32 t, CameraSpline::Knot *result, bool skip_rotation)
  225. {
  226. // Do some easing in and out for t.
  227. if(!gBuilding)
  228. {
  229. F32 oldT = t;
  230. if(oldT < 0.5f)
  231. {
  232. t = 0.5f - (mSin( (0.5 - oldT) * M_PI ) / 2.f);
  233. }
  234. if((F32(size()) - 1.5f) > 0.f && oldT - (F32(size()) - 1.5f) > 0.f)
  235. {
  236. oldT -= (F32(size()) - 1.5f);
  237. t = (F32(size()) - 1.5f) + (mCos( (0.5f - oldT) * F32(M_PI) ) / 2.f);
  238. }
  239. }
  240. // Verify that t is in range [0 >= t > size]
  241. // AssertFatal(t >= 0.0f && t < (F32)size(), "t out of range");
  242. Knot *p1 = getKnot((S32)mFloor(t));
  243. Knot *p2 = next(p1);
  244. F32 i = t - mFloor(t); // adjust t to 0 to 1 on p1-p2 interval
  245. if (p1->mPath == Knot::SPLINE)
  246. {
  247. Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
  248. Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
  249. result->mPosition.x = mCatmullrom(i, p0->mPosition.x, p1->mPosition.x, p2->mPosition.x, p3->mPosition.x);
  250. result->mPosition.y = mCatmullrom(i, p0->mPosition.y, p1->mPosition.y, p2->mPosition.y, p3->mPosition.y);
  251. result->mPosition.z = mCatmullrom(i, p0->mPosition.z, p1->mPosition.z, p2->mPosition.z, p3->mPosition.z);
  252. }
  253. else
  254. { // Linear
  255. result->mPosition.interpolate(p1->mPosition, p2->mPosition, i);
  256. }
  257. if (skip_rotation)
  258. return;
  259. buildTimeMap();
  260. // find the two knots to interpolate rotation and velocity through since some
  261. // knots are only positional
  262. S32 start = (S32)mFloor(t);
  263. S32 end = (p2 == p1) ? start : (start + 1);
  264. while (p1->mType == Knot::POSITION_ONLY && p1 != front())
  265. {
  266. p1 = prev(p1);
  267. start--;
  268. }
  269. while (p2->mType == Knot::POSITION_ONLY && p2 != back())
  270. {
  271. p2 = next(p2);
  272. end++;
  273. }
  274. if (start == end)
  275. {
  276. result->mRotation = p1->mRotation;
  277. result->mSpeed = p1->mSpeed;
  278. }
  279. else
  280. {
  281. F32 c = getDistance(t);
  282. F32 d1 = getDistance((F32)start);
  283. F32 d2 = getDistance((F32)end);
  284. if (d1 == d2)
  285. {
  286. result->mRotation = p2->mRotation;
  287. result->mSpeed = p2->mSpeed;
  288. }
  289. else
  290. {
  291. i = (c-d1)/(d2-d1);
  292. if(p1->mPath == Knot::SPLINE)
  293. {
  294. Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
  295. Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
  296. F32 q,w,e;
  297. q = mCatmullrom(i, 0, 1, 1, 1);
  298. w = mCatmullrom(i, 0, 0, 0, 1);
  299. e = mCatmullrom(i, 0, 0, 1, 1);
  300. QuatF a; a.interpolate(p0->mRotation, p1->mRotation, q);
  301. QuatF b; b.interpolate(p2->mRotation, p3->mRotation, w);
  302. result->mRotation.interpolate(a, b, e);
  303. result->mSpeed = mCatmullrom(i, p0->mSpeed, p1->mSpeed, p2->mSpeed, p3->mSpeed);
  304. }
  305. else
  306. {
  307. result->mRotation.interpolate(p1->mRotation, p2->mRotation, i);
  308. result->mSpeed = (p1->mSpeed * (1.0f-i)) + (p2->mSpeed * i);
  309. }
  310. }
  311. }
  312. }