cameraSpline.cpp 9.9 KB

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