Browse Source

linmath: Backport support for floor division to 1.10

Backport of 89447378440e9b9472a7290facbd8949f41a64ae

(Also fixes return type of `__pow__` to always be derived class)
rdb 4 years ago
parent
commit
2386e80448

+ 72 - 5
panda/src/linmath/lvecBase2_ext_src.I

@@ -200,11 +200,78 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
 /**
 /**
  *
  *
  */
  */
-INLINE_LINMATH FLOATNAME(LVecBase2) Extension<FLOATNAME(LVecBase2)>::
-__pow__(FLOATTYPE exponent) const {
-  return FLOATNAME(LVecBase2)(
-    cpow(_this->_v(0), exponent),
-    cpow(_this->_v(1), exponent));
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
+__floordiv__(PyObject *self, FLOATTYPE scalar) const {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase2) *vec = (FLOATNAME(LVecBase2) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase2));
+    nassertr(vec != nullptr, nullptr);
+
+#ifdef FLOATTYPE_IS_INT
+    if (scalar > 0) {
+      vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+      vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+    } else {
+      vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+      vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+    }
+#else
+    vec->_v(0) = std::floor(_this->_v(0) / scalar);
+    vec->_v(1) = std::floor(_this->_v(1) / scalar);
+#endif
+  }
+  return py_vec;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
+__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifdef FLOATTYPE_IS_INT
+  if (scalar > 0) {
+    _this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+    _this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+  } else {
+    _this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+    _this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+  }
+#else
+  _this->_v(0) = std::floor(_this->_v(0) / scalar);
+  _this->_v(1) = std::floor(_this->_v(1) / scalar);
+#endif
+  Py_INCREF(self);
+  return self;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
+__pow__(PyObject *self, FLOATTYPE exponent) const {
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase2) *vec = (FLOATNAME(LVecBase2) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase2));
+    nassertr(vec != nullptr, nullptr);
+
+    vec->_v(0) = cpow(_this->_v(0), exponent);
+    vec->_v(1) = cpow(_this->_v(1), exponent);
+  }
+  return py_vec;
 }
 }
 
 
 /**
 /**

+ 4 - 1
panda/src/linmath/lvecBase2_ext_src.h

@@ -23,7 +23,10 @@ public:
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH std::string __repr__() const;
   INLINE_LINMATH std::string __repr__() const;
 
 
-  INLINE_LINMATH FLOATNAME(LVecBase2) __pow__(FLOATTYPE exponent) const;
+  INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
+  INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
+
+  INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
 
 
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;

+ 4 - 1
panda/src/linmath/lvecBase2_src.h

@@ -133,7 +133,10 @@ PUBLISHED:
 
 
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase2) &other);
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase2) &other);
 
 
-  EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase2) __pow__(FLOATTYPE exponent) const);
+  EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
+  EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
+
+  EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
 
 
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

+ 79 - 6
panda/src/linmath/lvecBase3_ext_src.I

@@ -201,12 +201,85 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
 /**
 /**
  *
  *
  */
  */
-INLINE_LINMATH FLOATNAME(LVecBase3) Extension<FLOATNAME(LVecBase3)>::
-__pow__(FLOATTYPE exponent) const {
-  return FLOATNAME(LVecBase3)(
-    cpow(_this->_v(0), exponent),
-    cpow(_this->_v(1), exponent),
-    cpow(_this->_v(2), exponent));
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
+__floordiv__(PyObject *self, FLOATTYPE scalar) const {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase3) *vec = (FLOATNAME(LVecBase3) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase3));
+    nassertr(vec != nullptr, nullptr);
+
+#ifdef FLOATTYPE_IS_INT
+    if (scalar > 0) {
+      vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+      vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+      vec->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
+    } else {
+      vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+      vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+      vec->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
+    }
+#else
+    vec->_v(0) = std::floor(_this->_v(0) / scalar);
+    vec->_v(1) = std::floor(_this->_v(1) / scalar);
+    vec->_v(2) = std::floor(_this->_v(2) / scalar);
+#endif
+  }
+  return py_vec;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
+__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifdef FLOATTYPE_IS_INT
+  if (scalar > 0) {
+    _this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+    _this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+    _this->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
+  } else {
+    _this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+    _this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+    _this->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
+  }
+#else
+  _this->_v(0) = std::floor(_this->_v(0) / scalar);
+  _this->_v(1) = std::floor(_this->_v(1) / scalar);
+  _this->_v(2) = std::floor(_this->_v(2) / scalar);
+#endif
+  Py_INCREF(self);
+  return self;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
+__pow__(PyObject *self, FLOATTYPE exponent) const {
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase3) *vec = (FLOATNAME(LVecBase3) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase3));
+    nassertr(vec != nullptr, nullptr);
+
+    vec->_v(0) = cpow(_this->_v(0), exponent);
+    vec->_v(1) = cpow(_this->_v(1), exponent);
+    vec->_v(2) = cpow(_this->_v(2), exponent);
+  }
+  return py_vec;
 }
 }
 
 
 /**
 /**

+ 4 - 1
panda/src/linmath/lvecBase3_ext_src.h

@@ -23,7 +23,10 @@ public:
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH std::string __repr__() const;
   INLINE_LINMATH std::string __repr__() const;
 
 
-  INLINE_LINMATH FLOATNAME(LVecBase3) __pow__(FLOATTYPE exponent) const;
+  INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
+  INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
+
+  INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
 
 
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;

+ 4 - 1
panda/src/linmath/lvecBase3_src.h

@@ -152,7 +152,10 @@ PUBLISHED:
 
 
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase3) &other);
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase3) &other);
 
 
-  EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase3) __pow__(FLOATTYPE exponent) const);
+  EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
+  EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
+
+  EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
 
 
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

+ 86 - 7
panda/src/linmath/lvecBase4_ext_src.I

@@ -207,13 +207,92 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
 /**
 /**
  *
  *
  */
  */
