curve.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247
  1. /**************************************************************************/
  2. /* curve.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "curve.h"
  31. #include "core/core_string_names.h"
  32. #include "core/math/math_funcs.h"
  33. const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
  34. Curve::Curve() {
  35. }
  36. void Curve::set_point_count(int p_count) {
  37. ERR_FAIL_COND(p_count < 0);
  38. if (_points.size() >= p_count) {
  39. _points.resize(p_count);
  40. mark_dirty();
  41. } else {
  42. for (int i = p_count - _points.size(); i > 0; i--) {
  43. _add_point(Vector2());
  44. }
  45. }
  46. notify_property_list_changed();
  47. }
  48. int Curve::_add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
  49. // Add a point and preserve order
  50. // Curve bounds is in 0..1
  51. if (p_position.x > MAX_X) {
  52. p_position.x = MAX_X;
  53. } else if (p_position.x < MIN_X) {
  54. p_position.x = MIN_X;
  55. }
  56. int ret = -1;
  57. if (_points.size() == 0) {
  58. _points.push_back(Point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode));
  59. ret = 0;
  60. } else if (_points.size() == 1) {
  61. // TODO Is the `else` able to handle this block already?
  62. real_t diff = p_position.x - _points[0].position.x;
  63. if (diff > 0) {
  64. _points.push_back(Point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode));
  65. ret = 1;
  66. } else {
  67. _points.insert(0, Point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode));
  68. ret = 0;
  69. }
  70. } else {
  71. int i = get_index(p_position.x);
  72. if (i == 0 && p_position.x < _points[0].position.x) {
  73. // Insert before anything else
  74. _points.insert(0, Point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode));
  75. ret = 0;
  76. } else {
  77. // Insert between i and i+1
  78. ++i;
  79. _points.insert(i, Point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode));
  80. ret = i;
  81. }
  82. }
  83. update_auto_tangents(ret);
  84. mark_dirty();
  85. return ret;
  86. }
  87. int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
  88. int ret = _add_point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode);
  89. notify_property_list_changed();
  90. return ret;
  91. }
  92. int Curve::get_index(real_t p_offset) const {
  93. // Lower-bound float binary search
  94. int imin = 0;
  95. int imax = _points.size() - 1;
  96. while (imax - imin > 1) {
  97. int m = (imin + imax) / 2;
  98. real_t a = _points[m].position.x;
  99. real_t b = _points[m + 1].position.x;
  100. if (a < p_offset && b < p_offset) {
  101. imin = m;
  102. } else if (a > p_offset) {
  103. imax = m;
  104. } else {
  105. return m;
  106. }
  107. }
  108. // Will happen if the offset is out of bounds
  109. if (p_offset > _points[imax].position.x) {
  110. return imax;
  111. }
  112. return imin;
  113. }
  114. void Curve::clean_dupes() {
  115. bool dirty = false;
  116. for (int i = 1; i < _points.size(); ++i) {
  117. real_t diff = _points[i - 1].position.x - _points[i].position.x;
  118. if (diff <= CMP_EPSILON) {
  119. _points.remove_at(i);
  120. --i;
  121. dirty = true;
  122. }
  123. }
  124. if (dirty) {
  125. mark_dirty();
  126. }
  127. }
  128. void Curve::set_point_left_tangent(int p_index, real_t p_tangent) {
  129. ERR_FAIL_INDEX(p_index, _points.size());
  130. _points.write[p_index].left_tangent = p_tangent;
  131. _points.write[p_index].left_mode = TANGENT_FREE;
  132. mark_dirty();
  133. }
  134. void Curve::set_point_right_tangent(int p_index, real_t p_tangent) {
  135. ERR_FAIL_INDEX(p_index, _points.size());
  136. _points.write[p_index].right_tangent = p_tangent;
  137. _points.write[p_index].right_mode = TANGENT_FREE;
  138. mark_dirty();
  139. }
  140. void Curve::set_point_left_mode(int p_index, TangentMode p_mode) {
  141. ERR_FAIL_INDEX(p_index, _points.size());
  142. _points.write[p_index].left_mode = p_mode;
  143. if (p_index > 0) {
  144. if (p_mode == TANGENT_LINEAR) {
  145. Vector2 v = (_points[p_index - 1].position - _points[p_index].position).normalized();
  146. _points.write[p_index].left_tangent = v.y / v.x;
  147. }
  148. }
  149. mark_dirty();
  150. }
  151. void Curve::set_point_right_mode(int p_index, TangentMode p_mode) {
  152. ERR_FAIL_INDEX(p_index, _points.size());
  153. _points.write[p_index].right_mode = p_mode;
  154. if (p_index + 1 < _points.size()) {
  155. if (p_mode == TANGENT_LINEAR) {
  156. Vector2 v = (_points[p_index + 1].position - _points[p_index].position).normalized();
  157. _points.write[p_index].right_tangent = v.y / v.x;
  158. }
  159. }
  160. mark_dirty();
  161. }
  162. real_t Curve::get_point_left_tangent(int p_index) const {
  163. ERR_FAIL_INDEX_V(p_index, _points.size(), 0);
  164. return _points[p_index].left_tangent;
  165. }
  166. real_t Curve::get_point_right_tangent(int p_index) const {
  167. ERR_FAIL_INDEX_V(p_index, _points.size(), 0);
  168. return _points[p_index].right_tangent;
  169. }
  170. Curve::TangentMode Curve::get_point_left_mode(int p_index) const {
  171. ERR_FAIL_INDEX_V(p_index, _points.size(), TANGENT_FREE);
  172. return _points[p_index].left_mode;
  173. }
  174. Curve::TangentMode Curve::get_point_right_mode(int p_index) const {
  175. ERR_FAIL_INDEX_V(p_index, _points.size(), TANGENT_FREE);
  176. return _points[p_index].right_mode;
  177. }
  178. void Curve::_remove_point(int p_index) {
  179. ERR_FAIL_INDEX(p_index, _points.size());
  180. _points.remove_at(p_index);
  181. mark_dirty();
  182. }
  183. void Curve::remove_point(int p_index) {
  184. _remove_point(p_index);
  185. notify_property_list_changed();
  186. }
  187. void Curve::clear_points() {
  188. _points.clear();
  189. mark_dirty();
  190. notify_property_list_changed();
  191. }
  192. void Curve::set_point_value(int p_index, real_t p_position) {
  193. ERR_FAIL_INDEX(p_index, _points.size());
  194. _points.write[p_index].position.y = p_position;
  195. update_auto_tangents(p_index);
  196. mark_dirty();
  197. }
  198. int Curve::set_point_offset(int p_index, real_t p_offset) {
  199. ERR_FAIL_INDEX_V(p_index, _points.size(), -1);
  200. Point p = _points[p_index];
  201. _remove_point(p_index);
  202. int i = _add_point(Vector2(p_offset, p.position.y));
  203. _points.write[i].left_tangent = p.left_tangent;
  204. _points.write[i].right_tangent = p.right_tangent;
  205. _points.write[i].left_mode = p.left_mode;
  206. _points.write[i].right_mode = p.right_mode;
  207. if (p_index != i) {
  208. update_auto_tangents(p_index);
  209. }
  210. update_auto_tangents(i);
  211. return i;
  212. }
  213. Vector2 Curve::get_point_position(int p_index) const {
  214. ERR_FAIL_INDEX_V(p_index, _points.size(), Vector2(0, 0));
  215. return _points[p_index].position;
  216. }
  217. Curve::Point Curve::get_point(int p_index) const {
  218. ERR_FAIL_INDEX_V(p_index, _points.size(), Point());
  219. return _points[p_index];
  220. }
  221. void Curve::update_auto_tangents(int p_index) {
  222. Point &p = _points.write[p_index];
  223. if (p_index > 0) {
  224. if (p.left_mode == TANGENT_LINEAR) {
  225. Vector2 v = (_points[p_index - 1].position - p.position).normalized();
  226. p.left_tangent = v.y / v.x;
  227. }
  228. if (_points[p_index - 1].right_mode == TANGENT_LINEAR) {
  229. Vector2 v = (_points[p_index - 1].position - p.position).normalized();
  230. _points.write[p_index - 1].right_tangent = v.y / v.x;
  231. }
  232. }
  233. if (p_index + 1 < _points.size()) {
  234. if (p.right_mode == TANGENT_LINEAR) {
  235. Vector2 v = (_points[p_index + 1].position - p.position).normalized();
  236. p.right_tangent = v.y / v.x;
  237. }
  238. if (_points[p_index + 1].left_mode == TANGENT_LINEAR) {
  239. Vector2 v = (_points[p_index + 1].position - p.position).normalized();
  240. _points.write[p_index + 1].left_tangent = v.y / v.x;
  241. }
  242. }
  243. }
  244. #define MIN_Y_RANGE 0.01
  245. void Curve::set_min_value(real_t p_min) {
  246. if (_minmax_set_once & 0b11 && p_min > _max_value - MIN_Y_RANGE) {
  247. _min_value = _max_value - MIN_Y_RANGE;
  248. } else {
  249. _minmax_set_once |= 0b10; // first bit is "min set"
  250. _min_value = p_min;
  251. }
  252. // Note: min and max are indicative values,
  253. // it's still possible that existing points are out of range at this point.
  254. emit_signal(SNAME(SIGNAL_RANGE_CHANGED));
  255. }
  256. void Curve::set_max_value(real_t p_max) {
  257. if (_minmax_set_once & 0b11 && p_max < _min_value + MIN_Y_RANGE) {
  258. _max_value = _min_value + MIN_Y_RANGE;
  259. } else {
  260. _minmax_set_once |= 0b01; // second bit is "max set"
  261. _max_value = p_max;
  262. }
  263. emit_signal(SNAME(SIGNAL_RANGE_CHANGED));
  264. }
  265. real_t Curve::sample(real_t p_offset) const {
  266. if (_points.size() == 0) {
  267. return 0;
  268. }
  269. if (_points.size() == 1) {
  270. return _points[0].position.y;
  271. }
  272. int i = get_index(p_offset);
  273. if (i == _points.size() - 1) {
  274. return _points[i].position.y;
  275. }
  276. real_t local = p_offset - _points[i].position.x;
  277. if (i == 0 && local <= 0) {
  278. return _points[0].position.y;
  279. }
  280. return sample_local_nocheck(i, local);
  281. }
  282. real_t Curve::sample_local_nocheck(int p_index, real_t p_local_offset) const {
  283. const Point a = _points[p_index];
  284. const Point b = _points[p_index + 1];
  285. /* Cubic bézier
  286. *
  287. * ac-----bc
  288. * / \
  289. * / \ Here with a.right_tangent > 0
  290. * / \ and b.left_tangent < 0
  291. * / \
  292. * a b
  293. *
  294. * |-d1--|-d2--|-d3--|
  295. *
  296. * d1 == d2 == d3 == d / 3
  297. */
  298. // Control points are chosen at equal distances
  299. real_t d = b.position.x - a.position.x;
  300. if (Math::is_zero_approx(d)) {
  301. return b.position.y;
  302. }
  303. p_local_offset /= d;
  304. d /= 3.0;
  305. real_t yac = a.position.y + d * a.right_tangent;
  306. real_t ybc = b.position.y - d * b.left_tangent;
  307. real_t y = Math::bezier_interpolate(a.position.y, yac, ybc, b.position.y, p_local_offset);
  308. return y;
  309. }
  310. void Curve::mark_dirty() {
  311. _baked_cache_dirty = true;
  312. emit_signal(CoreStringNames::get_singleton()->changed);
  313. }
  314. Array Curve::get_data() const {
  315. Array output;
  316. const unsigned int ELEMS = 5;
  317. output.resize(_points.size() * ELEMS);
  318. for (int j = 0; j < _points.size(); ++j) {
  319. const Point p = _points[j];
  320. int i = j * ELEMS;
  321. output[i] = p.position;
  322. output[i + 1] = p.left_tangent;
  323. output[i + 2] = p.right_tangent;
  324. output[i + 3] = p.left_mode;
  325. output[i + 4] = p.right_mode;
  326. }
  327. return output;
  328. }
  329. void Curve::set_data(const Array p_input) {
  330. const unsigned int ELEMS = 5;
  331. ERR_FAIL_COND(p_input.size() % ELEMS != 0);
  332. _points.clear();
  333. // Validate input
  334. for (int i = 0; i < p_input.size(); i += ELEMS) {
  335. ERR_FAIL_COND(p_input[i].get_type() != Variant::VECTOR2);
  336. ERR_FAIL_COND(!p_input[i + 1].is_num());
  337. ERR_FAIL_COND(p_input[i + 2].get_type() != Variant::FLOAT);
  338. ERR_FAIL_COND(p_input[i + 3].get_type() != Variant::INT);
  339. int left_mode = p_input[i + 3];
  340. ERR_FAIL_COND(left_mode < 0 || left_mode >= TANGENT_MODE_COUNT);
  341. ERR_FAIL_COND(p_input[i + 4].get_type() != Variant::INT);
  342. int right_mode = p_input[i + 4];
  343. ERR_FAIL_COND(right_mode < 0 || right_mode >= TANGENT_MODE_COUNT);
  344. }
  345. _points.resize(p_input.size() / ELEMS);
  346. for (int j = 0; j < _points.size(); ++j) {
  347. Point &p = _points.write[j];
  348. int i = j * ELEMS;
  349. p.position = p_input[i];
  350. p.left_tangent = p_input[i + 1];
  351. p.right_tangent = p_input[i + 2];
  352. int left_mode = p_input[i + 3];
  353. int right_mode = p_input[i + 4];
  354. p.left_mode = (TangentMode)left_mode;
  355. p.right_mode = (TangentMode)right_mode;
  356. }
  357. mark_dirty();
  358. notify_property_list_changed();
  359. }
  360. void Curve::bake() {
  361. _baked_cache.clear();
  362. _baked_cache.resize(_bake_resolution);
  363. for (int i = 1; i < _bake_resolution - 1; ++i) {
  364. real_t x = i / static_cast<real_t>(_bake_resolution);
  365. real_t y = sample(x);
  366. _baked_cache.write[i] = y;
  367. }
  368. if (_points.size() != 0) {
  369. _baked_cache.write[0] = _points[0].position.y;
  370. _baked_cache.write[_baked_cache.size() - 1] = _points[_points.size() - 1].position.y;
  371. }
  372. _baked_cache_dirty = false;
  373. }
  374. void Curve::set_bake_resolution(int p_resolution) {
  375. ERR_FAIL_COND(p_resolution < 1);
  376. ERR_FAIL_COND(p_resolution > 1000);
  377. _bake_resolution = p_resolution;
  378. _baked_cache_dirty = true;
  379. }
  380. real_t Curve::sample_baked(real_t p_offset) const {
  381. if (_baked_cache_dirty) {
  382. // Last-second bake if not done already
  383. const_cast<Curve *>(this)->bake();
  384. }
  385. // Special cases if the cache is too small
  386. if (_baked_cache.size() == 0) {
  387. if (_points.size() == 0) {
  388. return 0;
  389. }
  390. return _points[0].position.y;
  391. } else if (_baked_cache.size() == 1) {
  392. return _baked_cache[0];
  393. }
  394. // Get interpolation index
  395. real_t fi = p_offset * _baked_cache.size();
  396. int i = Math::floor(fi);
  397. if (i < 0) {
  398. i = 0;
  399. fi = 0;
  400. } else if (i >= _baked_cache.size()) {
  401. i = _baked_cache.size() - 1;
  402. fi = 0;
  403. }
  404. // Sample
  405. if (i + 1 < _baked_cache.size()) {
  406. real_t t = fi - i;
  407. return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t);
  408. } else {
  409. return _baked_cache[_baked_cache.size() - 1];
  410. }
  411. }
  412. void Curve::ensure_default_setup(real_t p_min, real_t p_max) {
  413. if (_points.size() == 0 && _min_value == 0 && _max_value == 1) {
  414. add_point(Vector2(0, 1));
  415. add_point(Vector2(1, 1));
  416. set_min_value(p_min);
  417. set_max_value(p_max);
  418. }
  419. }
  420. bool Curve::_set(const StringName &p_name, const Variant &p_value) {
  421. Vector<String> components = String(p_name).split("/", true, 2);
  422. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  423. int point_index = components[0].trim_prefix("point_").to_int();
  424. String property = components[1];
  425. if (property == "position") {
  426. Vector2 position = p_value.operator Vector2();
  427. set_point_offset(point_index, position.x);
  428. set_point_value(point_index, position.y);
  429. return true;
  430. } else if (property == "left_tangent") {
  431. set_point_left_tangent(point_index, p_value);
  432. return true;
  433. } else if (property == "left_mode") {
  434. int mode = p_value;
  435. set_point_left_mode(point_index, (TangentMode)mode);
  436. return true;
  437. } else if (property == "right_tangent") {
  438. set_point_right_tangent(point_index, p_value);
  439. return true;
  440. } else if (property == "right_mode") {
  441. int mode = p_value;
  442. set_point_right_mode(point_index, (TangentMode)mode);
  443. return true;
  444. }
  445. }
  446. return false;
  447. }
  448. bool Curve::_get(const StringName &p_name, Variant &r_ret) const {
  449. Vector<String> components = String(p_name).split("/", true, 2);
  450. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  451. int point_index = components[0].trim_prefix("point_").to_int();
  452. String property = components[1];
  453. if (property == "position") {
  454. r_ret = get_point_position(point_index);
  455. return true;
  456. } else if (property == "left_tangent") {
  457. r_ret = get_point_left_tangent(point_index);
  458. return true;
  459. } else if (property == "left_mode") {
  460. r_ret = get_point_left_mode(point_index);
  461. return true;
  462. } else if (property == "right_tangent") {
  463. r_ret = get_point_right_tangent(point_index);
  464. return true;
  465. } else if (property == "right_mode") {
  466. r_ret = get_point_right_mode(point_index);
  467. return true;
  468. }
  469. }
  470. return false;
  471. }
  472. void Curve::_get_property_list(List<PropertyInfo> *p_list) const {
  473. for (int i = 0; i < _points.size(); i++) {
  474. PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
  475. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  476. p_list->push_back(pi);
  477. if (i != 0) {
  478. pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/left_tangent", i));
  479. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  480. p_list->push_back(pi);
  481. pi = PropertyInfo(Variant::INT, vformat("point_%d/left_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
  482. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  483. p_list->push_back(pi);
  484. }
  485. if (i != _points.size() - 1) {
  486. pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/right_tangent", i));
  487. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  488. p_list->push_back(pi);
  489. pi = PropertyInfo(Variant::INT, vformat("point_%d/right_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
  490. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  491. p_list->push_back(pi);
  492. }
  493. }
  494. }
  495. void Curve::_bind_methods() {
  496. ClassDB::bind_method(D_METHOD("get_point_count"), &Curve::get_point_count);
  497. ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve::set_point_count);
  498. ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE));
  499. ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
  500. ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
  501. ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Curve::get_point_position);
  502. ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value);
  503. ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_offset);
  504. ClassDB::bind_method(D_METHOD("sample", "offset"), &Curve::sample);
  505. ClassDB::bind_method(D_METHOD("sample_baked", "offset"), &Curve::sample_baked);
  506. ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent);
  507. ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_right_tangent);
  508. ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode);
  509. ClassDB::bind_method(D_METHOD("get_point_right_mode", "index"), &Curve::get_point_right_mode);
  510. ClassDB::bind_method(D_METHOD("set_point_left_tangent", "index", "tangent"), &Curve::set_point_left_tangent);
  511. ClassDB::bind_method(D_METHOD("set_point_right_tangent", "index", "tangent"), &Curve::set_point_right_tangent);
  512. ClassDB::bind_method(D_METHOD("set_point_left_mode", "index", "mode"), &Curve::set_point_left_mode);
  513. ClassDB::bind_method(D_METHOD("set_point_right_mode", "index", "mode"), &Curve::set_point_right_mode);
  514. ClassDB::bind_method(D_METHOD("get_min_value"), &Curve::get_min_value);
  515. ClassDB::bind_method(D_METHOD("set_min_value", "min"), &Curve::set_min_value);
  516. ClassDB::bind_method(D_METHOD("get_max_value"), &Curve::get_max_value);
  517. ClassDB::bind_method(D_METHOD("set_max_value", "max"), &Curve::set_max_value);
  518. ClassDB::bind_method(D_METHOD("clean_dupes"), &Curve::clean_dupes);
  519. ClassDB::bind_method(D_METHOD("bake"), &Curve::bake);
  520. ClassDB::bind_method(D_METHOD("get_bake_resolution"), &Curve::get_bake_resolution);
  521. ClassDB::bind_method(D_METHOD("set_bake_resolution", "resolution"), &Curve::set_bake_resolution);
  522. ClassDB::bind_method(D_METHOD("_get_data"), &Curve::get_data);
  523. ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve::set_data);
  524. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_min_value", "get_min_value");
  525. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
  526. ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
  527. ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
  528. ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
  529. ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
  530. BIND_ENUM_CONSTANT(TANGENT_FREE);
  531. BIND_ENUM_CONSTANT(TANGENT_LINEAR);
  532. BIND_ENUM_CONSTANT(TANGENT_MODE_COUNT);
  533. }
  534. int Curve2D::get_point_count() const {
  535. return points.size();
  536. }
  537. void Curve2D::set_point_count(int p_count) {
  538. ERR_FAIL_COND(p_count < 0);
  539. if (points.size() >= p_count) {
  540. points.resize(p_count);
  541. mark_dirty();
  542. } else {
  543. for (int i = p_count - points.size(); i > 0; i--) {
  544. _add_point(Vector2());
  545. }
  546. }
  547. notify_property_list_changed();
  548. }
  549. void Curve2D::_add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
  550. Point n;
  551. n.position = p_position;
  552. n.in = p_in;
  553. n.out = p_out;
  554. if (p_atpos >= 0 && p_atpos < points.size()) {
  555. points.insert(p_atpos, n);
  556. } else {
  557. points.push_back(n);
  558. }
  559. mark_dirty();
  560. }
  561. void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
  562. _add_point(p_position, p_in, p_out, p_atpos);
  563. notify_property_list_changed();
  564. }
  565. void Curve2D::set_point_position(int p_index, const Vector2 &p_position) {
  566. ERR_FAIL_INDEX(p_index, points.size());
  567. points.write[p_index].position = p_position;
  568. mark_dirty();
  569. }
  570. Vector2 Curve2D::get_point_position(int p_index) const {
  571. ERR_FAIL_INDEX_V(p_index, points.size(), Vector2());
  572. return points[p_index].position;
  573. }
  574. void Curve2D::set_point_in(int p_index, const Vector2 &p_in) {
  575. ERR_FAIL_INDEX(p_index, points.size());
  576. points.write[p_index].in = p_in;
  577. mark_dirty();
  578. }
  579. Vector2 Curve2D::get_point_in(int p_index) const {
  580. ERR_FAIL_INDEX_V(p_index, points.size(), Vector2());
  581. return points[p_index].in;
  582. }
  583. void Curve2D::set_point_out(int p_index, const Vector2 &p_out) {
  584. ERR_FAIL_INDEX(p_index, points.size());
  585. points.write[p_index].out = p_out;
  586. mark_dirty();
  587. }
  588. Vector2 Curve2D::get_point_out(int p_index) const {
  589. ERR_FAIL_INDEX_V(p_index, points.size(), Vector2());
  590. return points[p_index].out;
  591. }
  592. void Curve2D::_remove_point(int p_index) {
  593. ERR_FAIL_INDEX(p_index, points.size());
  594. points.remove_at(p_index);
  595. mark_dirty();
  596. }
  597. void Curve2D::remove_point(int p_index) {
  598. _remove_point(p_index);
  599. notify_property_list_changed();
  600. }
  601. void Curve2D::clear_points() {
  602. if (!points.is_empty()) {
  603. points.clear();
  604. mark_dirty();
  605. notify_property_list_changed();
  606. }
  607. }
  608. Vector2 Curve2D::sample(int p_index, const real_t p_offset) const {
  609. int pc = points.size();
  610. ERR_FAIL_COND_V(pc == 0, Vector2());
  611. if (p_index >= pc - 1) {
  612. return points[pc - 1].position;
  613. } else if (p_index < 0) {
  614. return points[0].position;
  615. }
  616. Vector2 p0 = points[p_index].position;
  617. Vector2 p1 = p0 + points[p_index].out;
  618. Vector2 p3 = points[p_index + 1].position;
  619. Vector2 p2 = p3 + points[p_index + 1].in;
  620. return p0.bezier_interpolate(p1, p2, p3, p_offset);
  621. }
  622. Vector2 Curve2D::samplef(real_t p_findex) const {
  623. if (p_findex < 0) {
  624. p_findex = 0;
  625. } else if (p_findex >= points.size()) {
  626. p_findex = points.size();
  627. }
  628. return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
  629. }
  630. void Curve2D::mark_dirty() {
  631. baked_cache_dirty = true;
  632. emit_signal(CoreStringNames::get_singleton()->changed);
  633. }
  634. void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
  635. real_t mp = p_begin + (p_end - p_begin) * 0.5;
  636. Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
  637. Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
  638. Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
  639. Vector2 na = (mid - beg).normalized();
  640. Vector2 nb = (end - mid).normalized();
  641. real_t dp = na.dot(nb);
  642. if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
  643. r_bake[mp] = mid;
  644. }
  645. if (p_depth < p_max_depth) {
  646. _bake_segment2d(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol);
  647. _bake_segment2d(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol);
  648. }
  649. }
  650. void Curve2D::_bake_segment2d_even_length(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_length) const {
  651. Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
  652. Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
  653. real_t length = beg.distance_to(end);
  654. if (length > p_length && p_depth < p_max_depth) {
  655. real_t mp = (p_begin + p_end) * 0.5;
  656. Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
  657. r_bake[mp] = mid;
  658. _bake_segment2d_even_length(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
  659. _bake_segment2d_even_length(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
  660. }
  661. }
  662. Vector2 Curve2D::_calculate_tangent(const Vector2 &p_begin, const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) {
  663. // Handle corner cases.
  664. if (Math::is_zero_approx(p_t - 0.0f) && p_control_1.is_equal_approx(p_begin)) {
  665. return (p_end - p_begin).normalized();
  666. }
  667. if (Math::is_zero_approx(p_t - 1.0f) && p_control_2.is_equal_approx(p_end)) {
  668. return (p_end - p_begin).normalized();
  669. }
  670. return p_begin.bezier_derivative(p_control_1, p_control_2, p_end, p_t).normalized();
  671. }
  672. void Curve2D::_bake() const {
  673. if (!baked_cache_dirty) {
  674. return;
  675. }
  676. baked_max_ofs = 0;
  677. baked_cache_dirty = false;
  678. if (points.size() == 0) {
  679. baked_point_cache.clear();
  680. baked_dist_cache.clear();
  681. baked_forward_vector_cache.clear();
  682. return;
  683. }
  684. if (points.size() == 1) {
  685. baked_point_cache.resize(1);
  686. baked_point_cache.set(0, points[0].position);
  687. baked_dist_cache.resize(1);
  688. baked_dist_cache.set(0, 0.0);
  689. baked_forward_vector_cache.resize(1);
  690. baked_forward_vector_cache.set(0, Vector2(0.0, 0.1));
  691. return;
  692. }
  693. // Tessellate curve to (almost) even length segments
  694. {
  695. Vector<RBMap<real_t, Vector2>> midpoints = _tessellate_even_length(10, bake_interval);
  696. int pc = 1;
  697. for (int i = 0; i < points.size() - 1; i++) {
  698. pc++;
  699. pc += midpoints[i].size();
  700. }
  701. baked_point_cache.resize(pc);
  702. baked_dist_cache.resize(pc);
  703. baked_forward_vector_cache.resize(pc);
  704. Vector2 *bpw = baked_point_cache.ptrw();
  705. Vector2 *bfw = baked_forward_vector_cache.ptrw();
  706. // Collect positions and sample tilts and tangents for each baked points.
  707. bpw[0] = points[0].position;
  708. bfw[0] = _calculate_tangent(points[0].position, points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0);
  709. int pidx = 0;
  710. for (int i = 0; i < points.size() - 1; i++) {
  711. for (const KeyValue<real_t, Vector2> &E : midpoints[i]) {
  712. pidx++;
  713. bpw[pidx] = E.value;
  714. bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
  715. }
  716. pidx++;
  717. bpw[pidx] = points[i + 1].position;
  718. bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
  719. }
  720. // Recalculate the baked distances.
  721. real_t *bdw = baked_dist_cache.ptrw();
  722. bdw[0] = 0.0;
  723. for (int i = 0; i < pc - 1; i++) {
  724. bdw[i + 1] = bdw[i] + bpw[i].distance_to(bpw[i + 1]);
  725. }
  726. baked_max_ofs = bdw[pc - 1];
  727. }
  728. }
  729. real_t Curve2D::get_baked_length() const {
  730. if (baked_cache_dirty) {
  731. _bake();
  732. }
  733. return baked_max_ofs;
  734. }
  735. Curve2D::Interval Curve2D::_find_interval(real_t p_offset) const {
  736. Interval interval = {
  737. -1,
  738. 0.0
  739. };
  740. ERR_FAIL_COND_V_MSG(baked_cache_dirty, interval, "Backed cache is dirty");
  741. int pc = baked_point_cache.size();
  742. ERR_FAIL_COND_V_MSG(pc < 2, interval, "Less than two points in cache");
  743. int start = 0;
  744. int end = pc;
  745. int idx = (end + start) / 2;
  746. // Binary search to find baked points.
  747. while (start < idx) {
  748. real_t offset = baked_dist_cache[idx];
  749. if (p_offset <= offset) {
  750. end = idx;
  751. } else {
  752. start = idx;
  753. }
  754. idx = (end + start) / 2;
  755. }
  756. real_t offset_begin = baked_dist_cache[idx];
  757. real_t offset_end = baked_dist_cache[idx + 1];
  758. real_t idx_interval = offset_end - offset_begin;
  759. ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, interval, "Offset out of range.");
  760. interval.idx = idx;
  761. if (idx_interval < FLT_EPSILON) {
  762. interval.frac = 0.5; // For a very short interval, 0.5 is a reasonable choice.
  763. ERR_FAIL_V_MSG(interval, "Zero length interval.");
  764. }
  765. interval.frac = (p_offset - offset_begin) / idx_interval;
  766. return interval;
  767. }
  768. Vector2 Curve2D::_sample_baked(Interval p_interval, bool p_cubic) const {
  769. // Assuming p_interval is valid.
  770. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Vector2(), "Invalid interval");
  771. int idx = p_interval.idx;
  772. real_t frac = p_interval.frac;
  773. const Vector2 *r = baked_point_cache.ptr();
  774. int pc = baked_point_cache.size();
  775. if (p_cubic) {
  776. Vector2 pre = idx > 0 ? r[idx - 1] : r[idx];
  777. Vector2 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
  778. return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
  779. } else {
  780. return r[idx].lerp(r[idx + 1], frac);
  781. }
  782. }
  783. Transform2D Curve2D::_sample_posture(Interval p_interval) const {
  784. // Assuming that p_interval is valid.
  785. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Transform2D(), "Invalid interval");
  786. int idx = p_interval.idx;
  787. real_t frac = p_interval.frac;
  788. Vector2 forward_begin = baked_forward_vector_cache[idx];
  789. Vector2 forward_end = baked_forward_vector_cache[idx + 1];
  790. // Build frames at both ends of the interval, then interpolate.
  791. const Vector2 forward = forward_begin.slerp(forward_end, frac).normalized();
  792. const Vector2 side = Vector2(-forward.y, forward.x);
  793. return Transform2D(side, forward, Vector2(0.0, 0.0));
  794. }
  795. Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
  796. if (baked_cache_dirty) {
  797. _bake();
  798. }
  799. // Validate: Curve may not have baked points.
  800. int pc = baked_point_cache.size();
  801. ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
  802. if (pc == 1) {
  803. return baked_point_cache[0];
  804. }
  805. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic.
  806. Curve2D::Interval interval = _find_interval(p_offset);
  807. return _sample_baked(interval, p_cubic);
  808. }
  809. Transform2D Curve2D::sample_baked_with_rotation(real_t p_offset, bool p_cubic) const {
  810. if (baked_cache_dirty) {
  811. _bake();
  812. }
  813. // Validate: Curve may not have baked points.
  814. const int point_count = baked_point_cache.size();
  815. ERR_FAIL_COND_V_MSG(point_count == 0, Transform2D(), "No points in Curve3D.");
  816. if (point_count == 1) {
  817. Transform2D t;
  818. t.set_origin(baked_point_cache.get(0));
  819. ERR_FAIL_V_MSG(t, "Only 1 point in Curve2D.");
  820. }
  821. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic.
  822. // 0. Find interval for all sampling steps.
  823. Curve2D::Interval interval = _find_interval(p_offset);
  824. // 1. Sample position.
  825. Vector2 pos = _sample_baked(interval, p_cubic);
  826. // 2. Sample rotation frame.
  827. Transform2D frame = _sample_posture(interval);
  828. frame.set_origin(pos);
  829. return frame;
  830. }
  831. PackedVector2Array Curve2D::get_baked_points() const {
  832. if (baked_cache_dirty) {
  833. _bake();
  834. }
  835. return baked_point_cache;
  836. }
  837. void Curve2D::set_bake_interval(real_t p_tolerance) {
  838. bake_interval = p_tolerance;
  839. mark_dirty();
  840. }
  841. real_t Curve2D::get_bake_interval() const {
  842. return bake_interval;
  843. }
  844. Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
  845. // Brute force method.
  846. if (baked_cache_dirty) {
  847. _bake();
  848. }
  849. // Validate: Curve may not have baked points.
  850. int pc = baked_point_cache.size();
  851. ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
  852. if (pc == 1) {
  853. return baked_point_cache.get(0);
  854. }
  855. const Vector2 *r = baked_point_cache.ptr();
  856. Vector2 nearest;
  857. real_t nearest_dist = -1.0f;
  858. for (int i = 0; i < pc - 1; i++) {
  859. const real_t interval = baked_dist_cache[i + 1] - baked_dist_cache[i];
  860. Vector2 origin = r[i];
  861. Vector2 direction = (r[i + 1] - origin) / interval;
  862. real_t d = CLAMP((p_to_point - origin).dot(direction), 0.0f, interval);
  863. Vector2 proj = origin + direction * d;
  864. real_t dist = proj.distance_squared_to(p_to_point);
  865. if (nearest_dist < 0.0f || dist < nearest_dist) {
  866. nearest = proj;
  867. nearest_dist = dist;
  868. }
  869. }
  870. return nearest;
  871. }
  872. real_t Curve2D::get_closest_offset(const Vector2 &p_to_point) const {
  873. // Brute force method.
  874. if (baked_cache_dirty) {
  875. _bake();
  876. }
  877. // Validate: Curve may not have baked points.
  878. int pc = baked_point_cache.size();
  879. ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve2D.");
  880. if (pc == 1) {
  881. return 0.0f;
  882. }
  883. const Vector2 *r = baked_point_cache.ptr();
  884. real_t nearest = 0.0f;
  885. real_t nearest_dist = -1.0f;
  886. real_t offset = 0.0f;
  887. for (int i = 0; i < pc - 1; i++) {
  888. offset = baked_dist_cache[i];
  889. const real_t interval = baked_dist_cache[i + 1] - baked_dist_cache[i];
  890. Vector2 origin = r[i];
  891. Vector2 direction = (r[i + 1] - origin) / interval;
  892. real_t d = CLAMP((p_to_point - origin).dot(direction), 0.0f, interval);
  893. Vector2 proj = origin + direction * d;
  894. real_t dist = proj.distance_squared_to(p_to_point);
  895. if (nearest_dist < 0.0f || dist < nearest_dist) {
  896. nearest = offset + d;
  897. nearest_dist = dist;
  898. }
  899. }
  900. return nearest;
  901. }
  902. Dictionary Curve2D::_get_data() const {
  903. Dictionary dc;
  904. PackedVector2Array d;
  905. d.resize(points.size() * 3);
  906. Vector2 *w = d.ptrw();
  907. for (int i = 0; i < points.size(); i++) {
  908. w[i * 3 + 0] = points[i].in;
  909. w[i * 3 + 1] = points[i].out;
  910. w[i * 3 + 2] = points[i].position;
  911. }
  912. dc["points"] = d;
  913. return dc;
  914. }
  915. void Curve2D::_set_data(const Dictionary &p_data) {
  916. ERR_FAIL_COND(!p_data.has("points"));
  917. PackedVector2Array rp = p_data["points"];
  918. int pc = rp.size();
  919. ERR_FAIL_COND(pc % 3 != 0);
  920. points.resize(pc / 3);
  921. const Vector2 *r = rp.ptr();
  922. for (int i = 0; i < points.size(); i++) {
  923. points.write[i].in = r[i * 3 + 0];
  924. points.write[i].out = r[i * 3 + 1];
  925. points.write[i].position = r[i * 3 + 2];
  926. }
  927. mark_dirty();
  928. notify_property_list_changed();
  929. }
  930. PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) const {
  931. PackedVector2Array tess;
  932. if (points.size() == 0) {
  933. return tess;
  934. }
  935. // The current implementation requires a sorted map.
  936. Vector<RBMap<real_t, Vector2>> midpoints;
  937. midpoints.resize(points.size() - 1);
  938. int pc = 1;
  939. for (int i = 0; i < points.size() - 1; i++) {
  940. _bake_segment2d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
  941. pc++;
  942. pc += midpoints[i].size();
  943. }
  944. tess.resize(pc);
  945. Vector2 *bpw = tess.ptrw();
  946. bpw[0] = points[0].position;
  947. int pidx = 0;
  948. for (int i = 0; i < points.size() - 1; i++) {
  949. for (const KeyValue<real_t, Vector2> &E : midpoints[i]) {
  950. pidx++;
  951. bpw[pidx] = E.value;
  952. }
  953. pidx++;
  954. bpw[pidx] = points[i + 1].position;
  955. }
  956. return tess;
  957. }
  958. Vector<RBMap<real_t, Vector2>> Curve2D::_tessellate_even_length(int p_max_stages, real_t p_length) const {
  959. Vector<RBMap<real_t, Vector2>> midpoints;
  960. ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
  961. midpoints.resize(points.size() - 1);
  962. for (int i = 0; i < points.size() - 1; i++) {
  963. _bake_segment2d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
  964. }
  965. return midpoints;
  966. }
  967. PackedVector2Array Curve2D::tessellate_even_length(int p_max_stages, real_t p_length) const {
  968. PackedVector2Array tess;
  969. Vector<RBMap<real_t, Vector2>> midpoints = _tessellate_even_length(p_max_stages, p_length);
  970. if (midpoints.size() == 0) {
  971. return tess;
  972. }
  973. int pc = 1;
  974. for (int i = 0; i < points.size() - 1; i++) {
  975. pc++;
  976. pc += midpoints[i].size();
  977. }
  978. tess.resize(pc);
  979. Vector2 *bpw = tess.ptrw();
  980. bpw[0] = points[0].position;
  981. int pidx = 0;
  982. for (int i = 0; i < points.size() - 1; i++) {
  983. for (const KeyValue<real_t, Vector2> &E : midpoints[i]) {
  984. pidx++;
  985. bpw[pidx] = E.value;
  986. }
  987. pidx++;
  988. bpw[pidx] = points[i + 1].position;
  989. }
  990. return tess;
  991. }
  992. bool Curve2D::_set(const StringName &p_name, const Variant &p_value) {
  993. Vector<String> components = String(p_name).split("/", true, 2);
  994. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  995. int point_index = components[0].trim_prefix("point_").to_int();
  996. String property = components[1];
  997. if (property == "position") {
  998. set_point_position(point_index, p_value);
  999. return true;
  1000. } else if (property == "in") {
  1001. set_point_in(point_index, p_value);
  1002. return true;
  1003. } else if (property == "out") {
  1004. set_point_out(point_index, p_value);
  1005. return true;
  1006. }
  1007. }
  1008. return false;
  1009. }
  1010. bool Curve2D::_get(const StringName &p_name, Variant &r_ret) const {
  1011. Vector<String> components = String(p_name).split("/", true, 2);
  1012. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  1013. int point_index = components[0].trim_prefix("point_").to_int();
  1014. String property = components[1];
  1015. if (property == "position") {
  1016. r_ret = get_point_position(point_index);
  1017. return true;
  1018. } else if (property == "in") {
  1019. r_ret = get_point_in(point_index);
  1020. return true;
  1021. } else if (property == "out") {
  1022. r_ret = get_point_out(point_index);
  1023. return true;
  1024. }
  1025. }
  1026. return false;
  1027. }
  1028. void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
  1029. for (int i = 0; i < points.size(); i++) {
  1030. PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
  1031. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1032. p_list->push_back(pi);
  1033. if (i != 0) {
  1034. pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/in", i));
  1035. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1036. p_list->push_back(pi);
  1037. }
  1038. if (i != points.size() - 1) {
  1039. pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/out", i));
  1040. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1041. p_list->push_back(pi);
  1042. }
  1043. }
  1044. }
  1045. void Curve2D::_bind_methods() {
  1046. ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
  1047. ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
  1048. ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
  1049. ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
  1050. ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
  1051. ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve2D::set_point_in);
  1052. ClassDB::bind_method(D_METHOD("get_point_in", "idx"), &Curve2D::get_point_in);
  1053. ClassDB::bind_method(D_METHOD("set_point_out", "idx", "position"), &Curve2D::set_point_out);
  1054. ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve2D::get_point_out);
  1055. ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve2D::remove_point);
  1056. ClassDB::bind_method(D_METHOD("clear_points"), &Curve2D::clear_points);
  1057. ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve2D::sample);
  1058. ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve2D::samplef);
  1059. //ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve2D::bake,DEFVAL(10));
  1060. ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve2D::set_bake_interval);
  1061. ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve2D::get_bake_interval);
  1062. ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
  1063. ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(0.0), DEFVAL(false));
  1064. ClassDB::bind_method(D_METHOD("sample_baked_with_rotation", "offset", "cubic"), &Curve2D::sample_baked_with_rotation, DEFVAL(0.0), DEFVAL(false));
  1065. ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points);
  1066. ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point);
  1067. ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset);
  1068. ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4));
  1069. ClassDB::bind_method(D_METHOD("tessellate_even_length", "max_stages", "tolerance_length"), &Curve2D::tessellate_even_length, DEFVAL(5), DEFVAL(20.0));
  1070. ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data);
  1071. ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve2D::_set_data);
  1072. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
  1073. ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
  1074. ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
  1075. }
  1076. Curve2D::Curve2D() {}
  1077. /***********************************************************************************/
  1078. /***********************************************************************************/
  1079. /***********************************************************************************/
  1080. /***********************************************************************************/
  1081. /***********************************************************************************/
  1082. /***********************************************************************************/
  1083. int Curve3D::get_point_count() const {
  1084. return points.size();
  1085. }
  1086. void Curve3D::set_point_count(int p_count) {
  1087. ERR_FAIL_COND(p_count < 0);
  1088. if (points.size() >= p_count) {
  1089. points.resize(p_count);
  1090. mark_dirty();
  1091. } else {
  1092. for (int i = p_count - points.size(); i > 0; i--) {
  1093. _add_point(Vector3());
  1094. }
  1095. }
  1096. notify_property_list_changed();
  1097. }
  1098. void Curve3D::_add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
  1099. Point n;
  1100. n.position = p_position;
  1101. n.in = p_in;
  1102. n.out = p_out;
  1103. if (p_atpos >= 0 && p_atpos < points.size()) {
  1104. points.insert(p_atpos, n);
  1105. } else {
  1106. points.push_back(n);
  1107. }
  1108. mark_dirty();
  1109. }
  1110. void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
  1111. _add_point(p_position, p_in, p_out, p_atpos);
  1112. notify_property_list_changed();
  1113. }
  1114. void Curve3D::set_point_position(int p_index, const Vector3 &p_position) {
  1115. ERR_FAIL_INDEX(p_index, points.size());
  1116. points.write[p_index].position = p_position;
  1117. mark_dirty();
  1118. }
  1119. Vector3 Curve3D::get_point_position(int p_index) const {
  1120. ERR_FAIL_INDEX_V(p_index, points.size(), Vector3());
  1121. return points[p_index].position;
  1122. }
  1123. void Curve3D::set_point_tilt(int p_index, real_t p_tilt) {
  1124. ERR_FAIL_INDEX(p_index, points.size());
  1125. points.write[p_index].tilt = p_tilt;
  1126. mark_dirty();
  1127. }
  1128. real_t Curve3D::get_point_tilt(int p_index) const {
  1129. ERR_FAIL_INDEX_V(p_index, points.size(), 0);
  1130. return points[p_index].tilt;
  1131. }
  1132. void Curve3D::set_point_in(int p_index, const Vector3 &p_in) {
  1133. ERR_FAIL_INDEX(p_index, points.size());
  1134. points.write[p_index].in = p_in;
  1135. mark_dirty();
  1136. }
  1137. Vector3 Curve3D::get_point_in(int p_index) const {
  1138. ERR_FAIL_INDEX_V(p_index, points.size(), Vector3());
  1139. return points[p_index].in;
  1140. }
  1141. void Curve3D::set_point_out(int p_index, const Vector3 &p_out) {
  1142. ERR_FAIL_INDEX(p_index, points.size());
  1143. points.write[p_index].out = p_out;
  1144. mark_dirty();
  1145. }
  1146. Vector3 Curve3D::get_point_out(int p_index) const {
  1147. ERR_FAIL_INDEX_V(p_index, points.size(), Vector3());
  1148. return points[p_index].out;
  1149. }
  1150. void Curve3D::_remove_point(int p_index) {
  1151. ERR_FAIL_INDEX(p_index, points.size());
  1152. points.remove_at(p_index);
  1153. mark_dirty();
  1154. }
  1155. void Curve3D::remove_point(int p_index) {
  1156. _remove_point(p_index);
  1157. notify_property_list_changed();
  1158. }
  1159. void Curve3D::clear_points() {
  1160. if (!points.is_empty()) {
  1161. points.clear();
  1162. mark_dirty();
  1163. notify_property_list_changed();
  1164. }
  1165. }
  1166. Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
  1167. int pc = points.size();
  1168. ERR_FAIL_COND_V(pc == 0, Vector3());
  1169. if (p_index >= pc - 1) {
  1170. return points[pc - 1].position;
  1171. } else if (p_index < 0) {
  1172. return points[0].position;
  1173. }
  1174. Vector3 p0 = points[p_index].position;
  1175. Vector3 p1 = p0 + points[p_index].out;
  1176. Vector3 p3 = points[p_index + 1].position;
  1177. Vector3 p2 = p3 + points[p_index + 1].in;
  1178. return p0.bezier_interpolate(p1, p2, p3, p_offset);
  1179. }
  1180. Vector3 Curve3D::samplef(real_t p_findex) const {
  1181. if (p_findex < 0) {
  1182. p_findex = 0;
  1183. } else if (p_findex >= points.size()) {
  1184. p_findex = points.size();
  1185. }
  1186. return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
  1187. }
  1188. void Curve3D::mark_dirty() {
  1189. baked_cache_dirty = true;
  1190. emit_signal(CoreStringNames::get_singleton()->changed);
  1191. }
  1192. void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
  1193. real_t mp = p_begin + (p_end - p_begin) * 0.5;
  1194. Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
  1195. Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
  1196. Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
  1197. Vector3 na = (mid - beg).normalized();
  1198. Vector3 nb = (end - mid).normalized();
  1199. real_t dp = na.dot(nb);
  1200. if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
  1201. r_bake[mp] = mid;
  1202. }
  1203. if (p_depth < p_max_depth) {
  1204. _bake_segment3d(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol);
  1205. _bake_segment3d(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol);
  1206. }
  1207. }
  1208. void Curve3D::_bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const {
  1209. Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
  1210. Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
  1211. real_t length = beg.distance_to(end);
  1212. if (length > p_length && p_depth < p_max_depth) {
  1213. real_t mp = (p_begin + p_end) * 0.5;
  1214. Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
  1215. r_bake[mp] = mid;
  1216. _bake_segment3d_even_length(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
  1217. _bake_segment3d_even_length(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
  1218. }
  1219. }
  1220. Vector3 Curve3D::_calculate_tangent(const Vector3 &p_begin, const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) {
  1221. // Handle corner cases.
  1222. if (Math::is_zero_approx(p_t - 0.0f) && p_control_1.is_equal_approx(p_begin)) {
  1223. return (p_end - p_begin).normalized();
  1224. }
  1225. if (Math::is_zero_approx(p_t - 1.0f) && p_control_2.is_equal_approx(p_end)) {
  1226. return (p_end - p_begin).normalized();
  1227. }
  1228. return p_begin.bezier_derivative(p_control_1, p_control_2, p_end, p_t).normalized();
  1229. }
  1230. void Curve3D::_bake() const {
  1231. if (!baked_cache_dirty) {
  1232. return;
  1233. }
  1234. baked_max_ofs = 0;
  1235. baked_cache_dirty = false;
  1236. if (points.size() == 0) {
  1237. baked_point_cache.clear();
  1238. baked_tilt_cache.clear();
  1239. baked_dist_cache.clear();
  1240. baked_forward_vector_cache.clear();
  1241. baked_up_vector_cache.clear();
  1242. return;
  1243. }
  1244. if (points.size() == 1) {
  1245. baked_point_cache.resize(1);
  1246. baked_point_cache.set(0, points[0].position);
  1247. baked_tilt_cache.resize(1);
  1248. baked_tilt_cache.set(0, points[0].tilt);
  1249. baked_dist_cache.resize(1);
  1250. baked_dist_cache.set(0, 0.0);
  1251. baked_forward_vector_cache.resize(1);
  1252. baked_forward_vector_cache.set(0, Vector3(0.0, 0.0, 1.0));
  1253. if (up_vector_enabled) {
  1254. baked_up_vector_cache.resize(1);
  1255. baked_up_vector_cache.set(0, Vector3(0.0, 1.0, 0.0));
  1256. } else {
  1257. baked_up_vector_cache.clear();
  1258. }
  1259. return;
  1260. }
  1261. // Step 1: Tessellate curve to (almost) even length segments
  1262. {
  1263. Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
  1264. int pc = 1;
  1265. for (int i = 0; i < points.size() - 1; i++) {
  1266. pc++;
  1267. pc += midpoints[i].size();
  1268. }
  1269. baked_point_cache.resize(pc);
  1270. baked_tilt_cache.resize(pc);
  1271. baked_dist_cache.resize(pc);
  1272. baked_forward_vector_cache.resize(pc);
  1273. Vector3 *bpw = baked_point_cache.ptrw();
  1274. real_t *btw = baked_tilt_cache.ptrw();
  1275. Vector3 *bfw = baked_forward_vector_cache.ptrw();
  1276. // Collect positions and sample tilts and tangents for each baked points.
  1277. bpw[0] = points[0].position;
  1278. bfw[0] = _calculate_tangent(points[0].position, points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0);
  1279. btw[0] = points[0].tilt;
  1280. int pidx = 0;
  1281. for (int i = 0; i < points.size() - 1; i++) {
  1282. for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
  1283. pidx++;
  1284. bpw[pidx] = E.value;
  1285. bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
  1286. btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
  1287. }
  1288. pidx++;
  1289. bpw[pidx] = points[i + 1].position;
  1290. bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
  1291. btw[pidx] = points[i + 1].tilt;
  1292. }
  1293. // Recalculate the baked distances.
  1294. real_t *bdw = baked_dist_cache.ptrw();
  1295. bdw[0] = 0.0;
  1296. for (int i = 0; i < pc - 1; i++) {
  1297. bdw[i + 1] = bdw[i] + bpw[i].distance_to(bpw[i + 1]);
  1298. }
  1299. baked_max_ofs = bdw[pc - 1];
  1300. }
  1301. if (!up_vector_enabled) {
  1302. baked_up_vector_cache.resize(0);
  1303. return;
  1304. }
  1305. // Step 2: Calculate the up vectors and the whole local reference frame
  1306. //
  1307. // See Dougan, Carl. "The parallel transport frame." Game Programming Gems 2 (2001): 215-219.
  1308. // for an example discussing about why not the Frenet frame.
  1309. {
  1310. int point_count = baked_point_cache.size();
  1311. baked_up_vector_cache.resize(point_count);
  1312. Vector3 *up_write = baked_up_vector_cache.ptrw();
  1313. const Vector3 *forward_ptr = baked_forward_vector_cache.ptr();
  1314. const Vector3 *points_ptr = baked_point_cache.ptr();
  1315. Basis frame; // X-right, Y-up, Z-forward.
  1316. Basis frame_prev;
  1317. // Set the initial frame based on Y-up rule.
  1318. {
  1319. Vector3 forward = forward_ptr[0];
  1320. if (abs(forward.dot(Vector3(0, 1, 0))) > 1.0 - UNIT_EPSILON) {
  1321. frame_prev = Basis::looking_at(-forward, Vector3(1, 0, 0));
  1322. } else {
  1323. frame_prev = Basis::looking_at(-forward, Vector3(0, 1, 0));
  1324. }
  1325. up_write[0] = frame_prev.get_column(1);
  1326. }
  1327. // Calculate the Parallel Transport Frame.
  1328. for (int idx = 1; idx < point_count; idx++) {
  1329. Vector3 forward = forward_ptr[idx];
  1330. Basis rotate;
  1331. rotate.rotate_to_align(frame_prev.get_column(2), forward);
  1332. frame = rotate * frame_prev;
  1333. frame.orthonormalize(); // guard against float error accumulation
  1334. up_write[idx] = frame.get_column(1);
  1335. frame_prev = frame;
  1336. }
  1337. bool is_loop = true;
  1338. // Loop smoothing only applies when the curve is a loop, which means two ends meet, and share forward directions.
  1339. {
  1340. if (!points_ptr[0].is_equal_approx(points_ptr[point_count - 1])) {
  1341. is_loop = false;
  1342. }
  1343. real_t dot = forward_ptr[0].dot(forward_ptr[point_count - 1]);
  1344. if (dot < 1.0 - UNIT_EPSILON) { // Alignment should not be too tight, or it doesn't work for coarse bake interval.
  1345. is_loop = false;
  1346. }
  1347. }
  1348. // Twist up vectors, so that they align at two ends of the curve.
  1349. if (is_loop) {
  1350. const Vector3 up_start = up_write[0];
  1351. const Vector3 up_end = up_write[point_count - 1];
  1352. real_t sign = SIGN(up_end.cross(up_start).dot(forward_ptr[0]));
  1353. real_t full_angle = Quaternion(up_end, up_start).get_angle();
  1354. if (abs(full_angle) < CMP_EPSILON) {
  1355. return;
  1356. } else {
  1357. const real_t *dists = baked_dist_cache.ptr();
  1358. for (int idx = 1; idx < point_count; idx++) {
  1359. const real_t frac = dists[idx] / baked_max_ofs;
  1360. const real_t angle = Math::lerp((real_t)0.0, full_angle, frac);
  1361. Basis twist(forward_ptr[idx] * sign, angle);
  1362. up_write[idx] = twist.xform(up_write[idx]);
  1363. }
  1364. }
  1365. }
  1366. }
  1367. }
  1368. real_t Curve3D::get_baked_length() const {
  1369. if (baked_cache_dirty) {
  1370. _bake();
  1371. }
  1372. return baked_max_ofs;
  1373. }
  1374. Curve3D::Interval Curve3D::_find_interval(real_t p_offset) const {
  1375. Interval interval = {
  1376. -1,
  1377. 0.0
  1378. };
  1379. ERR_FAIL_COND_V_MSG(baked_cache_dirty, interval, "Backed cache is dirty");
  1380. int pc = baked_point_cache.size();
  1381. ERR_FAIL_COND_V_MSG(pc < 2, interval, "Less than two points in cache");
  1382. int start = 0;
  1383. int end = pc;
  1384. int idx = (end + start) / 2;
  1385. // Binary search to find baked points.
  1386. while (start < idx) {
  1387. real_t offset = baked_dist_cache[idx];
  1388. if (p_offset <= offset) {
  1389. end = idx;
  1390. } else {
  1391. start = idx;
  1392. }
  1393. idx = (end + start) / 2;
  1394. }
  1395. real_t offset_begin = baked_dist_cache[idx];
  1396. real_t offset_end = baked_dist_cache[idx + 1];
  1397. real_t idx_interval = offset_end - offset_begin;
  1398. ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, interval, "Offset out of range.");
  1399. interval.idx = idx;
  1400. if (idx_interval < FLT_EPSILON) {
  1401. interval.frac = 0.5; // For a very short interval, 0.5 is a reasonable choice.
  1402. ERR_FAIL_V_MSG(interval, "Zero length interval.");
  1403. }
  1404. interval.frac = (p_offset - offset_begin) / idx_interval;
  1405. return interval;
  1406. }
  1407. Vector3 Curve3D::_sample_baked(Interval p_interval, bool p_cubic) const {
  1408. // Assuming p_interval is valid.
  1409. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Vector3(), "Invalid interval");
  1410. int idx = p_interval.idx;
  1411. real_t frac = p_interval.frac;
  1412. const Vector3 *r = baked_point_cache.ptr();
  1413. int pc = baked_point_cache.size();
  1414. if (p_cubic) {
  1415. Vector3 pre = idx > 0 ? r[idx - 1] : r[idx];
  1416. Vector3 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
  1417. return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
  1418. } else {
  1419. return r[idx].lerp(r[idx + 1], frac);
  1420. }
  1421. }
  1422. real_t Curve3D::_sample_baked_tilt(Interval p_interval) const {
  1423. // Assuming that p_interval is valid.
  1424. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_tilt_cache.size(), 0.0, "Invalid interval");
  1425. int idx = p_interval.idx;
  1426. real_t frac = p_interval.frac;
  1427. const real_t *r = baked_tilt_cache.ptr();
  1428. return Math::lerp(r[idx], r[idx + 1], frac);
  1429. }
  1430. Basis Curve3D::_sample_posture(Interval p_interval, bool p_apply_tilt) const {
  1431. // Assuming that p_interval is valid.
  1432. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Basis(), "Invalid interval");
  1433. if (up_vector_enabled) {
  1434. ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_up_vector_cache.size(), Basis(), "Invalid interval");
  1435. }
  1436. int idx = p_interval.idx;
  1437. real_t frac = p_interval.frac;
  1438. Vector3 forward_begin = baked_forward_vector_cache[idx];
  1439. Vector3 forward_end = baked_forward_vector_cache[idx + 1];
  1440. Vector3 up_begin;
  1441. Vector3 up_end;
  1442. if (up_vector_enabled) {
  1443. up_begin = baked_up_vector_cache[idx];
  1444. up_end = baked_up_vector_cache[idx + 1];
  1445. } else {
  1446. up_begin = Vector3(0.0, 1.0, 0.0);
  1447. up_end = Vector3(0.0, 1.0, 0.0);
  1448. }
  1449. // Build frames at both ends of the interval, then interpolate.
  1450. const Basis frame_begin = Basis::looking_at(-forward_begin, up_begin);
  1451. const Basis frame_end = Basis::looking_at(-forward_end, up_end);
  1452. const Basis frame = frame_begin.slerp(frame_end, frac).orthonormalized();
  1453. if (!p_apply_tilt) {
  1454. return frame;
  1455. }
  1456. // Applying tilt.
  1457. const real_t tilt = _sample_baked_tilt(p_interval);
  1458. Vector3 forward = frame.get_column(2);
  1459. const Basis twist(forward, tilt);
  1460. return twist * frame;
  1461. }
  1462. Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
  1463. if (baked_cache_dirty) {
  1464. _bake();
  1465. }
  1466. // Validate: Curve may not have baked points.
  1467. int pc = baked_point_cache.size();
  1468. ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
  1469. if (pc == 1) {
  1470. return baked_point_cache[0];
  1471. }
  1472. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic.
  1473. Curve3D::Interval interval = _find_interval(p_offset);
  1474. return _sample_baked(interval, p_cubic);
  1475. }
  1476. Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_apply_tilt) const {
  1477. if (baked_cache_dirty) {
  1478. _bake();
  1479. }
  1480. // Validate: Curve may not have baked points.
  1481. const int point_count = baked_point_cache.size();
  1482. ERR_FAIL_COND_V_MSG(point_count == 0, Transform3D(), "No points in Curve3D.");
  1483. if (point_count == 1) {
  1484. Transform3D t;
  1485. t.origin = baked_point_cache.get(0);
  1486. ERR_FAIL_V_MSG(t, "Only 1 point in Curve3D.");
  1487. }
  1488. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic.
  1489. // 0. Find interval for all sampling steps.
  1490. Curve3D::Interval interval = _find_interval(p_offset);
  1491. // 1. Sample position.
  1492. Vector3 pos = _sample_baked(interval, p_cubic);
  1493. // 2. Sample rotation frame.
  1494. Basis frame = _sample_posture(interval, p_apply_tilt);
  1495. return Transform3D(frame, pos);
  1496. }
  1497. real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
  1498. if (baked_cache_dirty) {
  1499. _bake();
  1500. }
  1501. // Validate: Curve may not have baked tilts.
  1502. int pc = baked_tilt_cache.size();
  1503. ERR_FAIL_COND_V_MSG(pc == 0, 0, "No tilts in Curve3D.");
  1504. if (pc == 1) {
  1505. return baked_tilt_cache.get(0);
  1506. }
  1507. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic
  1508. Curve3D::Interval interval = _find_interval(p_offset);
  1509. return _sample_baked_tilt(interval);
  1510. }
  1511. Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
  1512. if (baked_cache_dirty) {
  1513. _bake();
  1514. }
  1515. // Validate: Curve may not have baked up vectors.
  1516. ERR_FAIL_COND_V_MSG(!up_vector_enabled, Vector3(0, 1, 0), "No up vectors in Curve3D.");
  1517. int count = baked_up_vector_cache.size();
  1518. if (count == 1) {
  1519. return baked_up_vector_cache.get(0);
  1520. }
  1521. p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic.
  1522. Curve3D::Interval interval = _find_interval(p_offset);
  1523. return _sample_posture(interval, p_apply_tilt).get_column(1);
  1524. }
  1525. PackedVector3Array Curve3D::get_baked_points() const {
  1526. if (baked_cache_dirty) {
  1527. _bake();
  1528. }
  1529. return baked_point_cache;
  1530. }
  1531. Vector<real_t> Curve3D::get_baked_tilts() const {
  1532. if (baked_cache_dirty) {
  1533. _bake();
  1534. }
  1535. return baked_tilt_cache;
  1536. }
  1537. PackedVector3Array Curve3D::get_baked_up_vectors() const {
  1538. if (baked_cache_dirty) {
  1539. _bake();
  1540. }
  1541. return baked_up_vector_cache;
  1542. }
  1543. Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
  1544. // Brute force method.
  1545. if (baked_cache_dirty) {
  1546. _bake();
  1547. }
  1548. // Validate: Curve may not have baked points.
  1549. int pc = baked_point_cache.size();
  1550. ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
  1551. if (pc == 1) {
  1552. return baked_point_cache.get(0);
  1553. }
  1554. const Vector3 *r = baked_point_cache.ptr();
  1555. Vector3 nearest;
  1556. real_t nearest_dist = -1.0f;
  1557. for (int i = 0; i < pc - 1; i++) {
  1558. const real_t interval = baked_dist_cache[i + 1] - baked_dist_cache[i];
  1559. Vector3 origin = r[i];
  1560. Vector3 direction = (r[i + 1] - origin) / interval;
  1561. real_t d = CLAMP((p_to_point - origin).dot(direction), 0.0f, interval);
  1562. Vector3 proj = origin + direction * d;
  1563. real_t dist = proj.distance_squared_to(p_to_point);
  1564. if (nearest_dist < 0.0f || dist < nearest_dist) {
  1565. nearest = proj;
  1566. nearest_dist = dist;
  1567. }
  1568. }
  1569. return nearest;
  1570. }
  1571. real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
  1572. // Brute force method.
  1573. if (baked_cache_dirty) {
  1574. _bake();
  1575. }
  1576. // Validate: Curve may not have baked points.
  1577. int pc = baked_point_cache.size();
  1578. ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve3D.");
  1579. if (pc == 1) {
  1580. return 0.0f;
  1581. }
  1582. const Vector3 *r = baked_point_cache.ptr();
  1583. real_t nearest = 0.0f;
  1584. real_t nearest_dist = -1.0f;
  1585. real_t offset;
  1586. for (int i = 0; i < pc - 1; i++) {
  1587. offset = baked_dist_cache[i];
  1588. const real_t interval = baked_dist_cache[i + 1] - baked_dist_cache[i];
  1589. Vector3 origin = r[i];
  1590. Vector3 direction = (r[i + 1] - origin) / interval;
  1591. real_t d = CLAMP((p_to_point - origin).dot(direction), 0.0f, interval);
  1592. Vector3 proj = origin + direction * d;
  1593. real_t dist = proj.distance_squared_to(p_to_point);
  1594. if (nearest_dist < 0.0f || dist < nearest_dist) {
  1595. nearest = offset + d;
  1596. nearest_dist = dist;
  1597. }
  1598. }
  1599. return nearest;
  1600. }
  1601. void Curve3D::set_bake_interval(real_t p_tolerance) {
  1602. bake_interval = p_tolerance;
  1603. mark_dirty();
  1604. }
  1605. real_t Curve3D::get_bake_interval() const {
  1606. return bake_interval;
  1607. }
  1608. void Curve3D::set_up_vector_enabled(bool p_enable) {
  1609. up_vector_enabled = p_enable;
  1610. mark_dirty();
  1611. }
  1612. bool Curve3D::is_up_vector_enabled() const {
  1613. return up_vector_enabled;
  1614. }
  1615. Dictionary Curve3D::_get_data() const {
  1616. Dictionary dc;
  1617. PackedVector3Array d;
  1618. d.resize(points.size() * 3);
  1619. Vector3 *w = d.ptrw();
  1620. Vector<real_t> t;
  1621. t.resize(points.size());
  1622. real_t *wt = t.ptrw();
  1623. for (int i = 0; i < points.size(); i++) {
  1624. w[i * 3 + 0] = points[i].in;
  1625. w[i * 3 + 1] = points[i].out;
  1626. w[i * 3 + 2] = points[i].position;
  1627. wt[i] = points[i].tilt;
  1628. }
  1629. dc["points"] = d;
  1630. dc["tilts"] = t;
  1631. return dc;
  1632. }
  1633. void Curve3D::_set_data(const Dictionary &p_data) {
  1634. ERR_FAIL_COND(!p_data.has("points"));
  1635. ERR_FAIL_COND(!p_data.has("tilts"));
  1636. PackedVector3Array rp = p_data["points"];
  1637. int pc = rp.size();
  1638. ERR_FAIL_COND(pc % 3 != 0);
  1639. points.resize(pc / 3);
  1640. const Vector3 *r = rp.ptr();
  1641. Vector<real_t> rtl = p_data["tilts"];
  1642. const real_t *rt = rtl.ptr();
  1643. for (int i = 0; i < points.size(); i++) {
  1644. points.write[i].in = r[i * 3 + 0];
  1645. points.write[i].out = r[i * 3 + 1];
  1646. points.write[i].position = r[i * 3 + 2];
  1647. points.write[i].tilt = rt[i];
  1648. }
  1649. mark_dirty();
  1650. notify_property_list_changed();
  1651. }
  1652. PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) const {
  1653. PackedVector3Array tess;
  1654. if (points.size() == 0) {
  1655. return tess;
  1656. }
  1657. Vector<RBMap<real_t, Vector3>> midpoints;
  1658. midpoints.resize(points.size() - 1);
  1659. int pc = 1;
  1660. for (int i = 0; i < points.size() - 1; i++) {
  1661. _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
  1662. pc++;
  1663. pc += midpoints[i].size();
  1664. }
  1665. tess.resize(pc);
  1666. Vector3 *bpw = tess.ptrw();
  1667. bpw[0] = points[0].position;
  1668. int pidx = 0;
  1669. for (int i = 0; i < points.size() - 1; i++) {
  1670. for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
  1671. pidx++;
  1672. bpw[pidx] = E.value;
  1673. }
  1674. pidx++;
  1675. bpw[pidx] = points[i + 1].position;
  1676. }
  1677. return tess;
  1678. }
  1679. Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages, real_t p_length) const {
  1680. Vector<RBMap<real_t, Vector3>> midpoints;
  1681. ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
  1682. midpoints.resize(points.size() - 1);
  1683. for (int i = 0; i < points.size() - 1; i++) {
  1684. _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
  1685. }
  1686. return midpoints;
  1687. }
  1688. PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_length) const {
  1689. PackedVector3Array tess;
  1690. Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(p_max_stages, p_length);
  1691. if (midpoints.size() == 0) {
  1692. return tess;
  1693. }
  1694. int pc = 1;
  1695. for (int i = 0; i < points.size() - 1; i++) {
  1696. pc++;
  1697. pc += midpoints[i].size();
  1698. }
  1699. tess.resize(pc);
  1700. Vector3 *bpw = tess.ptrw();
  1701. bpw[0] = points[0].position;
  1702. int pidx = 0;
  1703. for (int i = 0; i < points.size() - 1; i++) {
  1704. for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
  1705. pidx++;
  1706. bpw[pidx] = E.value;
  1707. }
  1708. pidx++;
  1709. bpw[pidx] = points[i + 1].position;
  1710. }
  1711. return tess;
  1712. }
  1713. bool Curve3D::_set(const StringName &p_name, const Variant &p_value) {
  1714. Vector<String> components = String(p_name).split("/", true, 2);
  1715. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  1716. int point_index = components[0].trim_prefix("point_").to_int();
  1717. String property = components[1];
  1718. if (property == "position") {
  1719. set_point_position(point_index, p_value);
  1720. return true;
  1721. } else if (property == "in") {
  1722. set_point_in(point_index, p_value);
  1723. return true;
  1724. } else if (property == "out") {
  1725. set_point_out(point_index, p_value);
  1726. return true;
  1727. } else if (property == "tilt") {
  1728. set_point_tilt(point_index, p_value);
  1729. return true;
  1730. }
  1731. }
  1732. return false;
  1733. }
  1734. bool Curve3D::_get(const StringName &p_name, Variant &r_ret) const {
  1735. Vector<String> components = String(p_name).split("/", true, 2);
  1736. if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
  1737. int point_index = components[0].trim_prefix("point_").to_int();
  1738. String property = components[1];
  1739. if (property == "position") {
  1740. r_ret = get_point_position(point_index);
  1741. return true;
  1742. } else if (property == "in") {
  1743. r_ret = get_point_in(point_index);
  1744. return true;
  1745. } else if (property == "out") {
  1746. r_ret = get_point_out(point_index);
  1747. return true;
  1748. } else if (property == "tilt") {
  1749. r_ret = get_point_tilt(point_index);
  1750. return true;
  1751. }
  1752. }
  1753. return false;
  1754. }
  1755. void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
  1756. for (int i = 0; i < points.size(); i++) {
  1757. PropertyInfo pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/position", i));
  1758. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1759. p_list->push_back(pi);
  1760. if (i != 0) {
  1761. pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
  1762. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1763. p_list->push_back(pi);
  1764. }
  1765. if (i != points.size() - 1) {
  1766. pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
  1767. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1768. p_list->push_back(pi);
  1769. }
  1770. pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/tilt", i));
  1771. pi.usage &= ~PROPERTY_USAGE_STORAGE;
  1772. p_list->push_back(pi);
  1773. }
  1774. }
  1775. void Curve3D::_bind_methods() {
  1776. ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
  1777. ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
  1778. ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
  1779. ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
  1780. ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
  1781. ClassDB::bind_method(D_METHOD("set_point_tilt", "idx", "tilt"), &Curve3D::set_point_tilt);
  1782. ClassDB::bind_method(D_METHOD("get_point_tilt", "idx"), &Curve3D::get_point_tilt);
  1783. ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve3D::set_point_in);
  1784. ClassDB::bind_method(D_METHOD("get_point_in", "idx"), &Curve3D::get_point_in);
  1785. ClassDB::bind_method(D_METHOD("set_point_out", "idx", "position"), &Curve3D::set_point_out);
  1786. ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve3D::get_point_out);
  1787. ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve3D::remove_point);
  1788. ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
  1789. ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
  1790. ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
  1791. //ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
  1792. ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
  1793. ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
  1794. ClassDB::bind_method(D_METHOD("set_up_vector_enabled", "enable"), &Curve3D::set_up_vector_enabled);
  1795. ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled);
  1796. ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length);
  1797. ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve3D::sample_baked, DEFVAL(0.0), DEFVAL(false));
  1798. ClassDB::bind_method(D_METHOD("sample_baked_with_rotation", "offset", "cubic", "apply_tilt"), &Curve3D::sample_baked_with_rotation, DEFVAL(0.0), DEFVAL(false), DEFVAL(false));
  1799. ClassDB::bind_method(D_METHOD("sample_baked_up_vector", "offset", "apply_tilt"), &Curve3D::sample_baked_up_vector, DEFVAL(false));
  1800. ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points);
  1801. ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
  1802. ClassDB::bind_method(D_METHOD("get_baked_up_vectors"), &Curve3D::get_baked_up_vectors);
  1803. ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point);
  1804. ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset);
  1805. ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
  1806. ClassDB::bind_method(D_METHOD("tessellate_even_length", "max_stages", "tolerance_length"), &Curve3D::tessellate_even_length, DEFVAL(5), DEFVAL(0.2));
  1807. ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
  1808. ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
  1809. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
  1810. ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
  1811. ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
  1812. ADD_GROUP("Up Vector", "up_vector_");
  1813. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");
  1814. }
  1815. Curve3D::Curve3D() {}