Browse Source

Write masks and swizzle masks for all vecbase and vector classes (e.g. ability to do v.xy *= 1.5 or v.wz = Vec2(1, 2) and stuff)

rdb 15 years ago
parent
commit
8cd721b150

+ 54 - 3
panda/src/linmath/lvecBase2_src.cxx

@@ -20,7 +20,7 @@ TypeHandle FLOATNAME(LVecBase2)::_type_handle;
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
 #endif
 #endif
-#endif
+#endif  // HAVE_PYTHON
 
 
 const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_zero =
 const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_zero =
   FLOATNAME(LVecBase2)(0.0f, 0.0f);
   FLOATNAME(LVecBase2)(0.0f, 0.0f);
@@ -52,9 +52,7 @@ __reduce__(PyObject *self) const {
   Py_DECREF(this_class);
   Py_DECREF(this_class);
   return result;
   return result;
 }
 }
-#endif  // HAVE_PYTHON
 
 
-#ifdef HAVE_PYTHON
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase2::__getattr__
 //     Function: LVecBase2::__getattr__
 //       Access: Published
 //       Access: Published
@@ -83,6 +81,59 @@ __getattr__(const string &attr_name) const {
 
 
   return NULL;
   return NULL;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase2::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase2)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) != 'x' && (*it) != 'y') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[(*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase2::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase2)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name == "x" || attr_name == "y") {
+    PyErr_SetString(PyExc_ValueError, "a float is required");
+    return -1;
+  }
+  if (attr_name != "xy" && attr_name != "yx") {
+    PyTypeObject *tp = Py_TYPE(self);
+    PyErr_Format(PyExc_AttributeError,
+                 "'%.100s' object has no attribute '%.200s'",
+                 tp->tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+}
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
panda/src/linmath/lvecBase2_src.h

@@ -42,6 +42,8 @@ PUBLISHED:
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__getattr__(const string &attr_name) const;
   PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
 #endif
 #endif
 
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE operator [](int i) const;

+ 118 - 3
panda/src/linmath/lvecBase3_src.cxx

@@ -22,7 +22,7 @@ TypeHandle FLOATNAME(LVecBase3)::_type_handle;
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
 #endif
 #endif
-#endif
+#endif  // HAVE_PYTHON
 
 
 const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero =
 const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero =
   FLOATNAME(LVecBase3)(0.0f, 0.0f, 0.0f);
   FLOATNAME(LVecBase3)(0.0f, 0.0f, 0.0f);
@@ -56,9 +56,7 @@ __reduce__(PyObject *self) const {
   Py_DECREF(this_class);
   Py_DECREF(this_class);
   return result;
   return result;
 }
 }
-#endif  // HAVE_PYTHON
 
 
-#ifdef HAVE_PYTHON
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase3::__getattr__
 //     Function: LVecBase3::__getattr__
 //       Access: Published
 //       Access: Published
@@ -94,6 +92,123 @@ __getattr__(const string &attr_name) const {
 
 
   return NULL;
   return NULL;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[(*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 3) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 2) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase2).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 3) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 3) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase3).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[attr_name[2] - 'x'] = val._v.v._2;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
panda/src/linmath/lvecBase3_src.h

@@ -40,6 +40,9 @@ PUBLISHED:
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__getattr__(const string &attr_name) const;
   PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val);
 #endif
 #endif
 
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE operator [](int i) const;

+ 165 - 3
panda/src/linmath/lvecBase4_src.cxx

@@ -22,7 +22,7 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
 #endif
 #endif
-#endif
+#endif  // HAVE_PYTHON
 
 
 const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_zero =
 const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_zero =
   FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 0.0f);
   FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 0.0f);
@@ -58,9 +58,7 @@ __reduce__(PyObject *self) const {
   Py_DECREF(this_class);
   Py_DECREF(this_class);
   return result;
   return result;
 }
 }
-#endif  // HAVE_PYTHON
 
 
-#ifdef HAVE_PYTHON
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::__getattr__
 //     Function: LVecBase4::__getattr__
 //       Access: Published
 //       Access: Published
@@ -108,6 +106,170 @@ __getattr__(const string &attr_name) const {
 
 
   return NULL;
   return NULL;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[((*it) == 'w') ? 3 : (*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 2) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase2).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 3) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase3).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'] = val._v.v._2;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVecBase4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase4) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 4) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase4).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'] = val._v.v._2;
+  _v.data[(attr_name[3] == 'w') ? 3 : attr_name[3] - 'x'] = val._v.v._3;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 7 - 0
panda/src/linmath/lvecBase4_src.h

@@ -12,6 +12,9 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+class FLOATNAME(LVecBase2);
+class FLOATNAME(LVecBase3);
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : LVecBase4
 //       Class : LVecBase4
 // Description : This is the base class for all three-component
 // Description : This is the base class for all three-component
