diff --git a/panda/src/linmath/lvecBase2_src.cxx b/panda/src/linmath/lvecBase2_src.cxx index e1ddd6e8ce..1560fcd503 100644 --- a/panda/src/linmath/lvecBase2_src.cxx +++ b/panda/src/linmath/lvecBase2_src.cxx @@ -20,7 +20,7 @@ TypeHandle FLOATNAME(LVecBase2)::_type_handle; #ifndef CPPPARSER IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2); #endif -#endif +#endif // HAVE_PYTHON const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_zero = FLOATNAME(LVecBase2)(0.0f, 0.0f); @@ -52,9 +52,7 @@ __reduce__(PyObject *self) const { Py_DECREF(this_class); return result; } -#endif // HAVE_PYTHON -#ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: LVecBase2::__getattr__ // Access: Published @@ -83,6 +81,59 @@ __getattr__(const string &attr_name) const { 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 //////////////////////////////////////////////////////////////////// diff --git a/panda/src/linmath/lvecBase2_src.h b/panda/src/linmath/lvecBase2_src.h index 601a877559..6abea76f33 100644 --- a/panda/src/linmath/lvecBase2_src.h +++ b/panda/src/linmath/lvecBase2_src.h @@ -42,6 +42,8 @@ PUBLISHED: #ifdef HAVE_PYTHON PyObject *__reduce__(PyObject *self) 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 INLINE_LINMATH FLOATTYPE operator [](int i) const; diff --git a/panda/src/linmath/lvecBase3_src.cxx b/panda/src/linmath/lvecBase3_src.cxx index 02819d9031..026c654e85 100644 --- a/panda/src/linmath/lvecBase3_src.cxx +++ b/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_LVecBase3); #endif -#endif +#endif // HAVE_PYTHON const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero = FLOATNAME(LVecBase3)(0.0f, 0.0f, 0.0f); @@ -56,9 +56,7 @@ __reduce__(PyObject *self) const { Py_DECREF(this_class); return result; } -#endif // HAVE_PYTHON -#ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: LVecBase3::__getattr__ // Access: Published @@ -94,6 +92,123 @@ __getattr__(const string &attr_name) const { 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 //////////////////////////////////////////////////////////////////// diff --git a/panda/src/linmath/lvecBase3_src.h b/panda/src/linmath/lvecBase3_src.h index 4b3210af09..a642e75fda 100644 --- a/panda/src/linmath/lvecBase3_src.h +++ b/panda/src/linmath/lvecBase3_src.h @@ -40,6 +40,9 @@ PUBLISHED: #ifdef HAVE_PYTHON PyObject *__reduce__(PyObject *self) 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 INLINE_LINMATH FLOATTYPE operator [](int i) const; diff --git a/panda/src/linmath/lvecBase4_src.cxx b/panda/src/linmath/lvecBase4_src.cxx index c5a108197c..e8cf89455d 100644 --- a/panda/src/linmath/lvecBase4_src.cxx +++ b/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_LVecBase4); #endif -#endif +#endif // HAVE_PYTHON const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_zero = FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 0.0f); @@ -58,9 +58,7 @@ __reduce__(PyObject *self) const { Py_DECREF(this_class); return result; } -#endif // HAVE_PYTHON -#ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: LVecBase4::__getattr__ // Access: Published @@ -108,6 +106,170 @@ __getattr__(const string &attr_name) const { 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 //////////////////////////////////////////////////////////////////// diff --git a/panda/src/linmath/lvecBase4_src.h b/panda/src/linmath/lvecBase4_src.h index aadb8b5354..abecfbce1d 100644 --- a/panda/src/linmath/lvecBase4_src.h +++ b/panda/src/linmath/lvecBase4_src.h @@ -12,6 +12,9 @@ // //////////////////////////////////////////////////////////////////// +class FLOATNAME(LVecBase2); +class FLOATNAME(LVecBase3); + //////////////////////////////////////////////////////////////////// // Class : LVecBase4 // Description : This is the base class for all three-component @@ -41,6 +44,10 @@ PUBLISHED: #ifdef HAVE_PYTHON PyObject *__reduce__(PyObject *self) 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 INLINE_LINMATH FLOATTYPE operator [](int i) const; diff --git a/panda/src/linmath/lvector2_src.cxx b/panda/src/linmath/lvector2_src.cxx index 556a77482d..effc8ed17f 100644 --- a/panda/src/linmath/lvector2_src.cxx +++ b/panda/src/linmath/lvector2_src.cxx @@ -14,12 +14,103 @@ 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 // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// - void FLOATNAME(LVector2):: init_type() { if (_type_handle == TypeHandle::none()) { diff --git a/panda/src/linmath/lvector2_src.h b/panda/src/linmath/lvector2_src.h index 8f27a75011..d20c0b1807 100644 --- a/panda/src/linmath/lvector2_src.h +++ b/panda/src/linmath/lvector2_src.h @@ -25,6 +25,12 @@ PUBLISHED: INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE fill_value); 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) &unit_x(); INLINE_LINMATH static const FLOATNAME(LVector2) &unit_y(); diff --git a/panda/src/linmath/lvector3_src.cxx b/panda/src/linmath/lvector3_src.cxx index a1c6a5edb7..b755391192 100644 --- a/panda/src/linmath/lvector3_src.cxx +++ b/panda/src/linmath/lvector3_src.cxx @@ -14,12 +14,175 @@ 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 // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// - void FLOATNAME(LVector3):: init_type() { if (_type_handle == TypeHandle::none()) { diff --git a/panda/src/linmath/lvector3_src.h b/panda/src/linmath/lvector3_src.h index 58e5c4ddf5..c01db65ad4 100644 --- a/panda/src/linmath/lvector3_src.h +++ b/panda/src/linmath/lvector3_src.h @@ -31,6 +31,13 @@ PUBLISHED: INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE fill_value); 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) &unit_x(); INLINE_LINMATH static const FLOATNAME(LVector3) &unit_y(); diff --git a/panda/src/linmath/lvector4_src.cxx b/panda/src/linmath/lvector4_src.cxx index 4c3f59da2d..8dbb165b57 100644 --- a/panda/src/linmath/lvector4_src.cxx +++ b/panda/src/linmath/lvector4_src.cxx @@ -14,12 +14,235 @@ 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 // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// - void FLOATNAME(LVector4):: init_type() { if (_type_handle == TypeHandle::none()) { diff --git a/panda/src/linmath/lvector4_src.h b/panda/src/linmath/lvector4_src.h index 9db8c0071f..35713a1a4c 100644 --- a/panda/src/linmath/lvector4_src.h +++ b/panda/src/linmath/lvector4_src.h @@ -25,6 +25,14 @@ PUBLISHED: INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE fill_value); 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) &unit_x(); INLINE_LINMATH static const FLOATNAME(LVector4) &unit_y();