cameraSpline.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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()
  27. {
  28. mPosition = Point3F::Zero;
  29. mRotation = QuatF::Identity;
  30. mSpeed = 0.0f;
  31. mType = NORMAL;
  32. mPath = SPLINE;
  33. mDistance = 0.0f;
  34. prev = NULL; next = NULL;
  35. };
  36. CameraSpline::Knot::Knot(const Knot &k)
  37. {
  38. mPosition = k.mPosition;
  39. mRotation = k.mRotation;
  40. mSpeed = k.mSpeed;
  41. mType = k.mType;
  42. mPath = k.mPath;
  43. mDistance = k.mDistance;
  44. prev = NULL; next = NULL;
  45. }
  46. CameraSpline::Knot::Knot(const Point3F &p, const QuatF &r, F32 s, Knot::Type type, Knot::Path path)
  47. {
  48. mPosition = p;
  49. mRotation = r;
  50. mSpeed = s;
  51. mType = type;
  52. mPath = path;
  53. mDistance = 0.0f;
  54. prev = NULL; next = NULL;
  55. }
  56. //-----------------------------------------------------------------------------
  57. CameraSpline::CameraSpline()
  58. {
  59. mFront = NULL;
  60. mSize = 0;
  61. mIsMapDirty = true;
  62. VECTOR_SET_ASSOCIATION(mTimeMap);
  63. }
  64. CameraSpline::~CameraSpline()
  65. {
  66. removeAll();
  67. }
  68. void CameraSpline::push_back(Knot *w)
  69. {
  70. if (!mFront)
  71. {
  72. mFront = w;
  73. w->next = w;
  74. w->prev = w;
  75. }
  76. else
  77. {
  78. Knot *before = back();
  79. Knot *after = before->next;
  80. w->next = before->next;
  81. w->prev = before;
  82. after->prev = w;
  83. before->next = w;
  84. }
  85. ++mSize;
  86. mIsMapDirty = true;
  87. }
  88. CameraSpline::Knot* CameraSpline::getKnot(S32 i)
  89. {
  90. Knot *k = mFront;
  91. while(i--)
  92. k = k->next;
  93. return k;
  94. }
  95. CameraSpline::Knot* CameraSpline::remove(Knot *w)
  96. {
  97. if (w->next == mFront && w->prev == mFront)
  98. mFront = NULL;
  99. else
  100. {
  101. w->prev->next = w->next;
  102. w->next->prev = w->prev;
  103. if (mFront == w)
  104. mFront = w->next;
  105. }
  106. --mSize;
  107. mIsMapDirty = true;
  108. return w;
  109. }
  110. void CameraSpline::removeAll()
  111. {
  112. while(front())
  113. delete remove(front());
  114. mSize = 0;
  115. }
  116. //-----------------------------------------------------------------------------
  117. static bool gBuilding = false;
  118. void CameraSpline::buildTimeMap()
  119. {
  120. if (!mIsMapDirty)
  121. return;
  122. gBuilding = true;
  123. mTimeMap.clear();
  124. mTimeMap.reserve(size()*3); // preallocate
  125. // Initial node and knot value..
  126. TimeMap map;
  127. map.mTime = 0;
  128. map.mDistance = 0;
  129. mTimeMap.push_back(map);
  130. Knot ka,kj,ki;
  131. value(0, &kj, true);
  132. F32 length = 0.0f;
  133. ka = kj;
  134. // Loop through the knots and add nodes. Nodes are added for every knot and
  135. // whenever the spline length and segment length deviate by epsilon.
  136. F32 epsilon = Con::getFloatVariable("CameraSpline::epsilon", 0.90f);
  137. const F32 Step = 0.05f;
  138. F32 lt = 0,time = 0;
  139. do
  140. {
  141. if ((time += Step) > F32(mSize - 1))
  142. time = (F32)mSize - 1.0f;
  143. value(time, &ki, true);
  144. length += (ki.mPosition - kj.mPosition).len();
  145. F32 segment = (ki.mPosition - ka.mPosition).len();
  146. if ((segment / length) < epsilon || time == (mSize - 1) || mFloor(lt) != mFloor(time))
  147. {
  148. map.mTime = time;
  149. map.mDistance = length;
  150. mTimeMap.push_back(map);
  151. ka = ki;
  152. }
  153. kj = ki;
  154. lt = time;
  155. }
  156. while (time < mSize - 1);
  157. mIsMapDirty = false;
  158. gBuilding = false;
  159. }
  160. //-----------------------------------------------------------------------------
  161. void CameraSpline::renderTimeMap()
  162. {
  163. buildTimeMap();
  164. gBuilding = true;
  165. // Build vertex buffer
  166. GFXVertexBufferHandle<GFXVertexPCT> vb;
  167. vb.set(GFX, mTimeMap.size(), GFXBufferTypeVolatile);
  168. void *ptr = vb.lock();
  169. if(!ptr) return;
  170. MRandomLCG random(1376312589 * (uintptr_t)this);
  171. S32 index = 0;
  172. for(Vector<TimeMap>::iterator itr=mTimeMap.begin(); itr != mTimeMap.end(); itr++)
  173. {
  174. Knot a;
  175. value(itr->mTime, &a, true);
  176. S32 cr = random.randI(0,255);
  177. S32 cg = random.randI(0,255);
  178. S32 cb = random.randI(0,255);
  179. vb[index].color.set(cr, cg, cb);
  180. vb[index].point.set(a.mPosition.x, a.mPosition.y, a.mPosition.z);
  181. index++;
  182. }
  183. gBuilding = false;
  184. vb.unlock();
  185. // Render the buffer
  186. GFX->pushWorldMatrix();
  187. GFX->setupGenericShaders();
  188. GFX->setVertexBuffer(vb);
  189. GFX->drawPrimitive(GFXLineStrip,0,index);
  190. GFX->popWorldMatrix();
  191. }
  192. //-----------------------------------------------------------------------------
  193. F32 CameraSpline::advanceTime(F32 t, S32 delta_ms)
  194. {
  195. buildTimeMap();
  196. Knot k;
  197. value(t, &k, false);
  198. F32 dist = getDistance(t) + k.mSpeed * (F32(delta_ms) / 1000.0f);
  199. return getTime(dist);
  200. }
  201. F32 CameraSpline::advanceDist(F32 t, F32 meters)
  202. {
  203. buildTimeMap();
  204. F32 dist = getDistance(t) + meters;
  205. return getTime(dist);
  206. }
  207. F32 CameraSpline::getDistance(F32 t)
  208. {
  209. if (mSize <= 1)
  210. return 0;
  211. // Find the nodes spanning the time
  212. Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
  213. for (; end < (mTimeMap.end() - 1) && end->mTime < t; end++) { }
  214. start = end - 1;
  215. // Interpolate between the two nodes
  216. F32 i = (t - start->mTime) / (end->mTime - start->mTime);
  217. return start->mDistance + (end->mDistance - start->mDistance) * i;
  218. }
  219. F32 CameraSpline::getTime(F32 d)
  220. {
  221. if (mSize <= 1)
  222. return 0;
  223. // Find nodes spanning the distance
  224. Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
  225. for (; end < (mTimeMap.end() - 1) && end->mDistance < d; end++) { }
  226. start = end - 1;
  227. // Check for duplicate points..
  228. F32 seg = end->mDistance - start->mDistance;
  229. if (!seg)
  230. return end->mTime;
  231. // Interpolate between the two nodes
  232. F32 i = (d - start->mDistance) / (end->mDistance - start->mDistance);
  233. return start->mTime + (end->mTime - start->mTime) * i;
  234. }
  235. //-----------------------------------------------------------------------------
  236. void CameraSpline::value(F32 t, CameraSpline::Knot *result, bool skip_rotation)
  237. {
  238. // Do some easing in and out for t.
  239. if(!gBuilding)
  240. {
  241. F32 oldT = t;
  242. if(oldT < 0.5f)
  243. {
  244. t = 0.5f - (mSin( (0.5 - oldT) * M_PI ) / 2.f);
  245. }
  246. if((F32(size()) - 1.5f) > 0.f && oldT - (F32(size()) - 1.5f) > 0.f)
  247. {
  248. oldT -= (F32(size()) - 1.5f);
  249. t = (F32(size()) - 1.5f) + (mCos( (0.5f - oldT) * F32(M_PI) ) / 2.f);
  250. }
  251. }
  252. // Verify that t is in range [0 >= t > size]
  253. // AssertFatal(t >= 0.0f && t < (F32)size(), "t out of range");
  254. Knot *p1 = getKnot((S32)mFloor(t));
  255. Knot *p2 = next(p1);
  256. F32 i = t - mFloor(t); // adjust t to 0 to 1 on p1-p2 interval
  257. if (p1->mPath == Knot::SPLINE)
  258. {
  259. Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
  260. Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
  261. result->mPosition.x = mCatmullrom(i, p0->mPosition.x, p1->mPosition.x, p2->mPosition.x, p3->mPosition.x);
  262. result->mPosition.y = mCatmullrom(i, p0->mPosition.y, p1->mPosition.y, p2->mPosition.y, p3->mPosition.y);
  263. result->mPosition.z = mCatmullrom(i, p0->mPosition.z, p1->mPosition.z, p2->mPosition.z, p3->mPosition.z);
  264. }
  265. else
  266. { // Linear
  267. result->mPosition.interpolate(p1->mPosition, p2->mPosition, i);
  268. }
  269. if (skip_rotation)
  270. return;
  271. buildTimeMap();
  272. // find the two knots to interpolate rotation and velocity through since some
  273. // knots are only positional
  274. S32 start = (S32)mFloor(t);
  275. S32 end = (p2 == p1) ? start : (start + 1);
  276. while (p1->mType == Knot::POSITION_ONLY && p1 != front())
  277. {
  278. p1 = prev(p1);
  279. start--;
  280. }
  281. while (p2->mType == Knot::POSITION_ONLY && p2 != back())
  282. {
  283. p2 = next(p2);
  284. end++;
  285. }
  286. if (start == end)
  287. {
  288. result->mRotation = p1->mRotation;
  289. result->mSpeed = p1->mSpeed;
  290. }
  291. else
  292. {
  293. F32 c = getDistance(t);
  294. F32 d1 = getDistance((F32)start);
  295. F32 d2 = getDistance((F32)end);
  296. if (d1 == d2)
  297. {
  298. result->mRotation = p2->mRotation;
  299. result->mSpeed = p2->mSpeed;
  300. }
  301. else
  302. {
  303. i = (c-d1)/(d2-d1);
  304. if(p1->mPath == Knot::SPLINE)
  305. {
  306. Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
  307. Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
  308. F32 q,w,e;
  309. q = mCatmullrom(i, 0, 1, 1, 1);
  310. w = mCatmullrom(i, 0, 0, 0, 1);
  311. e = mCatmullrom(i, 0, 0, 1, 1);
  312. QuatF a; a.interpolate(p0->mRotation, p1->mRotation, q);
  313. QuatF b; b.interpolate(p2->mRotation, p3->mRotation, w);
  314. result->mRotation.interpolate(a, b, e);
  315. result->mSpeed = mCatmullrom(i, p0->mSpeed, p1->mSpeed, p2->mSpeed, p3->mSpeed);
  316. }
  317. else
  318. {
  319. result->mRotation.interpolate(p1->mRotation, p2->mRotation, i);
  320. result->mSpeed = (p1->mSpeed * (1.0f-i)) + (p2->mSpeed * i);
  321. }
  322. }
  323. }
  324. }