@@ -41,6 +44,10 @@ PUBLISHED:
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__reduce__(PyObject *self) const;
   PyObject *__getattr__(const string &attr_name) const;
   PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase4) val);
 #endif
 #endif
 
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE operator [](int i) const;

+ 92 - 1
panda/src/linmath/lvector2_src.cxx

@@ -14,12 +14,103 @@
 
 
 TypeHandle FLOATNAME(LVector2)::_type_handle;
 TypeHandle FLOATNAME(LVector2)::_type_handle;
 
 
+#ifdef HAVE_PYTHON
+#include "py_panda.h"  
+
+#ifndef CPPPARSER
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
+#endif
+#endif  // HAVE_PYTHON
+
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: LVector2::__getattr__
+//       Access: Published
+//  Description: This is used to implement swizzle masks.
+////////////////////////////////////////////////////////////////////
+PyObject *FLOATNAME(LVector2)::
+__getattr__(const string &attr_name) const {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if (*it != 'x' && *it != 'y') {
+      return NULL;
+    }
+  }
+#endif
+
+  if (attr_name.size() == 1) {
+    return PyFloat_FromDouble(_v.data[attr_name[0] - 'x']);
+
+  } else if (attr_name.size() == 2) {
+    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+    vec->_v.v._0 = _v.data[attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[attr_name[1] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+  }
+
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector2::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector2)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) != 'x' && (*it) != 'y') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[(*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector2::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector2)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name == "x" || attr_name == "y") {
+    PyErr_SetString(PyExc_ValueError, "a float is required");
+    return -1;
+  }
+  if (attr_name != "xy" && attr_name != "yx") {
+    PyTypeObject *tp = Py_TYPE(self);
+    PyErr_Format(PyExc_AttributeError,
+                 "'%.100s' object has no attribute '%.200s'",
+                 tp->tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+}
+#endif  // HAVE_PYTHON
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector2::init_type
 //     Function: LVector2::init_type
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-
 void FLOATNAME(LVector2)::
 void FLOATNAME(LVector2)::
 init_type() {
 init_type() {
   if (_type_handle == TypeHandle::none()) {
   if (_type_handle == TypeHandle::none()) {

+ 6 - 0
panda/src/linmath/lvector2_src.h

@@ -25,6 +25,12 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE x, FLOATTYPE y);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE x, FLOATTYPE y);
 
 
+#ifdef HAVE_PYTHON
+  PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
+#endif
+
   INLINE_LINMATH static const FLOATNAME(LVector2) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector2) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector2) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector2) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector2) &unit_y();
   INLINE_LINMATH static const FLOATNAME(LVector2) &unit_y();

+ 164 - 1
panda/src/linmath/lvector3_src.cxx

@@ -14,12 +14,175 @@
 
 
 TypeHandle FLOATNAME(LVector3)::_type_handle;
 TypeHandle FLOATNAME(LVector3)::_type_handle;
 
 
+#ifdef HAVE_PYTHON
+#include "py_panda.h"  
+
+#ifndef CPPPARSER
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector3);
+#endif
+#endif  // HAVE_PYTHON
+
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: LVector3::__getattr__
+//       Access: Published
+//  Description: This is used to implement swizzle masks.
+////////////////////////////////////////////////////////////////////
+PyObject *FLOATNAME(LVector3)::
+__getattr__(const string &attr_name) const {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if (*it < 'x' || *it > 'z') {
+      return NULL;
+    }
+  }
+#endif
+
+  if (attr_name.size() == 1) {
+    return PyFloat_FromDouble(_v.data[attr_name[0] - 'x']);
+
+  } else if (attr_name.size() == 2) {
+    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+    vec->_v.v._0 = _v.data[attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[attr_name[1] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+
+  } else if (attr_name.size() == 3) {
+    FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
+    vec->_v.v._0 = _v.data[attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[attr_name[1] - 'x'];
+    vec->_v.v._2 = _v.data[attr_name[2] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
+  }
+
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[(*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 3) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 2) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase2).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector3::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector3)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 3) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'x' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 3) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase3).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[attr_name[2] - 'x'] = val._v.v._2;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+#endif  // HAVE_PYTHON
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector3::init_type
 //     Function: LVector3::init_type
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-
 void FLOATNAME(LVector3)::
 void FLOATNAME(LVector3)::
 init_type() {
 init_type() {
   if (_type_handle == TypeHandle::none()) {
   if (_type_handle == TypeHandle::none()) {

+ 7 - 0
panda/src/linmath/lvector3_src.h

@@ -31,6 +31,13 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
 
 
+#ifdef HAVE_PYTHON
+  PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val);
+#endif
+
   INLINE_LINMATH static const FLOATNAME(LVector3) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector3) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector3) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector3) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector3) &unit_y();
   INLINE_LINMATH static const FLOATNAME(LVector3) &unit_y();

+ 224 - 1
panda/src/linmath/lvector4_src.cxx

