linalg.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. #include "pocketpy/linalg.h"
  2. namespace pkpy{
  3. #define BIND_VEC_VEC_OP(D, name, op) \
  4. vm->bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \
  5. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  6. PyVec##D& other = CAST(PyVec##D&, args[1]); \
  7. return VAR(self op other); \
  8. });
  9. #define BIND_VEC_FLOAT_OP(D, name, op) \
  10. vm->bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \
  11. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  12. f64 other = CAST(f64, args[1]); \
  13. return VAR(self op other); \
  14. });
  15. #define BIND_VEC_FUNCTION_0(D, name) \
  16. vm->bind_method<0>(type, #name, [](VM* vm, ArgsView args){ \
  17. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  18. return VAR(self.name()); \
  19. });
  20. #define BIND_VEC_FUNCTION_1(D, name) \
  21. vm->bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \
  22. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  23. PyVec##D& other = CAST(PyVec##D&, args[1]); \
  24. return VAR(self.name(other)); \
  25. });
  26. #define BIND_VEC_FIELD(D, name) \
  27. vm->bind_property(type, #name, \
  28. [](VM* vm, ArgsView args){ \
  29. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  30. return VAR(self.name); \
  31. }, [](VM* vm, ArgsView args){ \
  32. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  33. self.name = CAST(f64, args[1]); \
  34. return vm->None; \
  35. });
  36. // https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289
  37. static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
  38. {
  39. // Based on Game Programming Gems 4 Chapter 1.10
  40. smoothTime = std::max(0.0001F, smoothTime);
  41. float omega = 2.0F / smoothTime;
  42. float x = omega * deltaTime;
  43. float exp = 1.0F / (1.0F + x + 0.48F * x * x + 0.235F * x * x * x);
  44. float change_x = current.x - target.x;
  45. float change_y = current.y - target.y;
  46. Vec2 originalTo = target;
  47. // Clamp maximum speed
  48. float maxChange = maxSpeed * smoothTime;
  49. float maxChangeSq = maxChange * maxChange;
  50. float sqDist = change_x * change_x + change_y * change_y;
  51. if (sqDist > maxChangeSq)
  52. {
  53. float mag = std::sqrt(sqDist);
  54. change_x = change_x / mag * maxChange;
  55. change_y = change_y / mag * maxChange;
  56. }
  57. target.x = current.x - change_x;
  58. target.y = current.y - change_y;
  59. float temp_x = (currentVelocity.x + omega * change_x) * deltaTime;
  60. float temp_y = (currentVelocity.y + omega * change_y) * deltaTime;
  61. currentVelocity.x = (currentVelocity.x - omega * temp_x) * exp;
  62. currentVelocity.y = (currentVelocity.y - omega * temp_y) * exp;
  63. float output_x = target.x + (change_x + temp_x) * exp;
  64. float output_y = target.y + (change_y + temp_y) * exp;
  65. // Prevent overshooting
  66. float origMinusCurrent_x = originalTo.x - current.x;
  67. float origMinusCurrent_y = originalTo.y - current.y;
  68. float outMinusOrig_x = output_x - originalTo.x;
  69. float outMinusOrig_y = output_y - originalTo.y;
  70. if (origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0)
  71. {
  72. output_x = originalTo.x;
  73. output_y = originalTo.y;
  74. currentVelocity.x = (output_x - originalTo.x) / deltaTime;
  75. currentVelocity.y = (output_y - originalTo.y) / deltaTime;
  76. }
  77. return Vec2(output_x, output_y);
  78. }
  79. void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){
  80. PY_STRUCT_LIKE(PyVec2)
  81. vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){
  82. float x = CAST_F(args[1]);
  83. float y = CAST_F(args[2]);
  84. return vm->heap.gcnew<PyVec2>(PK_OBJ_GET(Type, args[0]), Vec2(x, y));
  85. });
  86. // @staticmethod
  87. vm->bind(type, "smooth_damp(current: vec2, target: vec2, current_velocity: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", [](VM* vm, ArgsView args){
  88. Vec2 current = CAST(Vec2, args[0]);
  89. Vec2 target = CAST(Vec2, args[1]);
  90. PyVec2& current_velocity = CAST(PyVec2&, args[2]);
  91. float smooth_time = CAST_F(args[3]);
  92. float max_speed = CAST_F(args[4]);
  93. float delta_time = CAST_F(args[5]);
  94. Vec2 ret = SmoothDamp(current, target, current_velocity, smooth_time, max_speed, delta_time);
  95. return VAR(ret);
  96. }, {}, BindType::STATICMETHOD);
  97. // @staticmethod
  98. vm->bind(type, "angle(__from: vec2, __to: vec2) -> float", [](VM* vm, ArgsView args){
  99. PyVec2 __from = CAST(PyVec2, args[0]);
  100. PyVec2 __to = CAST(PyVec2, args[1]);
  101. float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
  102. const float PI = 3.1415926535897932384f;
  103. if(val > PI) val -= 2*PI;
  104. if(val < -PI) val += 2*PI;
  105. return VAR(val);
  106. }, {}, BindType::STATICMETHOD);
  107. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  108. PyVec2& self = _CAST(PyVec2&, obj);
  109. std::stringstream ss;
  110. ss << std::fixed << std::setprecision(3);
  111. ss << "vec2(" << self.x << ", " << self.y << ")";
  112. return VAR(ss.str());
  113. });
  114. vm->bind_method<1>(type, "rotate", [](VM* vm, ArgsView args){
  115. Vec2 self = _CAST(PyVec2&, args[0]);
  116. float radian = CAST(f64, args[1]);
  117. float cr = cosf(radian);
  118. float sr = sinf(radian);
  119. Mat3x3 rotate(cr, -sr, 0.0f,
  120. sr, cr, 0.0f,
  121. 0.0f, 0.0f, 1.0f);
  122. self = rotate.transform_vector(self);
  123. return VAR(self);
  124. });
  125. BIND_VEC_VEC_OP(2, __add__, +)
  126. BIND_VEC_VEC_OP(2, __sub__, -)
  127. BIND_VEC_FLOAT_OP(2, __mul__, *)
  128. BIND_VEC_FLOAT_OP(2, __rmul__, *)
  129. BIND_VEC_FLOAT_OP(2, __truediv__, /)
  130. BIND_VEC_FIELD(2, x)
  131. BIND_VEC_FIELD(2, y)
  132. BIND_VEC_FUNCTION_1(2, dot)
  133. BIND_VEC_FUNCTION_1(2, cross)
  134. BIND_VEC_FUNCTION_1(2, assign)
  135. BIND_VEC_FUNCTION_0(2, length)
  136. BIND_VEC_FUNCTION_0(2, length_squared)
  137. BIND_VEC_FUNCTION_0(2, normalize)
  138. }
  139. void PyVec3::_register(VM* vm, PyObject* mod, PyObject* type){
  140. PY_STRUCT_LIKE(PyVec3)
  141. vm->bind_constructor<4>(type, [](VM* vm, ArgsView args){
  142. float x = CAST_F(args[1]);
  143. float y = CAST_F(args[2]);
  144. float z = CAST_F(args[3]);
  145. return vm->heap.gcnew<PyVec3>(PK_OBJ_GET(Type, args[0]), Vec3(x, y, z));
  146. });
  147. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  148. PyVec3& self = _CAST(PyVec3&, obj);
  149. std::stringstream ss;
  150. ss << std::fixed << std::setprecision(3);
  151. ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")";
  152. return VAR(ss.str());
  153. });
  154. BIND_VEC_VEC_OP(3, __add__, +)
  155. BIND_VEC_VEC_OP(3, __sub__, -)
  156. BIND_VEC_FLOAT_OP(3, __mul__, *)
  157. BIND_VEC_FLOAT_OP(3, __rmul__, *)
  158. BIND_VEC_FLOAT_OP(3, __truediv__, /)
  159. BIND_VEC_FIELD(3, x)
  160. BIND_VEC_FIELD(3, y)
  161. BIND_VEC_FIELD(3, z)
  162. BIND_VEC_FUNCTION_1(3, dot)
  163. BIND_VEC_FUNCTION_1(3, cross)
  164. BIND_VEC_FUNCTION_1(3, assign)
  165. BIND_VEC_FUNCTION_0(3, length)
  166. BIND_VEC_FUNCTION_0(3, length_squared)
  167. BIND_VEC_FUNCTION_0(3, normalize)
  168. }
  169. void PyVec4::_register(VM* vm, PyObject* mod, PyObject* type){
  170. PY_STRUCT_LIKE(PyVec4)
  171. vm->bind_constructor<1+4>(type, [](VM* vm, ArgsView args){
  172. float x = CAST_F(args[1]);
  173. float y = CAST_F(args[2]);
  174. float z = CAST_F(args[3]);
  175. float w = CAST_F(args[4]);
  176. return vm->heap.gcnew<PyVec4>(PK_OBJ_GET(Type, args[0]), Vec4(x, y, z, w));
  177. });
  178. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  179. PyVec4& self = _CAST(PyVec4&, obj);
  180. std::stringstream ss;
  181. ss << std::fixed << std::setprecision(3);
  182. ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")";
  183. return VAR(ss.str());
  184. });
  185. BIND_VEC_VEC_OP(4, __add__, +)
  186. BIND_VEC_VEC_OP(4, __sub__, -)
  187. BIND_VEC_FLOAT_OP(4, __mul__, *)
  188. BIND_VEC_FLOAT_OP(4, __rmul__, *)
  189. BIND_VEC_FLOAT_OP(4, __truediv__, /)
  190. BIND_VEC_FIELD(4, x)
  191. BIND_VEC_FIELD(4, y)
  192. BIND_VEC_FIELD(4, z)
  193. BIND_VEC_FIELD(4, w)
  194. BIND_VEC_FUNCTION_1(4, dot)
  195. BIND_VEC_FUNCTION_1(4, assign)
  196. BIND_VEC_FUNCTION_0(4, length)
  197. BIND_VEC_FUNCTION_0(4, length_squared)
  198. BIND_VEC_FUNCTION_0(4, normalize)
  199. }
  200. #undef BIND_VEC_ADDR
  201. #undef BIND_VEC_VEC_OP
  202. #undef BIND_VEC_FLOAT_OP
  203. #undef BIND_VEC_FIELD
  204. #undef BIND_VEC_FUNCTION_0
  205. #undef BIND_VEC_FUNCTION_1
  206. void PyMat3x3::_register(VM* vm, PyObject* mod, PyObject* type){
  207. PY_STRUCT_LIKE(PyMat3x3)
  208. vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){
  209. if(args.size() == 1+0) return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
  210. if(args.size() == 1+1){
  211. const List& list = CAST(List&, args[1]);
  212. if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
  213. Mat3x3 mat;
  214. for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
  215. return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), mat);
  216. }
  217. if(args.size() == 1+9){
  218. Mat3x3 mat;
  219. for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
  220. return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), mat);
  221. }
  222. vm->TypeError(fmt("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
  223. return vm->None;
  224. });
  225. vm->bind_method<1>(type, "assign", [](VM* vm, ArgsView args){
  226. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  227. const PyMat3x3& other = CAST(PyMat3x3&, args[1]);
  228. self = other;
  229. return vm->None;
  230. });
  231. vm->bind_method<0>(type, "set_zeros", PK_ACTION(PK_OBJ_GET(PyMat3x3, args[0]).set_zeros()));
  232. vm->bind_method<0>(type, "set_ones", PK_ACTION(PK_OBJ_GET(PyMat3x3, args[0]).set_ones()));
  233. vm->bind_method<0>(type, "set_identity", PK_ACTION(PK_OBJ_GET(PyMat3x3, args[0]).set_identity()));
  234. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  235. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  236. std::stringstream ss;
  237. ss << std::fixed << std::setprecision(3);
  238. ss << "mat3x3([" << self._11 << ", " << self._12 << ", " << self._13 << ",\n";
  239. ss << " " << self._21 << ", " << self._22 << ", " << self._23 << ",\n";
  240. ss << " " << self._31 << ", " << self._32 << ", " << self._33 << "])";
  241. return VAR(ss.str());
  242. });
  243. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index){
  244. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  245. Tuple& t = CAST(Tuple&, index);
  246. if(t.size() != 2){
  247. vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
  248. return vm->None;
  249. }
  250. i64 i = CAST(i64, t[0]);
  251. i64 j = CAST(i64, t[1]);
  252. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  253. vm->IndexError("index out of range");
  254. return vm->None;
  255. }
  256. return VAR(self.m[i][j]);
  257. });
  258. vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index, PyObject* value){
  259. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  260. Tuple& t = CAST(Tuple&, index);
  261. if(t.size() != 2){
  262. vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
  263. return;
  264. }
  265. i64 i = CAST(i64, t[0]);
  266. i64 j = CAST(i64, t[1]);
  267. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  268. vm->IndexError("index out of range");
  269. return;
  270. }
  271. self.m[i][j] = CAST_F(value);
  272. });
  273. #define PROPERTY_FIELD(field) \
  274. vm->bind_property(type, #field ": float", \
  275. [](VM* vm, ArgsView args){ \
  276. PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
  277. return VAR(self.field); \
  278. }, [](VM* vm, ArgsView args){ \
  279. PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
  280. self.field = CAST(f64, args[1]); \
  281. return vm->None; \
  282. });
  283. PROPERTY_FIELD(_11)
  284. PROPERTY_FIELD(_12)
  285. PROPERTY_FIELD(_13)
  286. PROPERTY_FIELD(_21)
  287. PROPERTY_FIELD(_22)
  288. PROPERTY_FIELD(_23)
  289. PROPERTY_FIELD(_31)
  290. PROPERTY_FIELD(_32)
  291. PROPERTY_FIELD(_33)
  292. #undef PROPERTY_FIELD
  293. vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  294. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  295. PyMat3x3& other = CAST(PyMat3x3&, _1);
  296. return VAR_T(PyMat3x3, self + other);
  297. });
  298. vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  299. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  300. PyMat3x3& other = CAST(PyMat3x3&, _1);
  301. return VAR_T(PyMat3x3, self - other);
  302. });
  303. vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  304. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  305. f64 other = CAST_F(_1);
  306. return VAR_T(PyMat3x3, self * other);
  307. });
  308. vm->bind_method<1>(type, "__rmul__", [](VM* vm, ArgsView args){
  309. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  310. f64 other = CAST_F(args[1]);
  311. return VAR_T(PyMat3x3, self * other);
  312. });
  313. vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  314. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  315. f64 other = CAST_F(_1);
  316. return VAR_T(PyMat3x3, self / other);
  317. });
  318. vm->bind__matmul__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  319. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  320. if(is_non_tagged_type(_1, PyMat3x3::_type(vm))){
  321. const PyMat3x3& other = _CAST(PyMat3x3&, _1);
  322. Mat3x3 out;
  323. self.matmul(other, out);
  324. return VAR_T(PyMat3x3, out);
  325. }
  326. if(is_non_tagged_type(_1, PyVec3::_type(vm))){
  327. const PyVec3& other = _CAST(PyVec3&, _1);
  328. Vec3 out;
  329. self.matmul(other, out);
  330. return VAR_T(PyVec3, out);
  331. }
  332. return vm->NotImplemented;
  333. });
  334. vm->bind_method<1>(type, "__imatmul__", [](VM* vm, ArgsView args){
  335. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  336. vm->check_non_tagged_type(args[1], PyMat3x3::_type(vm));
  337. const PyMat3x3& other = _CAST(PyMat3x3&, args[1]);
  338. Mat3x3 out;
  339. self.matmul(other, out);
  340. self = out;
  341. return args[0];
  342. });
  343. vm->bind_method<0>(type, "determinant", [](VM* vm, ArgsView args){
  344. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  345. return VAR(self.determinant());
  346. });
  347. vm->bind_method<0>(type, "transpose", [](VM* vm, ArgsView args){
  348. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  349. return VAR_T(PyMat3x3, self.transpose());
  350. });
  351. vm->bind__invert__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  352. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  353. Mat3x3 ret;
  354. bool ok = self.inverse(ret);
  355. if(!ok) vm->ValueError("matrix is not invertible");
  356. return VAR_T(PyMat3x3, ret);
  357. });
  358. vm->bind_method<0>(type, "invert_", [](VM* vm, ArgsView args){
  359. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  360. Mat3x3 ret;
  361. bool ok = self.inverse(ret);
  362. if(!ok) vm->ValueError("matrix is not invertible");
  363. self = ret;
  364. return vm->None;
  365. });
  366. // @staticmethod
  367. vm->bind(type, "zeros()", [](VM* vm, ArgsView args){
  368. PK_UNUSED(args);
  369. return VAR_T(PyMat3x3, Mat3x3::zeros());
  370. }, {}, BindType::STATICMETHOD);
  371. // @staticmethod
  372. vm->bind(type, "ones()", [](VM* vm, ArgsView args){
  373. PK_UNUSED(args);
  374. return VAR_T(PyMat3x3, Mat3x3::ones());
  375. }, {}, BindType::STATICMETHOD);
  376. // @staticmethod
  377. vm->bind(type, "identity()", [](VM* vm, ArgsView args){
  378. PK_UNUSED(args);
  379. return VAR_T(PyMat3x3, Mat3x3::identity());
  380. }, {}, BindType::STATICMETHOD);
  381. /*************** affine transformations ***************/
  382. // @staticmethod
  383. vm->bind(type, "trs(t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
  384. Vec2 t = CAST(Vec2, args[0]);
  385. f64 r = CAST_F(args[1]);
  386. Vec2 s = CAST(Vec2, args[2]);
  387. return VAR_T(PyMat3x3, Mat3x3::trs(t, r, s));
  388. }, {}, BindType::STATICMETHOD);
  389. vm->bind(type, "set_trs(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
  390. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  391. Vec2 t = CAST(Vec2, args[1]);
  392. f64 r = CAST_F(args[2]);
  393. Vec2 s = CAST(Vec2, args[3]);
  394. self = Mat3x3::trs(t, r, s);
  395. return vm->None;
  396. });
  397. vm->bind_method<0>(type, "is_affine", [](VM* vm, ArgsView args){
  398. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  399. return VAR(self.is_affine());
  400. });
  401. vm->bind_method<0>(type, "_t", [](VM* vm, ArgsView args){
  402. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  403. return VAR_T(PyVec2, self._t());
  404. });
  405. vm->bind_method<0>(type, "_r", [](VM* vm, ArgsView args){
  406. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  407. return VAR(self._r());
  408. });
  409. vm->bind_method<0>(type, "_s", [](VM* vm, ArgsView args){
  410. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  411. return VAR_T(PyVec2, self._s());
  412. });
  413. vm->bind_method<1>(type, "transform_point", [](VM* vm, ArgsView args){
  414. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  415. PyVec2& v = CAST(PyVec2&, args[1]);
  416. return VAR_T(PyVec2, self.transform_point(v));
  417. });
  418. vm->bind_method<1>(type, "transform_vector", [](VM* vm, ArgsView args){
  419. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  420. PyVec2& v = CAST(PyVec2&, args[1]);
  421. return VAR_T(PyVec2, self.transform_vector(v));
  422. });
  423. }
  424. void add_module_linalg(VM* vm){
  425. PyObject* linalg = vm->new_module("linalg");
  426. PyVec2::register_class(vm, linalg);
  427. PyVec3::register_class(vm, linalg);
  428. PyVec4::register_class(vm, linalg);
  429. PyMat3x3::register_class(vm, linalg);
  430. PyObject* float_p = vm->_modules["c"]->attr("float_p");
  431. linalg->attr().set("vec2_p", float_p);
  432. linalg->attr().set("vec3_p", float_p);
  433. linalg->attr().set("vec4_p", float_p);
  434. linalg->attr().set("mat3x3_p", float_p);
  435. }
  436. } // namespace pkpy