diff options
author | Benoit Bolsee <benoit.bolsee@online.be> | 2009-09-25 01:22:24 +0400 |
---|---|---|
committer | Benoit Bolsee <benoit.bolsee@online.be> | 2009-09-25 01:22:24 +0400 |
commit | 1483fafd1372a3d3e025d08634e798adb7da512f (patch) | |
tree | 9191765749e29866339f4c31d892603f5f8b334d /source/gameengine/Expressions | |
parent | c995c605f640d8d688e6e58e0fe247ca83f91696 (diff) | |
parent | 222fe6b1a5d49f67177cbb762f55a0e482145f5d (diff) |
Merge of itasc branch. Project files, scons and cmake should be working. Makefile updated but not tested. Comes with Eigen2 2.0.6 C++ matrix library.
Diffstat (limited to 'source/gameengine/Expressions')
-rw-r--r-- | source/gameengine/Expressions/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/gameengine/Expressions/PyObjectPlus.cpp | 380 | ||||
-rw-r--r-- | source/gameengine/Expressions/PyObjectPlus.h | 192 | ||||
-rw-r--r-- | source/gameengine/Expressions/SConscript | 2 |
4 files changed, 452 insertions, 123 deletions
diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 439a50852a7..ec3738d1fe8 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -30,6 +30,7 @@ SET(INC . ../../../source/kernel/gen_system ../../../intern/string + ../../../intern/guardedalloc ../../../intern/moto/include ../../../source/gameengine/SceneGraph ../../../source/blender/blenloader diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 1d1d9e6103b..7adbf5ac651 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -51,6 +51,7 @@ #include "PyObjectPlus.h" #include "STR_String.h" #include "MT_Vector3.h" +#include "MEM_guardedalloc.h" /*------------------------------ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ @@ -95,7 +96,6 @@ PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the ent PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return NULL; } - return self_plus->py_repr(); } @@ -145,42 +145,55 @@ PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObjec PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */ ret->ref= base->ref; - base->ref= NULL; /* invalidate! disallow further access */ - + ret->ptr= base->ptr; ret->py_owns= base->py_owns; + ret->py_ref = base->py_ref; - ret->ref->m_proxy= NULL; - - /* 'base' may be free'd after this func finished but not necessarily - * there is no reference to the BGE data now so it will throw an error on access */ - Py_DECREF(base); - - ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ - Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ - - - /* 'ret' will have 2 references. - * - One ref is needed because ret->ref->m_proxy holds a refcount to the current proxy. - * - Another is needed for returning the value. - * - * So we should be ok with 2 refs, but for some reason this crashes. so adding a new ref... - * */ + if (ret->py_ref) { + base->ref= NULL; /* invalidate! disallow further access */ + base->ptr = NULL; + if (ret->ref) + ret->ref->m_proxy= NULL; + /* 'base' may be free'd after this func finished but not necessarily + * there is no reference to the BGE data now so it will throw an error on access */ + Py_DECREF(base); + if (ret->ref) { + ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ + Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ + } + } else { + // generic structures don't hold a reference to this proxy, so don't increment ref count + if (ret->py_owns) + // but if the proxy owns the structure, there can be only one owner + base->ptr= NULL; + } return (PyObject *)ret; } void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); - if(self_plus) { - if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ - self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ - delete self_plus; + if (BGE_PROXY_PYREF(self)) { + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ + delete self_plus; + } + BGE_PROXY_REF(self)= NULL; // not really needed + } + // the generic pointer is not deleted directly, only through self_plus + BGE_PROXY_PTR(self)= NULL; // not really needed + } else { + void *ptr= BGE_PROXY_PTR(self); + if(ptr) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + // generic structure owned by python MUST be created though MEM_alloc + MEM_freeN(ptr); + } + BGE_PROXY_PTR(self)= NULL; // not really needed } - - BGE_PROXY_REF(self)= NULL; // not really needed } - #if 0 /* is ok normally but not for subtyping, use tp_free instead. */ PyObject_DEL( self ); @@ -217,8 +230,9 @@ PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DE /* note, this is called as a python 'getset, where the PyAttributeDef is the closure */ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) { - void *self= (void *)(BGE_PROXY_REF(self_py)); - if(self==NULL) { + PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); + char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; + if(ptr == NULL || (BGE_PROXY_PYREF(self_py) && (ref==NULL || !ref->py_is_valid()))) { if(attrdef == attr_invalid) Py_RETURN_TRUE; // dont bother running the function @@ -226,7 +240,6 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * return NULL; } - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) { // fake attribute, ignore @@ -237,9 +250,9 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * // the attribute has no field correspondance, handover processing to function. if (attrdef->m_getFunction == NULL) return NULL; - return (*attrdef->m_getFunction)(self, attrdef); + return (*attrdef->m_getFunction)(ref, attrdef); } - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + ptr += attrdef->m_offset; if (attrdef->m_length > 1) { PyObject* resultlist = PyList_New(attrdef->m_length); @@ -293,6 +306,35 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * else { switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_FLAG: + { + bool bval; + switch (attrdef->m_size) { + case 1: + { + unsigned char *val = reinterpret_cast<unsigned char*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + case 2: + { + unsigned short *val = reinterpret_cast<unsigned short*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + case 4: + { + unsigned int *val = reinterpret_cast<unsigned int*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + default: + return NULL; + } + if (attrdef->m_imax) + bval = !bval; + return PyLong_FromSsize_t(bval); + } case KX_PYATTRIBUTE_TYPE_BOOL: { bool *val = reinterpret_cast<bool*>(ptr); @@ -318,7 +360,49 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * case KX_PYATTRIBUTE_TYPE_FLOAT: { float *val = reinterpret_cast<float*>(ptr); - return PyFloat_FromDouble(*val); + if (attrdef->m_imin == 0) { + if (attrdef->m_imax == 0) { + return PyFloat_FromDouble(*val); + } else { + // vector, verify size + if (attrdef->m_size != attrdef->m_imax*sizeof(float)) + { + return NULL; + } +#ifdef USE_MATHUTILS + return newVectorObject(val, attrdef->m_imax, Py_NEW, NULL); +#else + PyObject* resultlist = PyList_New(attrdef->m_imax); + for (unsigned int i=0; i<attrdef->m_imax; i++) + { + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i])); + } + return resultlist; +#endif + } + } else { + // matrix case + if (attrdef->m_size != attrdef->m_imax*attrdef->m_imin*sizeof(float)) + { + return NULL; + } +#ifdef USE_MATHUTILS + return newMatrixObject(val, attrdef->m_imin, attrdef->m_imax, Py_WRAP, NULL); +#else + PyObject* rowlist = PyList_New(attrdef->m_imin); + for (unsigned int i=0; i<attrdef->m_imin; i++) + { + PyObject* collist = PyList_New(attrdef->m_imax); + for (unsigned int j=0; j<attrdef->m_imax; j++) + { + PyList_SET_ITEM(collist,j,PyFloat_FromDouble(val[j])); + } + PyList_SET_ITEM(rowlist,i,collist); + val += attrdef->m_imax; + } + return rowlist; +#endif + } } case KX_PYATTRIBUTE_TYPE_VECTOR: { @@ -340,17 +424,47 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * STR_String *val = reinterpret_cast<STR_String*>(ptr); return PyUnicode_FromString(*val); } + case KX_PYATTRIBUTE_TYPE_CHAR: + { + return PyUnicode_FromString(ptr); + } default: return NULL; } } } + +static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef) +{ + double val = PyFloat_AsDouble(value); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); + return false; + } + if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + return false; + } + *var = (float)val; + return true; +} + /* note, this is called as a python getset */ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) { - void *self= (void *)(BGE_PROXY_REF(self_py)); - if(self==NULL) { + PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); + char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; + if(ref==NULL || !ref->py_is_valid() || ptr==NULL) { PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return PY_SET_ATTR_FAIL; } @@ -358,8 +472,10 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt void *undoBuffer = NULL; void *sourceBuffer = NULL; size_t bufferSize = 0; + PyObject *item = NULL; // to store object that must be dereferenced in case of error + PyObject *list = NULL; // to store object that must be dereferenced in case of error - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + ptr += attrdef->m_offset; if (attrdef->m_length > 1) { if (!PySequence_Check(value)) @@ -380,7 +496,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); return PY_SET_ATTR_FAIL; } - return (*attrdef->m_setFunction)(self, attrdef, value); + return (*attrdef->m_setFunction)(ref, attrdef, value); case KX_PYATTRIBUTE_TYPE_BOOL: bufferSize = sizeof(bool); break; @@ -409,10 +525,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } for (int i=0; i<attrdef->m_length; i++) { - PyObject *item = PySequence_GetItem(value, i); /* new ref */ - // we can decrement the reference immediately, the reference count - // is at least 1 because the item is part of an array - Py_DECREF(item); + item = PySequence_GetItem(value, i); /* new ref */ switch (attrdef->m_type) { case KX_PYATTRIBUTE_TYPE_BOOL: @@ -528,11 +641,14 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name); goto UNDO_AND_ERROR; } + // finished using item, release + Py_DECREF(item); + item = NULL; } // no error, call check function if any if (attrdef->m_checkFunction != NULL) { - if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception if (PyErr_Occurred()==0) @@ -545,6 +661,8 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt memcpy(sourceBuffer, undoBuffer, bufferSize); free(undoBuffer); } + if (item) + Py_DECREF(item); return PY_SET_ATTR_FAIL; } } @@ -561,7 +679,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); return PY_SET_ATTR_FAIL; } - return (*attrdef->m_setFunction)(self, attrdef, value); + return (*attrdef->m_setFunction)(ref, attrdef, value); } if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR) { @@ -576,11 +694,19 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt bufferSize = sizeof(short); break; case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_FLAG: + case KX_PYATTRIBUTE_TYPE_CHAR: + bufferSize = attrdef->m_size; + break; case KX_PYATTRIBUTE_TYPE_INT: bufferSize = sizeof(int); break; case KX_PYATTRIBUTE_TYPE_FLOAT: bufferSize = sizeof(float); + if (attrdef->m_imax) + bufferSize *= attrdef->m_imax; + if (attrdef->m_imin) + bufferSize *= attrdef->m_imin; break; case KX_PYATTRIBUTE_TYPE_STRING: sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr(); @@ -624,6 +750,49 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } break; } + case KX_PYATTRIBUTE_TYPE_FLAG: + { + bool bval; + if (PyLong_Check(value)) + { + bval = (PyLong_AsSsize_t(value) != 0); + } + else if (PyBool_Check(value)) + { + bval = (value == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (attrdef->m_imax) + bval = !bval; + switch (attrdef->m_size) { + case 1: + { + unsigned char *val = reinterpret_cast<unsigned char*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + case 2: + { + unsigned short *val = reinterpret_cast<unsigned short*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + case 4: + { + unsigned int *val = reinterpret_cast<unsigned int*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + default: + PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *var = reinterpret_cast<short int*>(ptr); @@ -689,25 +858,71 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt case KX_PYATTRIBUTE_TYPE_FLOAT: { float *var = reinterpret_cast<float*>(ptr); - double val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) + if (attrdef->m_imin != 0) { - PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); - goto FREE_AND_ERROR; - } - else if (attrdef->m_clamp) + if (attrdef->m_size != attrdef->m_imin*attrdef->m_imax*sizeof(float)) + { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto FREE_AND_ERROR; + } + for (int i=0; i<attrdef->m_imin; i++) + { + PyObject *list = PySequence_GetItem(value, i); /* new ref */ + if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto RESTORE_AND_ERROR; + } + for (int j=0; j<attrdef->m_imax; j++) + { + item = PySequence_GetItem(list, j); /* new ref */ + if (!py_check_attr_float(var, item, attrdef)) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto RESTORE_AND_ERROR; + } + Py_DECREF(item); + item = NULL; + ++var; + } + Py_DECREF(list); + list = NULL; + } + } + else if (attrdef->m_imax != 0) { - if (val < attrdef->m_fmin) - val = attrdef->m_fmin; - else if (val > attrdef->m_fmax) - val = attrdef->m_fmax; - } - else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + if (attrdef->m_size != attrdef->m_imax*sizeof(float)) + { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name); + goto FREE_AND_ERROR; + } + for (int i=0; i<attrdef->m_imax; i++) + { + item = PySequence_GetItem(value, i); /* new ref */ + if (!py_check_attr_float(var, item, attrdef)) + { + goto RESTORE_AND_ERROR; + } + Py_DECREF(item); + item = NULL; + ++var; + } + } + else { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); - goto FREE_AND_ERROR; + if (!py_check_attr_float(var, value, attrdef)) + goto FREE_AND_ERROR; } - *var = (float)val; break; } case KX_PYATTRIBUTE_TYPE_VECTOR: @@ -715,16 +930,15 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt if (!PySequence_Check(value) || PySequence_Size(value) != 3) { PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; + goto FREE_AND_ERROR; } MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr); for (int i=0; i<3; i++) { - PyObject *item = PySequence_GetItem(value, i); /* new ref */ - // we can decrement the reference immediately, the reference count - // is at least 1 because the item is part of an array - Py_DECREF(item); + item = PySequence_GetItem(value, i); /* new ref */ double val = PyFloat_AsDouble(item); + Py_DECREF(item); + item = NULL; if (val == -1.0 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); @@ -746,6 +960,22 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } break; } + case KX_PYATTRIBUTE_TYPE_CHAR: + { + if (PyUnicode_Check(value)) + { + Py_ssize_t val_len; + char *val = _PyUnicode_AsStringAndSize(value, &val_len); + strncpy(ptr, val, attrdef->m_size); + ptr[attrdef->m_size-1] = 0; + } + else + { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *var = reinterpret_cast<STR_String*>(ptr); @@ -793,7 +1023,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt // check if post processing is needed if (attrdef->m_checkFunction != NULL) { - if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { // restore value RESTORE_AND_ERROR: @@ -814,6 +1044,10 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt FREE_AND_ERROR: if (undoBuffer) free(undoBuffer); + if (list) + Py_DECREF(list); + if (item) + Py_DECREF(item); return 1; } } @@ -857,23 +1091,35 @@ void PyObjectPlus::InvalidateProxy() // check typename of each parent } } -PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) +PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr) { if (self->m_proxy==NULL) { self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); BGE_PROXY_PYOWNS(self->m_proxy) = false; + BGE_PROXY_PYREF(self->m_proxy) = true; } //PyObject_Print(self->m_proxy, stdout, 0); //printf("ref %d\n", self->m_proxy->ob_refcnt); BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ + BGE_PROXY_PTR(self->m_proxy) = ptr; Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */ return self->m_proxy; } -PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns) +PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns) { + if (!self) + { + // in case of proxy without reference to game object + PyObject* proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); + BGE_PROXY_PYREF(proxy) = false; + BGE_PROXY_PYOWNS(proxy) = py_owns; + BGE_PROXY_REF(proxy) = NULL; + BGE_PROXY_PTR(proxy) = ptr; + return proxy; + } if (self->m_proxy) { if(py_owns) @@ -889,7 +1135,7 @@ PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool } - GetProxy_Ext(self, tp); + GetProxyPlus_Ext(self, tp, ptr); if(py_owns) { BGE_PROXY_PYOWNS(self->m_proxy) = py_owns; Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */ diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index d8ab007dde9..237f01f5a3a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -88,13 +88,17 @@ typedef struct { typedef struct PyObjectPlus_Proxy { PyObject_HEAD /* required python macro */ - class PyObjectPlus *ref; - bool py_owns; + class PyObjectPlus *ref; // pointer to GE object, it holds a reference to this proxy + void *ptr; // optional pointer to generic structure, the structure holds no reference to this proxy + bool py_owns; // true if the object pointed by ref should be deleted when the proxy is deleted + bool py_ref; // true if proxy is connected to a GE object (ref is used) } PyObjectPlus_Proxy; #define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" #define BGE_PROXY_REF(_self) (((PyObjectPlus_Proxy *)_self)->ref) +#define BGE_PROXY_PTR(_self) (((PyObjectPlus_Proxy *)_self)->ptr) #define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) +#define BGE_PROXY_PYREF(_self) (((PyObjectPlus_Proxy *)_self)->py_ref) /* Note, sometimes we dont care what BGE type this is as long as its a proxy */ #define BGE_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == PyObjectPlus::py_base_dealloc) @@ -103,27 +107,51 @@ typedef struct PyObjectPlus_Proxy { #define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy()) - // This must be the first line of each - // PyC++ class +// This must be the first line of each +// PyC++ class +// AttributesPtr correspond to attributes of proxy generic pointer +// each PyC++ class must be registered in KX_PythonInitTypes.cpp #define __Py_Header \ public: \ static PyTypeObject Type; \ static PyMethodDef Methods[]; \ static PyAttributeDef Attributes[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ - virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ - virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; + virtual PyObject *GetProxy() {return GetProxyPlus_Ext(this, &Type, NULL);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxyPlus_Ext(this, &Type, NULL, py_owns);}; \ +// leave above line empty (macro)! +// use this macro for class that use generic pointer in proxy +// GetProxy() and NewProxy() must be defined to set the correct pointer in the proxy +#define __Py_HeaderPtr \ + public: \ + static PyTypeObject Type; \ + static PyMethodDef Methods[]; \ + static PyAttributeDef Attributes[]; \ + static PyAttributeDef AttributesPtr[]; \ + virtual PyTypeObject *GetType(void) {return &Type;}; \ + virtual PyObject *GetProxy(); \ + virtual PyObject *NewProxy(bool py_owns); \ +// leave above line empty (macro)! #ifdef WITH_CXX_GUARDEDALLOC #define Py_Header __Py_Header \ void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ - void operator delete( void *mem ) { MEM_freeN(mem); } + void operator delete( void *mem ) { MEM_freeN(mem); } \ #else #define Py_Header __Py_Header #endif +#ifdef WITH_CXX_GUARDEDALLOC +#define Py_HeaderPtr __Py_HeaderPtr \ + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ + void operator delete( void *mem ) { MEM_freeN(mem); } \ + +#else +#define Py_HeaderPtr __Py_HeaderPtr +#endif + /* * nonzero values are an error for setattr * however because of the nested lookups we need to know if the errors @@ -245,6 +273,8 @@ enum KX_PYATTRIBUTE_TYPE { KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_TYPE_VECTOR, + KX_PYATTRIBUTE_TYPE_FLAG, + KX_PYATTRIBUTE_TYPE_CHAR, }; enum KX_PYATTRIBUTE_ACCESS { @@ -261,11 +291,14 @@ typedef struct KX_PYATTRIBUTE_DEF { const char *m_name; // name of the python attribute KX_PYATTRIBUTE_TYPE m_type; // type of value KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only - int m_imin; // minimum value in case of integer attributes (for string: minimum string length) - int m_imax; // maximum value in case of integer attributes (for string: maximum string length) + int m_imin; // minimum value in case of integer attributes + // (for string: minimum string length, for flag: mask value, for float: matrix row size) + int m_imax; // maximum value in case of integer attributes + // (for string: maximum string length, for flag: 1 if flag is negative, float: vector/matrix col size) float m_fmin; // minimum value in case of float attributes float m_fmax; // maximum value in case of float attributes bool m_clamp; // enforce min/max value by clamping + bool m_usePtr; // the attribute uses the proxy generic pointer, set at runtime size_t m_offset; // position of field in structure size_t m_size; // size of field for runtime verification (enum only) size_t m_length; // length of array, 1=simple attribute @@ -283,104 +316,146 @@ typedef struct KX_PYATTRIBUTE_DEF { float *m_floatPtr; STR_String *m_stringPtr; MT_Vector3 *m_vectorPtr; + char *m_charPtr; } m_typeCheck; } PyAttributeDef; #define KX_PYATTRIBUTE_DUMMY(name) \ - { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } + +/* attribute points to a single bit of an integer field, attribute=true if bit is set */ +#define KX_PYATTRIBUTE_FLAG_RW(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name,object,field,bit,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RO(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } + +/* attribute points to a single bit of an integer field, attribute=true if bit is set*/ +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name,object,field,bit,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } // enum field cannot be mapped to pointer (because we would need a pointer for each enum) // use field size to verify mapping at runtime only, assuming enum size is equal to int size. #define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } // SHORT_LIST #define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } // INT_LIST #define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } // always clamp for float #define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n], returns a sequence #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } - + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n], returns a vector +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name,min,max,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name,min,max,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n][n], returns a matrix +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name,min,max,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name,min,max,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } + +// only for STR_String member #define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + +// only for char [] array +#define KX_PYATTRIBUTE_CHAR_RW(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +// for MT_Vector3 member #define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } /*------------------------------ @@ -422,16 +497,23 @@ public: /* These are all virtual python methods that are defined in each class * Our own fake subclassing calls these on each class, then calls the parent */ virtual PyObject* py_repr(void); + /* subclass may overwrite this function to implement more sophisticated method of validating a proxy */ + virtual bool py_is_valid(void) { return true; } static PyObject* py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef); static int py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef); /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ static PyObject* pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); - static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); - + + static PyObject *GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr); + /* self=NULL => proxy to generic pointer detached from GE object + if py_owns is true, the memory pointed by ptr will be deleted automatially with MEM_freeN + self!=NULL=> proxy attached to GE object, ptr is optional and point to a struct from which attributes can be defined + if py_owns is true, the object will be deleted automatically, ptr will NOT be deleted + (assume object destructor takes care of it) */ + static PyObject *NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns); + void InvalidateProxy(); /** diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript index c819bfb0d3e..26cafb004b2 100644 --- a/source/gameengine/Expressions/SConscript +++ b/source/gameengine/Expressions/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.cpp') -incs ='. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/SceneGraph #source/blender/blenloader' +incs ='. #source/kernel/gen_system #intern/guardedalloc #intern/string #intern/moto/include #source/gameengine/SceneGraph #source/blender/blenloader' incs += ' ' + env['BF_PYTHON_INC'] env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['core','player'], priority = [360,80], cxx_compileflags=env['BGE_CXXFLAGS']) |