VectorAdapter.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. #include "VectorAdapter.h"
  2. #include "../ScriptEngine.h"
  3. #include "WallpaperEngine/Data/Utils/SFINAE.h"
  4. #include "WallpaperEngine/Data/Utils/ScopeGuard.h"
  5. #include <variant>
  6. using namespace WallpaperEngine::Data::Utils;
  7. using namespace WallpaperEngine::Data::Model;
  8. using namespace WallpaperEngine::Scripting::Adapters;
  9. static uint32_t VectorInstanceId = 0;
  10. static uint32_t VectorAdapterInstanceId = 0;
  11. static constexpr int InvalidVectorInstanceId = 0;
  12. // magic value used to ensure the assigned opaque value we got back is valid
  13. #define VEC_OPAQUE_MAGIC 0xdeadbee0
  14. #define VEC_MAGIC_CHECK_EXCEPTION(container, components) \
  15. do { \
  16. if (!container || container->magic != (int)(VEC_OPAQUE_MAGIC + components)) { \
  17. return JS_ThrowTypeError (ctx, "invalid or mismatched vector%d instance", components); \
  18. } \
  19. } while (0)
  20. #define VEC_MAGIC_CHECK_ERROR(container, components) \
  21. do { \
  22. if (!container || container->magic != (int)(VEC_OPAQUE_MAGIC + components)) { \
  23. return -1; \
  24. } \
  25. } while (0)
  26. template <int components> std::map<uint32_t, VectorAdapter<components>&> vectorAdapterInstances;
  27. template <int components> struct VectorOpaqueContainer {
  28. int magic;
  29. VectorAdapter<components>& adapter;
  30. DynamicValue& value;
  31. uint32_t id;
  32. };
  33. template <int components> auto vector_new () -> decltype (auto) {
  34. static_assert (components >= 2 && components <= 4, "Unsupported vector type");
  35. if constexpr (components == 2) {
  36. return glm::vec2 {};
  37. } else if constexpr (components == 3) {
  38. return glm::vec3 {};
  39. } else if constexpr (components == 4) {
  40. return glm::vec4 {};
  41. }
  42. }
  43. template auto vector_new<2> () -> decltype (auto);
  44. template auto vector_new<3> () -> decltype (auto);
  45. template auto vector_new<4> () -> decltype (auto);
  46. template <int components> auto vector_new (float value) -> decltype (auto) {
  47. static_assert (components >= 2 && components <= 4, "Unsupported vector type");
  48. if constexpr (components == 2) {
  49. return glm::vec2 (value);
  50. } else if constexpr (components == 3) {
  51. return glm::vec3 (value);
  52. } else if constexpr (components == 4) {
  53. return glm::vec4 (value);
  54. }
  55. }
  56. template auto vector_new<2> (float value) -> decltype (auto);
  57. template auto vector_new<3> (float value) -> decltype (auto);
  58. template auto vector_new<4> (float value) -> decltype (auto);
  59. template <int components> auto vector_get (DynamicValue& value) -> decltype (auto) {
  60. static_assert (components >= 2 && components <= 4, "Unsupported vector type");
  61. if constexpr (components == 2) {
  62. return value.getVec2 ();
  63. } else if constexpr (components == 3) {
  64. return value.getVec3 ();
  65. } else if constexpr (components == 4) {
  66. return value.getVec4 ();
  67. }
  68. }
  69. template <int components> auto vector_get (JSContext* ctx, JSValue source) -> decltype (auto) {
  70. static_assert (components >= 2 && components <= 4, "Unsupported vector type");
  71. int tag = JS_VALUE_GET_TAG (source);
  72. if (tag == JS_TAG_INT) {
  73. int32_t value = 0;
  74. JS_ToInt32 (ctx, &value, source);
  75. return vector_new<components> (value);
  76. }
  77. if (JS_TAG_IS_FLOAT64 (tag)) {
  78. double value = 0.0f;
  79. JS_ToFloat64 (ctx, &value, source);
  80. return vector_new<components> (static_cast<float> (value));
  81. }
  82. if (tag == JS_TAG_OBJECT) {
  83. JSValue x = JS_GetPropertyStr (ctx, source, "x");
  84. JSValue y = JS_GetPropertyStr (ctx, source, "y");
  85. JSValue z = JS_GetPropertyStr (ctx, source, "z");
  86. JSValue w = JS_GetPropertyStr (ctx, source, "w");
  87. if (!JS_IsNumber (x) || !JS_IsNumber (y)) {
  88. throw std::runtime_error ("Unsupported type conversion for VectorAdapter");
  89. }
  90. // a wider vector handed to a narrower target just loses its extra components
  91. double xVal = 0.0f, yVal = 0.0f, zVal = 0.0f, wVal = 0.0f;
  92. JS_ToFloat64 (ctx, &xVal, x);
  93. JS_ToFloat64 (ctx, &yVal, y);
  94. if (JS_IsNumber (z)) {
  95. JS_ToFloat64 (ctx, &zVal, z);
  96. }
  97. if (JS_IsNumber (w)) {
  98. JS_ToFloat64 (ctx, &wVal, w);
  99. }
  100. if constexpr (components == 2) {
  101. return glm::vec2 (xVal, yVal);
  102. } else if constexpr (components == 3) {
  103. return glm::vec3 (xVal, yVal, zVal);
  104. } else if constexpr (components == 4) {
  105. return glm::vec4 (xVal, yVal, zVal, wVal);
  106. }
  107. }
  108. throw std::runtime_error ("Unsupported type conversion for VectorAdapter");
  109. }
  110. template auto vector_get<2> (JSContext* ctx, JSValue source) -> decltype (auto);
  111. template auto vector_get<3> (JSContext* ctx, JSValue source) -> decltype (auto);
  112. template auto vector_get<4> (JSContext* ctx, JSValue source) -> decltype (auto);
  113. template auto vector_get<2> (DynamicValue& value) -> decltype (auto);
  114. template auto vector_get<3> (DynamicValue& value) -> decltype (auto);
  115. template auto vector_get<4> (DynamicValue& value) -> decltype (auto);
  116. template <int components>
  117. JSValue vector_property_get (JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst receiver) {
  118. JSClassID classId = 0;
  119. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (obj_val, &classId));
  120. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  121. // Exotic get_property intercepts *every* lookup on this class, bypassing the prototype
  122. // chain - so methods (multiply, add, dot, ...), which live only on the prototype, must be
  123. // looked up manually below when the name isn't x/y/z/w.
  124. const char* name = JS_AtomToCString (ctx, atom);
  125. if (name != nullptr) {
  126. ScopeGuard guard ([=] { JS_FreeCString (ctx, name); });
  127. const auto value = vector_get<components> (container->value);
  128. if (strcmp (name, "x") == 0) {
  129. return JS_NewFloat64 (ctx, value.x);
  130. }
  131. if (strcmp (name, "y") == 0) {
  132. return JS_NewFloat64 (ctx, value.y);
  133. }
  134. if constexpr (components >= 3) {
  135. if (strcmp (name, "z") == 0) {
  136. return JS_NewFloat64 (ctx, value.z);
  137. }
  138. if constexpr (components >= 4) {
  139. if (strcmp (name, "w") == 0) {
  140. return JS_NewFloat64 (ctx, value.w);
  141. }
  142. }
  143. }
  144. }
  145. JSValue proto = JS_GetClassProto (ctx, classId);
  146. JSValue result = JS_GetProperty (ctx, proto, atom);
  147. JS_FreeValue (ctx, proto);
  148. return result;
  149. }
  150. template JSValue vector_property_get<2> (JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst receiver);
  151. template JSValue vector_property_get<3> (JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst receiver);
  152. template JSValue vector_property_get<4> (JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst receiver);
  153. template <int components>
  154. int vector_property_set (
  155. JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst val, JSValueConst receiver, int flags
  156. ) {
  157. JSClassID classId = 0;
  158. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (obj_val, &classId));
  159. VEC_MAGIC_CHECK_ERROR (container, components);
  160. int tag = JS_VALUE_GET_TAG (val);
  161. // reading an undeclared property assigns undefined, keep the component as it was instead of throwing
  162. if (tag == JS_TAG_UNDEFINED || tag == JS_TAG_NULL) {
  163. return 0;
  164. }
  165. if (tag != JS_TAG_INT && !JS_TAG_IS_FLOAT64 (tag)) {
  166. return -1;
  167. }
  168. const char* name = JS_AtomToCString (ctx, atom);
  169. if (name == nullptr) {
  170. return -1;
  171. }
  172. ScopeGuard guard ([=] { JS_FreeCString (ctx, name); });
  173. auto vec = vector_get<components> (container->value);
  174. void* into = nullptr;
  175. if (strcmp (name, "x") == 0) {
  176. if constexpr (
  177. std::is_same_v<decltype (vec), glm::vec2> || std::is_same_v<decltype (vec), glm::vec3>
  178. || std::is_same_v<decltype (vec), glm::vec4>
  179. ) {
  180. into = &vec.x;
  181. } else if constexpr (std::is_same_v<decltype (vec), Color>) {
  182. into = &vec.r;
  183. }
  184. } else if (strcmp (name, "y") == 0) {
  185. if constexpr (
  186. std::is_same_v<decltype (vec), glm::vec2> || std::is_same_v<decltype (vec), glm::vec3>
  187. || std::is_same_v<decltype (vec), glm::vec4>
  188. ) {
  189. into = &vec.y;
  190. } else if constexpr (std::is_same_v<decltype (vec), Color>) {
  191. into = &vec.g;
  192. }
  193. } else if constexpr (components >= 3) {
  194. if (strcmp (name, "z") == 0) {
  195. if constexpr (std::is_same_v<decltype (vec), glm::vec3> || std::is_same_v<decltype (vec), glm::vec4>) {
  196. into = &vec.z;
  197. } else if constexpr (std::is_same_v<decltype (vec), Color>) {
  198. into = &vec.b;
  199. }
  200. } else if constexpr (components >= 4) {
  201. if (strcmp (name, "w") == 0) {
  202. if constexpr (std::is_same_v<decltype (vec), glm::vec4>) {
  203. into = &vec.w;
  204. } else if constexpr (std::is_same_v<decltype (vec), Color>) {
  205. into = &vec.a;
  206. }
  207. }
  208. }
  209. }
  210. if (into == nullptr) {
  211. return -1;
  212. }
  213. double value = 0;
  214. JS_ToFloat64 (ctx, &value, val);
  215. *static_cast<float*> (into) = static_cast<float> (value);
  216. container->value.update (vec, DynamicValue::UpdateSource::Script);
  217. return 0;
  218. }
  219. template int vector_property_set<2> (
  220. JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst val, JSValueConst receiver, int flags
  221. );
  222. template int vector_property_set<3> (
  223. JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst val, JSValueConst receiver, int flags
  224. );
  225. template int vector_property_set<4> (
  226. JSContext* ctx, JSValueConst obj_val, JSAtom atom, JSValueConst val, JSValueConst receiver, int flags
  227. );
  228. template <int components> JSValue vector_copy (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  229. JSClassID classId = 0;
  230. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  231. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  232. return container->adapter.instantiate (container->value, true);
  233. }
  234. template JSValue vector_copy<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  235. template JSValue vector_copy<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  236. template JSValue vector_copy<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  237. bool vector_value_equals (JSContext* ctx, JSValue left, JSValue right) {
  238. if (JS_TAG_IS_FLOAT64 (JS_VALUE_GET_TAG (left)) || JS_TAG_IS_FLOAT64 (JS_VALUE_GET_TAG (right))) {
  239. double x1Val = 0.0f, x2Val = 0.0f;
  240. JS_ToFloat64 (ctx, &x1Val, left);
  241. JS_ToFloat64 (ctx, &x2Val, right);
  242. if (std::abs (x1Val - x2Val) > 0.00001) {
  243. return false;
  244. }
  245. } else {
  246. if (!JS_IsEqual (ctx, left, right)) {
  247. return false;
  248. }
  249. }
  250. return true;
  251. }
  252. template <int components> JSValue vector_equals (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  253. if (argc == 0) {
  254. return JS_FALSE;
  255. }
  256. JSClassID classId = 0;
  257. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  258. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  259. JSValue other = argv[0];
  260. auto* otherContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (other, &classId));
  261. VEC_MAGIC_CHECK_EXCEPTION (otherContainer, components);
  262. const auto vector = vector_get<components> (container->value);
  263. const auto otherVector = vector_get<components> (otherContainer->value);
  264. if constexpr (components == 2) {
  265. return vector.x == otherVector.x && vector.y == otherVector.y ? JS_TRUE : JS_FALSE;
  266. } else if constexpr (components == 3) {
  267. return vector.x == otherVector.x && vector.y == otherVector.y && vector.z == otherVector.z ? JS_TRUE : JS_FALSE;
  268. } else if constexpr (components == 4) {
  269. return vector.x == otherVector.x && vector.y == otherVector.y && vector.z == otherVector.z
  270. && vector.w == otherVector.w
  271. ? JS_TRUE
  272. : JS_FALSE;
  273. }
  274. return JS_FALSE;
  275. }
  276. template JSValue vector_equals<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  277. template JSValue vector_equals<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  278. template JSValue vector_equals<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  279. template <int components> JSValue vector_length (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  280. JSClassID classId = 0;
  281. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  282. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  283. return JS_NewFloat64 (ctx, glm::length (vector_get<components> (container->value)));
  284. }
  285. template JSValue vector_length<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  286. template JSValue vector_length<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  287. template JSValue vector_length<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  288. template <int components>
  289. JSValue vector_constructor (JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int magic) {
  290. auto it = vectorAdapterInstances<components>.find (magic);
  291. if (it == vectorAdapterInstances<components>.end ()) {
  292. return JS_ThrowTypeError (ctx, "invalid vector%d constructor instance", components);
  293. }
  294. JSValue result = it->second.instantiate ();
  295. JSClassID classId = 0;
  296. auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (result, &classId));
  297. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  298. // `new Vec3()` with no args is valid and expected to default to a zero vector - already
  299. // zero-initialized above, so nothing further to do here.
  300. if (argc > 1) {
  301. // new Vec3(x, y, z): one number per component, anything not given stays 0
  302. double parts[4] = { 0.0, 0.0, 0.0, 0.0 };
  303. for (int i = 0; i < argc && i < components; i++) {
  304. JS_ToFloat64 (ctx, &parts[i], argv[i]);
  305. }
  306. if constexpr (components == 2) {
  307. container->value.update (glm::vec2 (parts[0], parts[1]), DynamicValue::UpdateSource::Initialization);
  308. } else if constexpr (components == 3) {
  309. container->value.update (glm::vec3 (parts[0], parts[1], parts[2]), DynamicValue::UpdateSource::Initialization);
  310. } else {
  311. container->value.update (
  312. glm::vec4 (parts[0], parts[1], parts[2], parts[3]), DynamicValue::UpdateSource::Initialization
  313. );
  314. }
  315. } else if (argc > 0) {
  316. container->value.update (vector_get<components> (ctx, argv[0]), DynamicValue::UpdateSource::Initialization);
  317. }
  318. return result;
  319. }
  320. template JSValue vector_constructor<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
  321. template JSValue vector_constructor<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
  322. template JSValue vector_constructor<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
  323. template <int components> void vector_finalizer (JSRuntime* rt, JSValueConst val) {
  324. JSClassID classId = 0;
  325. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (val, &classId));
  326. if (!container || container->magic != (int)(VEC_OPAQUE_MAGIC + components)) {
  327. return;
  328. }
  329. // free container and the associated DynamicValue if temporal
  330. if (container->id != InvalidVectorInstanceId) {
  331. container->adapter.free (container->id);
  332. }
  333. delete container;
  334. }
  335. template void vector_finalizer<2> (JSRuntime* rt, JSValueConst val);
  336. template void vector_finalizer<3> (JSRuntime* rt, JSValueConst val);
  337. template void vector_finalizer<4> (JSRuntime* rt, JSValueConst val);
  338. template <int components>
  339. JSValue vector_normalize (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  340. JSClassID classId = 0;
  341. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  342. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  343. JSValue newVector = container->adapter.instantiate (container->value, true);
  344. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  345. newContainer->value.update (
  346. glm::normalize (vector_get<components> (container->value)), DynamicValue::UpdateSource::Script
  347. );
  348. return newVector;
  349. }
  350. template JSValue vector_normalize<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  351. template JSValue vector_normalize<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  352. template JSValue vector_normalize<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  353. template <int components> JSValue vector_add (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  354. if (argc != 1) {
  355. return JS_UNDEFINED;
  356. }
  357. JSClassID classId = 0;
  358. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  359. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  360. JSValue newVector = container->adapter.instantiate ();
  361. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  362. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  363. newContainer->value.update (
  364. vector_get<components> (ctx, argv[0]) + vector_get<components> (container->value),
  365. DynamicValue::UpdateSource::Initialization
  366. );
  367. return newVector;
  368. }
  369. template JSValue vector_add<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  370. template JSValue vector_add<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  371. template JSValue vector_add<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  372. template <int components>
  373. JSValue vector_subtract (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  374. if (argc != 1) {
  375. return JS_UNDEFINED;
  376. }
  377. JSClassID classId = 0;
  378. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  379. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  380. JSValue newVector = container->adapter.instantiate ();
  381. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  382. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  383. newContainer->value.update (
  384. vector_get<components> (ctx, argv[0]) - vector_get<components> (container->value),
  385. DynamicValue::UpdateSource::Initialization
  386. );
  387. return newVector;
  388. }
  389. template JSValue vector_subtract<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  390. template JSValue vector_subtract<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  391. template JSValue vector_subtract<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  392. template <int components>
  393. JSValue vector_multiply (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  394. if (argc != 1) {
  395. return JS_UNDEFINED;
  396. }
  397. JSClassID classId = 0;
  398. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  399. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  400. JSValue newVector = container->adapter.instantiate ();
  401. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  402. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  403. newContainer->value.update (
  404. vector_get<components> (ctx, argv[0]) * vector_get<components> (container->value),
  405. DynamicValue::UpdateSource::Initialization
  406. );
  407. return newVector;
  408. }
  409. template JSValue vector_multiply<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  410. template JSValue vector_multiply<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  411. template JSValue vector_multiply<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  412. template <int components> JSValue vector_divide (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  413. if (argc != 1) {
  414. return JS_UNDEFINED;
  415. }
  416. JSClassID classId = 0;
  417. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  418. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  419. JSValue newVector = container->adapter.instantiate ();
  420. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  421. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  422. newContainer->value.update (
  423. vector_get<components> (ctx, argv[0]) / vector_get<components> (container->value),
  424. DynamicValue::UpdateSource::Initialization
  425. );
  426. return newVector;
  427. }
  428. template JSValue vector_divide<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  429. template JSValue vector_divide<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  430. template JSValue vector_divide<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  431. template <int components> JSValue vector_dot (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  432. if (argc != 1) {
  433. return JS_UNDEFINED;
  434. }
  435. JSClassID classId = 0;
  436. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  437. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  438. JSValue newVector = container->adapter.instantiate ();
  439. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  440. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  441. newContainer->value.update (
  442. glm::dot (vector_get<components> (ctx, argv[0]), vector_get<components> (container->value)),
  443. DynamicValue::UpdateSource::Initialization
  444. );
  445. return newVector;
  446. }
  447. template JSValue vector_dot<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  448. template JSValue vector_dot<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  449. template JSValue vector_dot<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  450. template <int components> JSValue vector_cross (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  451. if (argc != 1) {
  452. return JS_UNDEFINED;
  453. }
  454. JSClassID classId = 0;
  455. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  456. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  457. JSValue newVector = container->adapter.instantiate ();
  458. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  459. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  460. newContainer->value.update (
  461. glm::cross (vector_get<components> (ctx, argv[0]), vector_get<components> (container->value)),
  462. DynamicValue::UpdateSource::Initialization
  463. );
  464. return newVector;
  465. }
  466. template JSValue vector_cross<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  467. template <int components> JSValue vector_mix (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  468. if (argc != 2) {
  469. return JS_EXCEPTION;
  470. }
  471. if (!JS_IsNumber (argv[1])) {
  472. return JS_EXCEPTION;
  473. }
  474. double amount = 0.0f;
  475. JS_ToFloat64 (ctx, &amount, argv[1]);
  476. JSClassID classId = 0;
  477. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  478. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  479. JSValue newVector = container->adapter.instantiate ();
  480. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  481. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  482. newContainer->value.update (
  483. glm::mix (vector_get<components> (ctx, argv[0]), vector_get<components> (container->value), amount),
  484. DynamicValue::UpdateSource::Initialization
  485. );
  486. return newVector;
  487. }
  488. template JSValue vector_mix<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  489. template JSValue vector_mix<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  490. template JSValue vector_mix<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  491. template <int components> JSValue vector_min (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  492. if (argc != 1) {
  493. return JS_UNDEFINED;
  494. }
  495. JSClassID classId = 0;
  496. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  497. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  498. JSValue newVector = container->adapter.instantiate ();
  499. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  500. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  501. newContainer->value.update (
  502. glm::min (vector_get<components> (ctx, argv[0]), vector_get<components> (container->value)),
  503. DynamicValue::UpdateSource::Initialization
  504. );
  505. return newVector;
  506. }
  507. template JSValue vector_min<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  508. template JSValue vector_min<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  509. template JSValue vector_min<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  510. template <int components> JSValue vector_max (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  511. if (argc != 1) {
  512. return JS_UNDEFINED;
  513. }
  514. JSClassID classId = 0;
  515. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  516. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  517. JSValue newVector = container->adapter.instantiate ();
  518. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  519. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  520. newContainer->value.update (
  521. glm::max (vector_get<components> (ctx, argv[0]), vector_get<components> (container->value)),
  522. DynamicValue::UpdateSource::Initialization
  523. );
  524. return newVector;
  525. }
  526. template JSValue vector_max<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  527. template JSValue vector_max<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  528. template JSValue vector_max<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  529. template <int components> JSValue vector_abs (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  530. JSClassID classId = 0;
  531. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  532. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  533. JSValue newVector = container->adapter.instantiate ();
  534. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  535. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  536. newContainer->value.update (
  537. glm::abs (vector_get<components> (container->value)), DynamicValue::UpdateSource::Initialization
  538. );
  539. return newVector;
  540. }
  541. template JSValue vector_abs<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  542. template JSValue vector_abs<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  543. template JSValue vector_abs<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  544. template <int components> JSValue vector_sign (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  545. JSClassID classId = 0;
  546. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  547. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  548. JSValue newVector = container->adapter.instantiate ();
  549. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  550. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  551. newContainer->value.update (
  552. glm::sign (vector_get<components> (container->value)), DynamicValue::UpdateSource::Initialization
  553. );
  554. return newVector;
  555. }
  556. template JSValue vector_sign<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  557. template JSValue vector_sign<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  558. template JSValue vector_sign<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  559. template <int components> JSValue vector_round (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  560. JSClassID classId = 0;
  561. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  562. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  563. JSValue newVector = container->adapter.instantiate ();
  564. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  565. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  566. newContainer->value.update (
  567. glm::round (vector_get<components> (container->value)), DynamicValue::UpdateSource::Initialization
  568. );
  569. return newVector;
  570. }
  571. template JSValue vector_round<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  572. template JSValue vector_round<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  573. template JSValue vector_round<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  574. template <int components> JSValue vector_floor (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  575. JSClassID classId = 0;
  576. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  577. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  578. JSValue newVector = container->adapter.instantiate ();
  579. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  580. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  581. newContainer->value.update (
  582. glm::floor (vector_get<components> (container->value)), DynamicValue::UpdateSource::Initialization
  583. );
  584. return newVector;
  585. }
  586. template JSValue vector_floor<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  587. template JSValue vector_floor<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  588. template JSValue vector_floor<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  589. template <int components> JSValue vector_ceil (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  590. JSClassID classId = 0;
  591. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  592. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  593. JSValue newVector = container->adapter.instantiate ();
  594. const auto* newContainer = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (newVector, &classId));
  595. const auto vector = vector_get<components> (container->value);
  596. VEC_MAGIC_CHECK_EXCEPTION (newContainer, components);
  597. newContainer->value.update (glm::ceil (vector), DynamicValue::UpdateSource::Initialization);
  598. return newVector;
  599. }
  600. template JSValue vector_ceil<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  601. template JSValue vector_ceil<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  602. template JSValue vector_ceil<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  603. template <int components>
  604. JSValue vector_toString (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
  605. JSClassID classId = 0;
  606. const auto* container = static_cast<VectorOpaqueContainer<components>*> (JS_GetAnyOpaque (this_val, &classId));
  607. VEC_MAGIC_CHECK_EXCEPTION (container, components);
  608. return JS_NewString (ctx, container->value.toString ().c_str ());
  609. }
  610. template JSValue vector_toString<2> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  611. template JSValue vector_toString<3> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  612. template JSValue vector_toString<4> (JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
  613. template <int components>
  614. VectorAdapter<components>::VectorAdapter (ScriptEngine& engine) :
  615. ObjectAdapter (engine), m_instanceId (++VectorAdapterInstanceId), m_name ("Vec" + std::to_string (components)),
  616. m_exoticMethods (
  617. {
  618. .get_property = vector_property_get<components>,
  619. .set_property = vector_property_set<components>,
  620. }
  621. ) {
  622. vectorAdapterInstances<components>.emplace (this->m_instanceId, *this);
  623. this->registerType (
  624. {
  625. .class_name = this->m_name.c_str (),
  626. .finalizer = vector_finalizer<components>,
  627. .exotic = &this->m_exoticMethods,
  628. }
  629. );
  630. m_prototype = JS_NewObject (this->m_engine.getContext ());
  631. JS_DupValue (this->m_engine.getContext (), m_prototype);
  632. JSValue ctor = JS_NewCFunctionMagic (
  633. this->m_engine.getContext (), vector_constructor<components>, this->m_name.c_str (), 1,
  634. JS_CFUNC_constructor_magic, this->m_instanceId
  635. );
  636. JS_SetConstructor (this->m_engine.getContext (), ctor, m_prototype);
  637. JS_DefinePropertyValueStr (
  638. this->m_engine.getContext (), m_prototype, "copy",
  639. JS_NewCFunction (this->m_engine.getContext (), vector_copy<components>, "copy", 0), JS_PROP_ENUMERABLE
  640. );
  641. JS_DefinePropertyValueStr (
  642. this->m_engine.getContext (), m_prototype, "equals",
  643. JS_NewCFunction (this->m_engine.getContext (), vector_equals<components>, "equals", 1), JS_PROP_ENUMERABLE
  644. );
  645. JS_DefinePropertyValueStr (
  646. this->m_engine.getContext (), m_prototype, "length",
  647. JS_NewCFunction (this->m_engine.getContext (), vector_length<components>, "length", 0), JS_PROP_ENUMERABLE
  648. );
  649. JS_DefinePropertyValueStr (
  650. this->m_engine.getContext (), m_prototype, "lengthSqr",
  651. JS_NewCFunction (this->m_engine.getContext (), vector_length<components>, "lengthSqr", 0), JS_PROP_ENUMERABLE
  652. );
  653. JS_DefinePropertyValueStr (
  654. this->m_engine.getContext (), m_prototype, "normalize",
  655. JS_NewCFunction (this->m_engine.getContext (), vector_normalize<components>, "normalize", 0), JS_PROP_ENUMERABLE
  656. );
  657. JS_DefinePropertyValueStr (
  658. this->m_engine.getContext (), m_prototype, "add",
  659. JS_NewCFunction (this->m_engine.getContext (), vector_add<components>, "add", 1), JS_PROP_ENUMERABLE
  660. );
  661. JS_DefinePropertyValueStr (
  662. this->m_engine.getContext (), m_prototype, "subtract",
  663. JS_NewCFunction (this->m_engine.getContext (), vector_subtract<components>, "subtract", 1), JS_PROP_ENUMERABLE
  664. );
  665. JS_DefinePropertyValueStr (
  666. this->m_engine.getContext (), m_prototype, "multiply",
  667. JS_NewCFunction (this->m_engine.getContext (), vector_multiply<components>, "multiply", 1), JS_PROP_ENUMERABLE
  668. );
  669. JS_DefinePropertyValueStr (
  670. this->m_engine.getContext (), m_prototype, "divide",
  671. JS_NewCFunction (this->m_engine.getContext (), vector_divide<components>, "divide", 1), JS_PROP_ENUMERABLE
  672. );
  673. JS_DefinePropertyValueStr (
  674. this->m_engine.getContext (), m_prototype, "dot",
  675. JS_NewCFunction (this->m_engine.getContext (), vector_dot<components>, "dot", 1), JS_PROP_ENUMERABLE
  676. );
  677. if constexpr (components == 3) {
  678. JS_DefinePropertyValueStr (
  679. this->m_engine.getContext (), m_prototype, "cross",
  680. JS_NewCFunction (this->m_engine.getContext (), vector_cross<components>, "cross", 1), JS_PROP_ENUMERABLE
  681. );
  682. }
  683. JS_DefinePropertyValueStr (
  684. this->m_engine.getContext (), m_prototype, "mix",
  685. JS_NewCFunction (this->m_engine.getContext (), vector_mix<components>, "mix", 2), JS_PROP_ENUMERABLE
  686. );
  687. JS_DefinePropertyValueStr (
  688. this->m_engine.getContext (), m_prototype, "min",
  689. JS_NewCFunction (this->m_engine.getContext (), vector_min<components>, "min", 1), JS_PROP_ENUMERABLE
  690. );
  691. JS_DefinePropertyValueStr (
  692. this->m_engine.getContext (), m_prototype, "max",
  693. JS_NewCFunction (this->m_engine.getContext (), vector_max<components>, "max", 1), JS_PROP_ENUMERABLE
  694. );
  695. JS_DefinePropertyValueStr (
  696. this->m_engine.getContext (), m_prototype, "abs",
  697. JS_NewCFunction (this->m_engine.getContext (), vector_abs<components>, "abs", 0), JS_PROP_ENUMERABLE
  698. );
  699. JS_DefinePropertyValueStr (
  700. this->m_engine.getContext (), m_prototype, "sign",
  701. JS_NewCFunction (this->m_engine.getContext (), vector_sign<components>, "sign", 0), JS_PROP_ENUMERABLE
  702. );
  703. JS_DefinePropertyValueStr (
  704. this->m_engine.getContext (), m_prototype, "round",
  705. JS_NewCFunction (this->m_engine.getContext (), vector_round<components>, "round", 0), JS_PROP_ENUMERABLE
  706. );
  707. JS_DefinePropertyValueStr (
  708. this->m_engine.getContext (), m_prototype, "floor",
  709. JS_NewCFunction (this->m_engine.getContext (), vector_floor<components>, "floor", 0), JS_PROP_ENUMERABLE
  710. );
  711. JS_DefinePropertyValueStr (
  712. this->m_engine.getContext (), m_prototype, "ceil",
  713. JS_NewCFunction (this->m_engine.getContext (), vector_ceil<components>, "ceil", 0), JS_PROP_ENUMERABLE
  714. );
  715. JS_DefinePropertyValueStr (
  716. this->m_engine.getContext (), m_prototype, "toString",
  717. JS_NewCFunction (this->m_engine.getContext (), vector_toString<components>, "toString", 0), JS_PROP_ENUMERABLE
  718. );
  719. JS_SetClassProto (this->m_engine.getContext (), this->m_classId, m_prototype);
  720. // JS_SetConstructor only wires up prototype<->constructor for instanceof; without exposing
  721. // ctor as a global here, `new Vec3(...)` didn't exist, and scripts using it at module top
  722. // level (not inside a function) would throw ReferenceError during module evaluation, killing
  723. // that script before init()/update() ever ran.
  724. JS_DefinePropertyValueStr (
  725. this->m_engine.getContext (), this->m_engine.getGlobalThis (), this->m_name.c_str (), ctor, JS_PROP_ENUMERABLE
  726. );
  727. }
  728. template <int components> VectorAdapter<components>::~VectorAdapter () {
  729. vectorAdapterInstances<components>.erase (this->m_instanceId);
  730. // Runs after ScriptEngine has freed the JS runtime/context, so m_prototype and everything
  731. // else tied to it is already gone - nothing left to release here.
  732. }
  733. template <int components> JSValue VectorAdapter<components>::instantiate (ScriptableObject& object) {
  734. throw std::runtime_error ("Cannot create a Vector4 instance from a ScriptableObject");
  735. }
  736. template <int components> JSValue VectorAdapter<components>::instantiate (DynamicValue& value) {
  737. JSValue result = this->ObjectAdapter::instantiate (value);
  738. JS_SetOpaque (
  739. result,
  740. new VectorOpaqueContainer<components> {
  741. .magic = VEC_OPAQUE_MAGIC + components,
  742. .adapter = *this,
  743. .value = value,
  744. .id = InvalidVectorInstanceId,
  745. }
  746. );
  747. return result;
  748. }
  749. template <int components> JSValue VectorAdapter<components>::instantiate (DynamicValue& source, bool temporal) {
  750. auto value = std::make_unique<DynamicValue> (source);
  751. uint32_t id = ++VectorInstanceId;
  752. JSValue result = this->ObjectAdapter::instantiate (*value);
  753. JS_SetOpaque (
  754. result,
  755. new VectorOpaqueContainer<components> {
  756. .magic = VEC_OPAQUE_MAGIC + components,
  757. .adapter = *this,
  758. .value = *value,
  759. .id = id,
  760. }
  761. );
  762. this->m_values.emplace (id, std::move (value));
  763. return result;
  764. }
  765. template <int components> JSValue VectorAdapter<components>::instantiate () {
  766. auto value = std::make_unique<DynamicValue> (vector_new<components> ());
  767. uint32_t id = ++VectorInstanceId;
  768. JSValue result = this->ObjectAdapter::instantiate (*value);
  769. JS_SetOpaque (
  770. result,
  771. new VectorOpaqueContainer<components> {
  772. .magic = VEC_OPAQUE_MAGIC + components,
  773. .adapter = *this,
  774. .value = *value,
  775. .id = id,
  776. }
  777. );
  778. this->m_values.emplace (id, std::move (value));
  779. return result;
  780. }
  781. template <int components> void VectorAdapter<components>::free (uint32_t vectorId) {
  782. auto it = this->m_values.find (vectorId);
  783. if (it != this->m_values.end ()) {
  784. this->m_values.erase (it);
  785. }
  786. }
  787. namespace WallpaperEngine::Scripting::Adapters {
  788. template class VectorAdapter<2>;
  789. template class VectorAdapter<3>;
  790. template class VectorAdapter<4>;
  791. } // namespace WallpaperEngine::Scripting::Adapters