-INLINE_LINMATH FLOATNAME(LVecBase4) Extension<FLOATNAME(LVecBase4)>::
-__pow__(FLOATTYPE exponent) const {
-  return FLOATNAME(LVecBase4)(
-    cpow(_this->_v(0), exponent),
-    cpow(_this->_v(1), exponent),
-    cpow(_this->_v(2), exponent),
-    cpow(_this->_v(3), exponent));
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
+__floordiv__(PyObject *self, FLOATTYPE scalar) const {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase4) *vec = (FLOATNAME(LVecBase4) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase4));
+    nassertr(vec != nullptr, nullptr);
+
+#ifdef FLOATTYPE_IS_INT
+    if (scalar > 0) {
+      vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+      vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+      vec->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
+      vec->_v(3) = (_this->_v(3) >= 0) ? _this->_v(3) / scalar : -1 - (-1 - _this->_v(3)) / scalar;
+    } else {
+      vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+      vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+      vec->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
+      vec->_v(3) = (_this->_v(3) <= 0) ? _this->_v(3) / scalar : -1 + (1 - _this->_v(3)) / -scalar;
+    }
+#else
+    vec->_v(0) = std::floor(_this->_v(0) / scalar);
+    vec->_v(1) = std::floor(_this->_v(1) / scalar);
+    vec->_v(2) = std::floor(_this->_v(2) / scalar);
+    vec->_v(3) = std::floor(_this->_v(3) / scalar);
+#endif
+  }
+  return py_vec;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
+__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
+  if (scalar == (FLOATTYPE)0) {
+    return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
+  }
+
+#ifdef FLOATTYPE_IS_INT
+  if (scalar > 0) {
+    _this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
+    _this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
+    _this->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
+    _this->_v(3) = (_this->_v(3) >= 0) ? _this->_v(3) / scalar : -1 - (-1 - _this->_v(3)) / scalar;
+  } else {
+    _this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
+    _this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
+    _this->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
+    _this->_v(3) = (_this->_v(3) <= 0) ? _this->_v(3) / scalar : -1 + (1 - _this->_v(3)) / -scalar;
+  }
+#else
+  _this->_v(0) = std::floor(_this->_v(0) / scalar);
+  _this->_v(1) = std::floor(_this->_v(1) / scalar);
+  _this->_v(2) = std::floor(_this->_v(2) / scalar);
+  _this->_v(3) = std::floor(_this->_v(3) / scalar);
+#endif
+  Py_INCREF(self);
+  return self;
+}
+
+/**
+ *
+ */
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
+__pow__(PyObject *self, FLOATTYPE exponent) const {
+#ifndef CPPPARSER
+  extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
+#endif
+  PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
+  if (py_vec != nullptr) {
+    FLOATNAME(LVecBase4) *vec = (FLOATNAME(LVecBase4) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase4));
+    nassertr(vec != nullptr, nullptr);
+
+    vec->_v(0) = cpow(_this->_v(0), exponent);
+    vec->_v(1) = cpow(_this->_v(1), exponent);
+    vec->_v(2) = cpow(_this->_v(2), exponent);
+    vec->_v(3) = cpow(_this->_v(3), exponent);
+  }
+  return py_vec;
 }
 }
 
 
 /**
 /**

+ 4 - 1
panda/src/linmath/lvecBase4_ext_src.h

@@ -23,7 +23,10 @@ public:
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
   INLINE_LINMATH std::string __repr__() const;
   INLINE_LINMATH std::string __repr__() const;
 
 
-  INLINE_LINMATH FLOATNAME(LVecBase4) __pow__(FLOATTYPE exponent) const;
+  INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
+  INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
+
+  INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
   INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
 
 
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;
   INLINE_LINMATH PyObject *__round__(PyObject *self) const;

+ 4 - 1
panda/src/linmath/lvecBase4_src.h

@@ -160,7 +160,10 @@ PUBLISHED:
 
 
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase4) &other);
   INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase4) &other);
 
 
-  EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase4) __pow__(FLOATTYPE exponent) const);
+  EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
+  EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
+
+  EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
   EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
 
 
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));
   EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

+ 20 - 0
tests/linmath/test_lvector2.py

@@ -2,6 +2,7 @@ from math import floor, ceil
 import sys
 import sys
 
 
 from panda3d.core import Vec2, Vec3, Vec4, Vec2F, Vec2D
 from panda3d.core import Vec2, Vec3, Vec4, Vec2F, Vec2D
+from panda3d import core
 import pytest
 import pytest
 
 
 
 
@@ -121,3 +122,22 @@ def test_vec2_ceil():
     rounded_vector = ceil(original_vector)
     rounded_vector = ceil(original_vector)
     assert rounded_vector.x == 3
     assert rounded_vector.x == 3
     assert rounded_vector.y == -2
     assert rounded_vector.y == -2
+
+
[email protected]("type", (core.LVecBase2f, core.LVecBase2d, core.LVecBase2i))
+def test_vec2_floordiv(type):
+    with pytest.raises(ZeroDivisionError):
+        type(1, 2) // 0
+
+    for i in range(-100, 100):
+        for j in range(1, 100):
+            assert (type(i) // j).x == i // j
+            assert (type(i) // -j).x == i // -j
+
+            v = type(i)
+            v //= j
+            assert v.x == i // j
+
+            v = type(i)
+            v //= -j
+            assert v.x == i // -j

+ 20 - 0
tests/linmath/test_lvector3.py

@@ -2,6 +2,7 @@ from math import floor, ceil
 import sys
 import sys
 
 
 from panda3d.core import Vec2, Vec3, Vec3F, Vec3D
 from panda3d.core import Vec2, Vec3, Vec3F, Vec3D
+from panda3d import core
 import pytest
 import pytest
 
 
 
 
@@ -106,3 +107,22 @@ def test_vec3_ceil():
     assert rounded_vector.x == 3
     assert rounded_vector.x == 3
     assert rounded_vector.y == -2
     assert rounded_vector.y == -2
     assert rounded_vector.z == 4
     assert rounded_vector.z == 4
+
+
[email protected]("type", (core.LVecBase3f, core.LVecBase3d, core.LVecBase3i))
+def test_vec3_floordiv(type):
+    with pytest.raises(ZeroDivisionError):
+        type(1, 2, 3) // 0
+
+    for i in range(-100, 100):
+        for j in range(1, 100):
+            assert (type(i) // j).x == i // j
+            assert (type(i) // -j).x == i // -j
+
+            v = type(i)
+            v //= j
+            assert v.x == i // j
+
+            v = type(i)
+            v //= -j
+            assert v.x == i // -j

+ 20 - 0
tests/linmath/test_lvector4.py

@@ -2,6 +2,7 @@ from math import floor, ceil
 import sys
 import sys
 
 
 from panda3d.core import Vec2, Vec3, Vec4, Vec4F, Vec4D
 from panda3d.core import Vec2, Vec3, Vec4, Vec4F, Vec4D
+from panda3d import core
 import pytest
 import pytest
 
 
 
 
@@ -122,3 +123,22 @@ def test_vec4_ceil():
     assert rounded_vector.y == -2
     assert rounded_vector.y == -2
     assert rounded_vector.z == 4
     assert rounded_vector.z == 4
     assert rounded_vector.w == 1
     assert rounded_vector.w == 1
+
+
[email protected]("type", (core.LVecBase4f, core.LVecBase4d, core.LVecBase4i))
+def test_vec4_floordiv(type):
+    with pytest.raises(ZeroDivisionError):
+        type(1, 2, 3, 4) // 0
+
+    for i in range(-100, 100):
+        for j in range(1, 100):
+            assert (type(i) // j).x == i // j
+            assert (type(i) // -j).x == i // -j
+
+            v = type(i)
+            v //= j
+            assert v.x == i // j
+
+            v = type(i)
+            v //= -j
+            assert v.x == i // -j