@@ -14,12 +14,235 @@
 
 
 TypeHandle FLOATNAME(LVector4)::_type_handle;
 TypeHandle FLOATNAME(LVector4)::_type_handle;
 
 
+#ifdef HAVE_PYTHON
+#include "py_panda.h"  
+
+#ifndef CPPPARSER
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector3);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector4);
+#endif
+#endif  // HAVE_PYTHON
+
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::__getattr__
+//       Access: Published
+//  Description: This is used to implement swizzle masks.
+////////////////////////////////////////////////////////////////////
+PyObject *FLOATNAME(LVector4)::
+__getattr__(const string &attr_name) const {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if (*it < 'w' || *it > 'z') {
+      return NULL;
+    }
+  }
+#endif
+
+  if (attr_name.size() == 1) {
+    if (attr_name[0] == 'w') {
+      return PyFloat_FromDouble(_v.data[3]);
+    } else {
+      return PyFloat_FromDouble(_v.data[attr_name[0] - 'x']);
+    }
+
+  } else if (attr_name.size() == 2) {
+    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+    vec->_v.v._0 = _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+
+  } else if (attr_name.size() == 3) {
+    FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
+    vec->_v.v._0 = _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'];
+    vec->_v.v._2 = _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
+
+  } else if (attr_name.size() == 4) {
+    FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
+    vec->_v.v._0 = _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'];
+    vec->_v.v._1 = _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'];
+    vec->_v.v._2 = _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'];
+    vec->_v.v._3 = _v.data[(attr_name[3] == 'w') ? 3 : attr_name[3] - 'x'];
+    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+  }
+
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATTYPE val) {
+#ifndef NDEBUG
+  // Loop through the components in the attribute name,
+  // and assign the floating-point value to every one of them.
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      PyTypeObject *tp = Py_TYPE(self);
+      PyErr_Format(PyExc_AttributeError,
+                   "'%.100s' object has no attribute '%.200s'",
+                   tp->tp_name, attr_name.c_str());
+      return -1;
+    }
+
+    _v.data[((*it) == 'w') ? 3 : (*it) - 'x'] = val;
+  }
+#endif
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 2) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase2).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 3) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase3).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'] = val._v.v._2;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::__setattr__
+//       Access: Published
+//  Description: This is used to implement write masks.
+////////////////////////////////////////////////////////////////////
+int FLOATNAME(LVector4)::
+__setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase4) val) {
+#ifndef NDEBUG
+  // Validate the attribute name.
+  if (attr_name.size() > 4) {
+    goto attrerr;
+  }
+  for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
+    if ((*it) < 'w' || (*it) > 'z') {
+      goto attrerr;
+    }
+  }
+  
+  // Make sure the right type is passed for the right write mask length.
+  if (attr_name.size() == 1) {
+    PyErr_SetString(PyExc_AttributeError, "a float is required");
+    return -1;
+
+  } else if (attr_name.size() != 4) {
+    PyTypeObject &tp = FLOATNAME(Dtool_LVecBase4).As_PyTypeObject();
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot assign '%s' to write mask '%s'",
+                 tp.tp_name, attr_name.c_str());
+    return -1;
+  }
+#endif
+
+  // Assign the components.
+  _v.data[(attr_name[0] == 'w') ? 3 : attr_name[0] - 'x'] = val._v.v._0;
+  _v.data[(attr_name[1] == 'w') ? 3 : attr_name[1] - 'x'] = val._v.v._1;
+  _v.data[(attr_name[2] == 'w') ? 3 : attr_name[2] - 'x'] = val._v.v._2;
+  _v.data[(attr_name[3] == 'w') ? 3 : attr_name[3] - 'x'] = val._v.v._3;
+  return 0;
+
+attrerr:
+  PyTypeObject *tp = Py_TYPE(self);
+  PyErr_Format(PyExc_AttributeError,
+               "'%.100s' object has no attribute '%.200s'",
+               tp->tp_name, attr_name.c_str());
+  return -1;
+}
+#endif  // HAVE_PYTHON
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector2::init_type
 //     Function: LVector2::init_type
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-
 void FLOATNAME(LVector4)::
 void FLOATNAME(LVector4)::
 init_type() {
 init_type() {
   if (_type_handle == TypeHandle::none()) {
   if (_type_handle == TypeHandle::none()) {

+ 8 - 0
panda/src/linmath/lvector4_src.h

@@ -25,6 +25,14 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
 
 
+#ifdef HAVE_PYTHON
+  PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, const string &attr_name, FLOATTYPE val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase2) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase3) val);
+  int __setattr__(PyObject *self, const string &attr_name, FLOATNAME(LVecBase4) val);
+#endif
+
   INLINE_LINMATH static const FLOATNAME(LVector4) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector4) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector4) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector4) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVector4) &unit_y();
   INLINE_LINMATH static const FLOATNAME(LVector4) &unit_y();