Curve.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * Curve.cpp
  3. */
  4. #include "Base.h"
  5. #include "Curve.h"
  6. #include "Transform.h"
  7. namespace gameplay
  8. {
  9. Curve::Curve(unsigned int pointCount, unsigned int componentCount)
  10. : _pointCount(pointCount), _componentCount(componentCount), _componentSize(0), _quaternionOffsets(NULL), _quaternionOffsetsCount(0), _points(NULL)
  11. {
  12. assert(pointCount > 1 && componentCount > 0);
  13. _componentSize = sizeof(float)*componentCount;
  14. _points = new Point[_pointCount];
  15. for (unsigned int i = 0; i < _pointCount; i++)
  16. {
  17. _points[i].time = 0.0f;
  18. _points[i].value = new float[_componentCount];
  19. _points[i].inValue = new float[_componentCount];
  20. _points[i].outValue = new float[_componentCount];
  21. _points[i].type = LINEAR;
  22. }
  23. _points[_pointCount - 1].time = 1.0f;
  24. }
  25. Curve::~Curve()
  26. {
  27. SAFE_DELETE_ARRAY(_points);
  28. }
  29. Curve::Point::Point()
  30. : time(0.0f), value(NULL), inValue(NULL), outValue(NULL)
  31. {
  32. }
  33. Curve::Point::~Point()
  34. {
  35. SAFE_DELETE_ARRAY(value);
  36. SAFE_DELETE_ARRAY(inValue);
  37. SAFE_DELETE_ARRAY(outValue);
  38. }
  39. unsigned int Curve::getPointCount() const
  40. {
  41. return _pointCount;
  42. }
  43. unsigned int Curve::getComponentCount() const
  44. {
  45. return _componentCount;
  46. }
  47. void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type)
  48. {
  49. setPoint(index, time, value, type, NULL, NULL);
  50. }
  51. void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue)
  52. {
  53. assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(index == 0 && time != 0.0f) && !(index == _pointCount - 1 && time != 1.0f));
  54. _points[index].time = time;
  55. _points[index].type = type;
  56. if (value)
  57. memcpy(_points[index].value, value, _componentSize);
  58. if (inValue)
  59. memcpy(_points[index].inValue, inValue, _componentSize);
  60. if (outValue)
  61. memcpy(_points[index].outValue, outValue, _componentSize);
  62. }
  63. void Curve::setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue)
  64. {
  65. assert(index < _pointCount);
  66. _points[index].type = type;
  67. if (inValue)
  68. memcpy(_points[index].inValue, inValue, _componentSize);
  69. if (outValue)
  70. memcpy(_points[index].outValue, outValue, _componentSize);
  71. }
  72. void Curve::evaluate(float time, float* dst) const
  73. {
  74. assert(dst && time >= 0 && time <= 1.0f);
  75. // Check if we are at or beyond the bounds of the curve.
  76. if (time <= _points[0].time)
  77. {
  78. memcpy(dst, _points[0].value, _componentSize);
  79. return;
  80. }
  81. else if (time >= _points[_pointCount - 1].time)
  82. {
  83. memcpy(dst, _points[_pointCount - 1].value, _componentSize);
  84. return;
  85. }
  86. // Locate the points we are interpolating between using a binary search.
  87. unsigned int index = determineIndex(time);
  88. Point* from = _points + index;
  89. Point* to = _points + (index + 1);
  90. // Calculate the fractional time between the two points.
  91. float scale = (to->time - from->time);
  92. float t = (time - from->time) / scale;
  93. // Calculate the value of the curve discretely if appropriate.
  94. switch (from->type)
  95. {
  96. case BEZIER:
  97. {
  98. interpolateBezier(t, from, to, dst);
  99. break;
  100. }
  101. case BSPLINE:
  102. {
  103. Point* c0;
  104. Point* c1;
  105. if (index == 0)
  106. {
  107. c0 = from;
  108. }
  109. else
  110. {
  111. c0 = (_points + index - 1);
  112. }
  113. if (index == _pointCount - 2)
  114. {
  115. c1 = to;
  116. }
  117. else
  118. {
  119. c1 = (_points + index + 2);
  120. }
  121. interpolateBSpline(t, c0, from, to, c1, dst);
  122. break;
  123. }
  124. case FLAT:
  125. {
  126. interpolateHermiteFlat(t, from, to, dst);
  127. break;
  128. }
  129. case HERMITE:
  130. {
  131. interpolateHermite(t, from, to, dst);
  132. break;
  133. }
  134. case LINEAR:
  135. {
  136. interpolateLinear(t, from, to, dst);
  137. break;
  138. }
  139. case SMOOTH:
  140. {
  141. interpolateHermiteSmooth(t, index, from, to, dst);
  142. break;
  143. }
  144. case STEP:
  145. {
  146. memcpy(dst, from->value, _componentSize);
  147. break;
  148. }
  149. }
  150. }
  151. void Curve::addQuaternionOffset(unsigned int offset)
  152. {
  153. if (!_quaternionOffsets)
  154. {
  155. _quaternionOffsetsCount = 1;
  156. _quaternionOffsets = new unsigned int[_quaternionOffsetsCount];
  157. _quaternionOffsets[0] = offset;
  158. }
  159. else
  160. {
  161. assert((offset >= _componentCount - 4) && (offset > (_quaternionOffsets[_quaternionOffsetsCount - 1] + 3)));
  162. unsigned int oldSize = _quaternionOffsetsCount;
  163. _quaternionOffsetsCount++;
  164. unsigned int* newArray = new unsigned int[_quaternionOffsetsCount];
  165. memcpy(newArray, _quaternionOffsets, sizeof(unsigned int) * oldSize);
  166. // set new offset.
  167. newArray[oldSize] = offset;
  168. delete[] _quaternionOffsets; // delete old array
  169. _quaternionOffsets = newArray; // point to new array.
  170. }
  171. }
  172. void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
  173. {
  174. float s_2 = s * s;
  175. float eq0 = 1 - s;
  176. float eq0_2 = eq0 * eq0;
  177. float eq1 = eq0_2 * eq0;
  178. float eq2 = 3 * s * eq0_2;
  179. float eq3 = 3 * s_2 * eq0;
  180. float eq4 = s_2 * s;
  181. if (!_quaternionOffsets)
  182. {
  183. for (unsigned int i = 0; i < _componentCount; i++)
  184. {
  185. dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
  186. }
  187. }
  188. else
  189. {
  190. // Interpolate values as scalars up to first quaternion offset.
  191. unsigned int quaternionOffsetIndex = 0;
  192. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  193. unsigned int i = 0;
  194. do {
  195. while (i < quaternionOffset)
  196. {
  197. dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
  198. i++;
  199. }
  200. // Handle quaternion component.
  201. float interpTime = from->time * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->time * eq4;
  202. interpolateQuaternion(s, (from->value + i), (to->value + i), (dst + i));
  203. i += 4;
  204. quaternionOffsetIndex++;
  205. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  206. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  207. while (i < _componentCount)
  208. {
  209. dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
  210. i++;
  211. }
  212. }
  213. }
  214. void Curve::interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const
  215. {
  216. float s_2 = s * s;
  217. float s_3 = s_2 * s;
  218. float eq0 = (-s_3 + 3 * s_2 - 3 * s + 1) / 6.0f;
  219. float eq1 = (3 * s_3 - 6 * s_2 + 4) / 6.0f;
  220. float eq2 = (-3 * s_3 + 3 * s_2 + 3 * s + 1) / 6.0f;
  221. float eq3 = s_3 / 6.0f;
  222. if (!_quaternionOffsets)
  223. {
  224. for (unsigned int i = 0; i < _componentCount; i++)
  225. {
  226. dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
  227. }
  228. }
  229. else
  230. {
  231. // Interpolate values as scalars up to first quaternion offset.
  232. unsigned int quaternionOffsetIndex = 0;
  233. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  234. unsigned int i = 0;
  235. do {
  236. while (i < quaternionOffset)
  237. {
  238. dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
  239. i++;
  240. }
  241. // Handle quaternion component.
  242. float interpTime;
  243. if (c0->time == c1->time)
  244. interpTime = -c0->time * eq0 + c1->time * eq1 + c2->time * eq2 + c3->time * eq3;
  245. else if (c2->time == c3->time)
  246. interpTime = c0->time * eq0 + c1->time * eq1 + c2->time * eq2 - c3->time * eq3;
  247. else
  248. interpTime = c0->time * eq0 + c1->time * eq1 + c2->time * eq2 + c3->time * eq3;
  249. interpolateQuaternion(s, (c1->value + quaternionOffset) , (c2->value + quaternionOffset), (dst + quaternionOffset));
  250. i += 4;
  251. quaternionOffsetIndex++;
  252. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  253. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  254. // Handle remaining scalar values.
  255. while (i < _componentCount)
  256. {
  257. dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
  258. i++;
  259. }
  260. }
  261. }
  262. void Curve::interpolateHermite(float s, Point* from, Point* to, float* dst) const
  263. {
  264. // Calculate the hermite basis functions.
  265. float s_2 = s * s; // t^2
  266. float s_3 = s_2 * s; // t^3
  267. float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
  268. float h01 = -2 * s_3 + 3 * s_2; // basis function 1
  269. float h10 = s_3 - 2 * s_2 + s; // basis function 2
  270. float h11 = s_3 - s_2; // basis function 3
  271. if (!_quaternionOffsets)
  272. {
  273. for (unsigned int i = 0; i < _componentCount; i++)
  274. {
  275. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
  276. }
  277. }
  278. else
  279. {
  280. // Interpolate values as scalars up to first quaternion offset.
  281. unsigned int quaternionOffsetIndex = 0;
  282. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  283. unsigned int i = 0;
  284. do {
  285. while (i < quaternionOffset)
  286. {
  287. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
  288. i++;
  289. }
  290. // Handle quaternion component.
  291. float interpTime = h01 * 1.0f + h10 * from->outValue[quaternionOffset] + h11 * to->inValue[quaternionOffset];
  292. interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
  293. i += 4;
  294. quaternionOffsetIndex++;
  295. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  296. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  297. // Handle remaining scalar values.
  298. while (i < _componentCount)
  299. {
  300. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
  301. i++;
  302. }
  303. }
  304. }
  305. void Curve::interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const
  306. {
  307. // Calculate the hermite basis functions.
  308. float s_2 = s * s; // t^2
  309. float s_3 = s_2 * s; // t^3
  310. float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
  311. float h01 = -2 * s_3 + 3 * s_2; // basis function 1
  312. if (!_quaternionOffsets)
  313. {
  314. for (unsigned int i = 0; i < _componentCount; i++)
  315. {
  316. dst[i] = h00 * from->value[i] + h01 * to->value[i];
  317. }
  318. }
  319. else
  320. {
  321. // Interpolate values as scalars up to first quaternion offset.
  322. unsigned int quaternionOffsetIndex = 0;
  323. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  324. unsigned int i = 0;
  325. float interpTime = h01 * 1.0f; // Can drop all other terms because they will compute to 0. Only need to compute once.
  326. do {
  327. while (i < quaternionOffset)
  328. {
  329. dst[i] = h00 * from->value[i] + h01 * to->value[i];
  330. i++;
  331. }
  332. // We've hit a quaternion component, so handle it. increase the component counter by 4, and increase quaternionOffsetIndex
  333. interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
  334. i += 4;
  335. quaternionOffsetIndex++;
  336. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  337. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  338. // Handle remaining scalar values.
  339. while (i < _componentCount)
  340. {
  341. dst[i] = h00 * from->value[i] + h01 * to->value[i];
  342. i++;
  343. }
  344. }
  345. }
  346. void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const
  347. {
  348. // Calculate the hermite basis functions.
  349. float s_2 = s * s; // t^2
  350. float s_3 = s_2 * s; // t^3
  351. float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
  352. float h01 = -2 * s_3 + 3 * s_2; // basis function 1
  353. float h10 = s_3 - 2 * s_2 + s; // basis function 2
  354. float h11 = s_3 - s_2; // basis function 3
  355. float inValue;
  356. float outValue;
  357. if (!_quaternionOffsets)
  358. {
  359. for (unsigned int i = 0; i < _componentCount; i++)
  360. {
  361. if (index == 0)
  362. {
  363. outValue = to->value[i] - from->value[i];
  364. }
  365. else
  366. {
  367. outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
  368. }
  369. if (index == _pointCount - 2)
  370. {
  371. inValue = to->value[i] - from->value[i];
  372. }
  373. else
  374. {
  375. inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
  376. }
  377. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
  378. }
  379. }
  380. else
  381. {
  382. // Calculates in/out values for interpolating the time for the quaternion component.
  383. // Only need to calculate this once.
  384. if (index == 0)
  385. {
  386. outValue = to->time - from->time;
  387. }
  388. else
  389. {
  390. outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
  391. }
  392. if (index == _pointCount - 2)
  393. {
  394. inValue = to->time - from->time;
  395. }
  396. else
  397. {
  398. inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
  399. }
  400. // Interpolate values as scalars up to first quaternion offset.
  401. unsigned int quaternionOffsetIndex = 0;
  402. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  403. unsigned int i = 0;
  404. do {
  405. // Handle scalar values up to the quaternion offset.
  406. while (i < quaternionOffset)
  407. {
  408. // Interpolate as scalar.
  409. if (index == 0)
  410. {
  411. outValue = to->value[i] - from->value[i];
  412. }
  413. else
  414. {
  415. outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
  416. }
  417. if (index == _pointCount - 2)
  418. {
  419. inValue = to->value[i] - from->value[i];
  420. }
  421. else
  422. {
  423. inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
  424. }
  425. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
  426. i++;
  427. }
  428. float interpTime = h01 * 1.0f + h10 * outValue + h11 * inValue;
  429. interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
  430. i+=4;
  431. quaternionOffsetIndex++;
  432. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  433. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  434. // Handle remaining scalar values.
  435. while (i < _componentCount)
  436. {
  437. // Interpolate as scalar.
  438. if (index == 0)
  439. {
  440. outValue = to->value[i] - from->value[i];
  441. }
  442. else
  443. {
  444. outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
  445. }
  446. if (index == _pointCount - 2)
  447. {
  448. inValue = to->value[i] - from->value[i];
  449. }
  450. else
  451. {
  452. inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
  453. }
  454. dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
  455. i++;
  456. }
  457. }
  458. }
  459. void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
  460. {
  461. if (!_quaternionOffsets)
  462. {
  463. for (unsigned int i = 0; i < _componentCount; i++)
  464. {
  465. dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
  466. }
  467. }
  468. else
  469. {
  470. // Interpolate values as scalars up to first quaternion offset.
  471. unsigned int quaternionOffsetIndex = 0;
  472. unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  473. unsigned int i = 0;
  474. do {
  475. // Loop through values until you hit the next quaternion offset.
  476. while (i < quaternionOffset)
  477. {
  478. dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
  479. i++;
  480. }
  481. // Handle quaternion component.
  482. interpolateQuaternion(s, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
  483. i += 4;
  484. quaternionOffsetIndex++;
  485. quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
  486. } while (quaternionOffsetIndex < _quaternionOffsetsCount);
  487. // Loop through the last remaining values, if any.
  488. while (i < _componentCount)
  489. {
  490. dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
  491. i++;
  492. }
  493. }
  494. }
  495. void Curve::interpolateQuaternion(float s, float* from, float* to, float* dst) const
  496. {
  497. Quaternion quatFrom(from);
  498. Quaternion quatTo(to);
  499. Quaternion result;
  500. // Normalize the quaternions.
  501. quatFrom.normalize();
  502. quatTo.normalize();
  503. // Evaluate.
  504. if (s >= 0)
  505. Quaternion::slerp(quatFrom, quatTo, s, &result);
  506. else
  507. Quaternion::slerp(quatTo, quatFrom, -s, &result);
  508. // Place in destination.
  509. dst[0] = result.x;
  510. dst[1] = result.y;
  511. dst[2] = result.z;
  512. dst[3] = result.w;
  513. }
  514. int Curve::determineIndex(float time) const
  515. {
  516. unsigned int min = 0;
  517. unsigned int max = _pointCount - 1;
  518. unsigned int mid = 0;
  519. // Do a binary search to determine the index.
  520. do
  521. {
  522. mid = (min + max) >> 1;
  523. if (time >= _points[mid].time && time <= _points[mid + 1].time)
  524. return mid;
  525. else if (time < _points[mid].time)
  526. max = mid - 1;
  527. else
  528. min = mid + 1;
  529. } while (min <= max);
  530. // We should never hit this!
  531. return -1;
  532. }
  533. }