cameraSpline.cpp 9.8 KB

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