diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-04-20 19:06:46 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-04-20 19:06:46 +0400 |
commit | 874c29cea8e6f9bc411fccf2d6f4cb07e94328d0 (patch) | |
tree | 5971e577cf7c02e05a1e37b5ad058c71a6744877 /source/gameengine/Expressions | |
parent | 7555bfa793a2b0fc187c6211c56986f35b2d7b09 (diff) | |
parent | c5bc4e4fb1a33eda8c31f2ea02e91f32f74c8fa5 (diff) |
2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323:HEAD
Notes:
* blenderbuttons and ICON_SNAP_PEEL_OBJECT were not merged.
Diffstat (limited to 'source/gameengine/Expressions')
25 files changed, 1118 insertions, 949 deletions
diff --git a/source/gameengine/Expressions/BoolValue.cpp b/source/gameengine/Expressions/BoolValue.cpp index cadb34d7e8f..13c870b68e5 100644 --- a/source/gameengine/Expressions/BoolValue.cpp +++ b/source/gameengine/Expressions/BoolValue.cpp @@ -181,9 +181,9 @@ ret: the bool stored in the object -float CBoolValue::GetNumber() +double CBoolValue::GetNumber() { - return (float)m_bool; + return (double)m_bool; } diff --git a/source/gameengine/Expressions/BoolValue.h b/source/gameengine/Expressions/BoolValue.h index 6c4d964249f..9352b9d4b92 100644 --- a/source/gameengine/Expressions/BoolValue.h +++ b/source/gameengine/Expressions/BoolValue.h @@ -33,7 +33,7 @@ public: CBoolValue(bool innie, STR_String name, AllocationTYPE alloctype = CValue::HEAPVALUE); virtual const STR_String& GetText(); - virtual float GetNumber(); + virtual double GetNumber(); bool GetBool(); virtual void SetValue(CValue* newval); diff --git a/source/gameengine/Expressions/ConstExpr.cpp b/source/gameengine/Expressions/ConstExpr.cpp index e33ba091ac4..6b64be9c9a9 100644 --- a/source/gameengine/Expressions/ConstExpr.cpp +++ b/source/gameengine/Expressions/ConstExpr.cpp @@ -84,7 +84,7 @@ void CConstExpr::ClearModified() -float CConstExpr::GetNumber() +double CConstExpr::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ConstExpr.h b/source/gameengine/Expressions/ConstExpr.h index e27ece52a83..b117140fe70 100644 --- a/source/gameengine/Expressions/ConstExpr.h +++ b/source/gameengine/Expressions/ConstExpr.h @@ -32,7 +32,7 @@ public: //bool IsInside(float x,float y,float z,bool bBorderInclude=true); bool NeedsRecalculated(); void ClearModified(); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* Calculate(); CConstExpr(CValue* constval); CConstExpr(); diff --git a/source/gameengine/Expressions/EmptyValue.cpp b/source/gameengine/Expressions/EmptyValue.cpp index c2b60e590a4..f72ddc47096 100644 --- a/source/gameengine/Expressions/EmptyValue.cpp +++ b/source/gameengine/Expressions/EmptyValue.cpp @@ -76,7 +76,7 @@ this object -float CEmptyValue::GetNumber() +double CEmptyValue::GetNumber() { return 0; } diff --git a/source/gameengine/Expressions/EmptyValue.h b/source/gameengine/Expressions/EmptyValue.h index b9cca0e57e5..fb6b4a477a6 100644 --- a/source/gameengine/Expressions/EmptyValue.h +++ b/source/gameengine/Expressions/EmptyValue.h @@ -27,7 +27,7 @@ public: virtual ~CEmptyValue(); virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); CListValue* GetPolySoup(); virtual double* GetVector3(bool bGetTransformedVec=false); bool IsInside(CValue* testpoint,bool bBorderInclude=true); diff --git a/source/gameengine/Expressions/ErrorValue.cpp b/source/gameengine/Expressions/ErrorValue.cpp index e52be4c8021..651a772db19 100644 --- a/source/gameengine/Expressions/ErrorValue.cpp +++ b/source/gameengine/Expressions/ErrorValue.cpp @@ -99,7 +99,7 @@ ret: a new object containing the result of applying operator op to val and -float CErrorValue::GetNumber() +double CErrorValue::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ErrorValue.h b/source/gameengine/Expressions/ErrorValue.h index 16e608ca01a..5b5795196ba 100644 --- a/source/gameengine/Expressions/ErrorValue.h +++ b/source/gameengine/Expressions/ErrorValue.h @@ -23,7 +23,7 @@ class CErrorValue : public CPropValue public: virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); CErrorValue(); CErrorValue(STR_String errmsg); virtual ~CErrorValue(); diff --git a/source/gameengine/Expressions/FloatValue.cpp b/source/gameengine/Expressions/FloatValue.cpp index 460eaa73f35..212a55fe457 100644 --- a/source/gameengine/Expressions/FloatValue.cpp +++ b/source/gameengine/Expressions/FloatValue.cpp @@ -278,7 +278,7 @@ ret: the float stored in the object -float CFloatValue::GetNumber() +double CFloatValue::GetNumber() { return m_float; } @@ -287,7 +287,7 @@ float CFloatValue::GetNumber() void CFloatValue::SetValue(CValue* newval) { - m_float = newval->GetNumber(); + m_float = (float)newval->GetNumber(); SetModified(true); } diff --git a/source/gameengine/Expressions/FloatValue.h b/source/gameengine/Expressions/FloatValue.h index 33f05f1d7f2..41f70b5c54c 100644 --- a/source/gameengine/Expressions/FloatValue.h +++ b/source/gameengine/Expressions/FloatValue.h @@ -28,7 +28,7 @@ public: virtual const STR_String & GetText(); void Configure(CValue* menuvalue); - virtual float GetNumber(); + virtual double GetNumber(); virtual void SetValue(CValue* newval); float GetFloat(); void SetFloat(float fl); diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp index 94663c4a365..66075dd8d42 100644 --- a/source/gameengine/Expressions/InputParser.cpp +++ b/source/gameengine/Expressions/InputParser.cpp @@ -39,7 +39,12 @@ #include "IfExpr.h" #if defined(WIN32) || defined(WIN64) -#define strcasecmp _stricmp +#define strcasecmp _stricmp + +#ifndef strtoll +#define strtoll _strtoi64 +#endif + #endif /* Def WIN32 or Def WIN64 */ #define NUM_PRIORITY 6 @@ -319,12 +324,14 @@ void CParser::NextSym() } } +#if 0 int CParser::MakeInt() { // returns the integer representation of the value in the global // variable const_as_string // pre: const_as_string contains only numercal chars return atoi(const_as_string); } +#endif STR_String CParser::Symbol2Str(int s) { // returns a string representation of of symbol s, @@ -436,8 +443,8 @@ CExpression *CParser::Ex(int i) { break; case inttype: { - int temp; - temp = atoi(const_as_string); + cInt temp; + temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */ e1 = new CConstExpr(new CIntValue(temp)); break; } @@ -580,7 +587,7 @@ float CParser::GetFloat(STR_String txt) CExpression* expr = ProcessText(txt); if (expr) { val = expr->Calculate(); - result=val->GetNumber(); + result=(float)val->GetNumber(); @@ -642,7 +649,7 @@ PyObject* CParserPyMake(PyObject* ignored,PyObject* args) CExpression* expr = parser.ProcessText(txt); CValue* val = expr->Calculate(); expr->Release(); - return val; + return val->GetProxy(); } static PyMethodDef CParserMethods[] = diff --git a/source/gameengine/Expressions/InputParser.h b/source/gameengine/Expressions/InputParser.h index f51c473ba18..3d517222639 100644 --- a/source/gameengine/Expressions/InputParser.h +++ b/source/gameengine/Expressions/InputParser.h @@ -94,7 +94,9 @@ private: void CharRep(); void GrabString(int start); void NextSym(); +#if 0 /* not used yet */ int MakeInt(); +#endif STR_String Symbol2Str(int s); void Term(int s); int Priority(int optor); diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp index fb586cb4979..4e86f7bf789 100644 --- a/source/gameengine/Expressions/IntValue.cpp +++ b/source/gameengine/Expressions/IntValue.cpp @@ -42,10 +42,10 @@ effect: constructs a new CIntValue -CIntValue::CIntValue(int innie) +CIntValue::CIntValue(cInt innie) /* pre: -effect: constructs a new CIntValue containing int innie +effect: constructs a new CIntValue containing cInt innie */ { m_int = innie; @@ -54,7 +54,7 @@ effect: constructs a new CIntValue containing int innie -CIntValue::CIntValue(int innie,STR_String name,AllocationTYPE alloctype) +CIntValue::CIntValue(cInt innie,STR_String name,AllocationTYPE alloctype) { m_int = innie; SetName(name); @@ -280,10 +280,10 @@ this object -int CIntValue::GetInt() +cInt CIntValue::GetInt() /* pre: -ret: the int stored in the object +ret: the cInt stored in the object */ { return m_int; @@ -291,7 +291,7 @@ ret: the int stored in the object -float CIntValue::GetNumber() +double CIntValue::GetNumber() { return (float) m_int; } @@ -302,7 +302,7 @@ const STR_String & CIntValue::GetText() { if (!m_pstrRep) m_pstrRep=new STR_String(); - m_pstrRep->Format("%d",m_int); + m_pstrRep->Format("%lld",m_int); return *m_pstrRep; } @@ -321,7 +321,7 @@ CValue* CIntValue::GetReplica() { void CIntValue::SetValue(CValue* newval) { - m_int = (int)newval->GetNumber(); + m_int = (cInt)newval->GetNumber(); SetModified(true); } @@ -329,5 +329,8 @@ void CIntValue::SetValue(CValue* newval) PyObject* CIntValue::ConvertValueToPython() { - return PyInt_FromLong(m_int); + if((m_int > INT_MIN) && (m_int < INT_MAX)) + return PyInt_FromLong(m_int); + else + return PyLong_FromLongLong(m_int); } diff --git a/source/gameengine/Expressions/IntValue.h b/source/gameengine/Expressions/IntValue.h index 4fdc1089857..0f3a38b274b 100644 --- a/source/gameengine/Expressions/IntValue.h +++ b/source/gameengine/Expressions/IntValue.h @@ -18,18 +18,20 @@ #include "Value.h" +typedef long long cInt; + class CIntValue : public CPropValue { //PLUGIN_DECLARE_SERIAL (CIntValue,CValue) public: virtual const STR_String& GetText(); - virtual float GetNumber(); + virtual double GetNumber(); - int GetInt(); + cInt GetInt(); CIntValue(); - CIntValue(int innie); - CIntValue(int innie, + CIntValue(cInt innie); + CIntValue(cInt innie, STR_String name, AllocationTYPE alloctype=CValue::HEAPVALUE); @@ -51,7 +53,7 @@ protected: virtual ~CIntValue(); private: - int m_int; + cInt m_int; STR_String* m_pstrRep; }; diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index 90a939af236..dd9b296dce1 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -27,59 +27,81 @@ #define Py_ssize_t int #endif -Py_ssize_t listvalue_bufferlen(PyObject* list) +Py_ssize_t listvalue_bufferlen(PyObject* self) { - return (Py_ssize_t)( ((CListValue*)list)->GetCount()); + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) + return 0; + + return (Py_ssize_t)list->GetCount(); } -PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index) +PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index) { - int count = ((CListValue*) list)->GetCount(); + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + int count = list->GetCount(); if (index < 0) index = count+index; if (index >= 0 && index < count) { - PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython(); + PyObject* pyobj = list->GetValue(index)->ConvertValueToPython(); if (pyobj) return pyobj; else - return ((CListValue*) list)->GetValue(index)->AddRef(); + return list->GetValue(index)->GetProxy(); } - PyErr_SetString(PyExc_IndexError, "Python ListIndex out of range"); + PyErr_SetString(PyExc_IndexError, "list[i]: Python ListIndex out of range in CValueList"); return NULL; } -PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex) +PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex) { + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + if (PyString_Check(pyindex)) { STR_String index(PyString_AsString(pyindex)); CValue *item = ((CListValue*) list)->FindValue(index); if (item) - return (PyObject*) item; + return item->GetProxy(); } if (PyInt_Check(pyindex)) { int index = PyInt_AsLong(pyindex); - return listvalue_buffer_item(list, index); + return listvalue_buffer_item(self, index); } PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */ - PyErr_Format(PyExc_KeyError, "'%s' not in list", PyString_AsString(pyindex_str)); + PyErr_Format(PyExc_KeyError, "list[key]: '%s' key not in list", PyString_AsString(pyindex_str)); Py_DECREF(pyindex_str); return NULL; } /* just slice it into a python list... */ -PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh) +PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh) { + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + int i, j; - PyListObject *newlist; + PyObject *newlist; if (ilow < 0) ilow = 0; @@ -90,18 +112,18 @@ PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihig if (ihigh < ilow) ihigh = ilow; - newlist = (PyListObject *) PyList_New(ihigh - ilow); + newlist = PyList_New(ihigh - ilow); if (!newlist) return NULL; for (i = ilow, j = 0; i < ihigh; i++, j++) { - PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython(); + PyObject* pyobj = list->GetValue(i)->ConvertValueToPython(); if (!pyobj) - pyobj = ((CListValue*) list)->GetValue(i)->AddRef(); - newlist->ob_item[j] = pyobj; + pyobj = list->GetValue(i)->GetProxy(); + PyList_SET_ITEM(newlist, i, pyobj); } - return (PyObject *) newlist; + return newlist; } @@ -109,11 +131,16 @@ PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihig static PyObject * listvalue_buffer_concat(PyObject * self, PyObject * other) { + CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (listval==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + // for now, we support CListValue concatenated with items // and CListValue concatenated to Python Lists // and CListValue concatenated with another CListValue - - CListValue* listval = (CListValue*) self; + listval->AddRef(); if (other->ob_type == &PyList_Type) { @@ -135,7 +162,7 @@ listvalue_buffer_concat(PyObject * self, PyObject * other) } if (error) { - PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add one or more items to a list"); + PyErr_SetString(PyExc_SystemError, "list.append(val): couldn't add one or more items to this CValueList"); return NULL; } @@ -160,7 +187,7 @@ listvalue_buffer_concat(PyObject * self, PyObject * other) listval->Add(objval); } else { - PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add item to a list"); + PyErr_SetString(PyExc_SystemError, "list.append(i): couldn't add item to this CValueList"); return NULL; } } @@ -193,23 +220,28 @@ static PyMappingMethods instance_as_mapping = { PyTypeObject CListValue::Type = { - PyObject_HEAD_INIT(&PyType_Type) + PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "CListValue", /*tp_name*/ - sizeof(CListValue), /*tp_basicsize*/ + sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - PyDestructor, /*tp_dealloc*/ + py_base_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_compare*/ - __repr, /*tp_repr*/ + py_base_repr, /*tp_repr*/ 0, /*tp_as_number*/ &listvalue_as_sequence, /*tp_as_sequence*/ &instance_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call */ + 0, + py_base_getattro, + py_base_setattro, + 0,0,0,0,0,0,0,0,0, + Methods }; @@ -228,6 +260,7 @@ PyMethodDef CListValue::Methods[] = { {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS}, {"index", (PyCFunction)CListValue::sPyindex,METH_O}, {"count", (PyCFunction)CListValue::sPycount,METH_O}, + {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O}, {NULL,NULL} //Sentinel }; @@ -236,8 +269,8 @@ PyAttributeDef CListValue::Attributes[] = { { NULL } //Sentinel }; -PyObject* CListValue::_getattr(const char *attr) { - _getattr_up(CValue); +PyObject* CListValue::py_getattro(PyObject* attr) { + py_getattro_up(CValue); } @@ -405,14 +438,14 @@ void CListValue::MergeList(CListValue *otherlist) -PyObject* CListValue::Pyappend(PyObject* self, PyObject* value) +PyObject* CListValue::Pyappend(PyObject* value) { - return listvalue_buffer_concat(self, value); + return listvalue_buffer_concat(m_proxy, value); /* m_proxy is the same as self */ } -PyObject* CListValue::Pyreverse(PyObject* self) +PyObject* CListValue::Pyreverse() { std::reverse(m_pValueArray.begin(),m_pValueArray.end()); Py_RETURN_NONE; @@ -425,6 +458,10 @@ bool CListValue::CheckEqual(CValue* first,CValue* second) bool result = false; CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second); + + if (eqval==NULL) + return false; + STR_String txt = eqval->GetText(); eqval->Release(); if (txt=="TRUE") @@ -437,7 +474,7 @@ bool CListValue::CheckEqual(CValue* first,CValue* second) -PyObject* CListValue::Pyindex(PyObject* self, PyObject *value) +PyObject* CListValue::Pyindex(PyObject *value) { PyObject* result = NULL; @@ -458,7 +495,7 @@ PyObject* CListValue::Pyindex(PyObject* self, PyObject *value) checkobj->Release(); if (result==NULL) { - PyErr_SetString(PyExc_ValueError, "ValueError: list.index(x): x not in CListValue"); + PyErr_SetString(PyExc_ValueError, "list.index(x): x not in CListValue"); } return result; @@ -466,7 +503,7 @@ PyObject* CListValue::Pyindex(PyObject* self, PyObject *value) -PyObject* CListValue::Pycount(PyObject* self, PyObject* value) +PyObject* CListValue::Pycount(PyObject* value) { int numfound = 0; @@ -474,7 +511,7 @@ PyObject* CListValue::Pycount(PyObject* self, PyObject* value) if (checkobj==NULL) { /* in this case just return that there are no items in the list */ PyErr_Clear(); - PyInt_FromLong(0); + return PyInt_FromLong(0); } int numelem = GetCount(); @@ -493,12 +530,32 @@ PyObject* CListValue::Pycount(PyObject* self, PyObject* value) +PyObject* CListValue::Pyfrom_id(PyObject* value) +{ + uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value); + + if (PyErr_Occurred()) + return NULL; + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) + { + if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id) + return GetValue(i)->GetProxy(); + } + PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList"); + return NULL; + +} + + /* --------------------------------------------------------------------- * Some stuff taken from the header * --------------------------------------------------------------------- */ CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) { - assert(false); // todo: implement me! + //assert(false); // todo: implement me! + fprintf(stderr, "CValueList::Calc not yet implimented\n"); return NULL; } @@ -508,7 +565,8 @@ CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val) { - assert(false); // todo: implement me! + //assert(false); // todo: implement me! + fprintf(stderr, "CValueList::CalcFinal not yet implimented\n"); return NULL; } @@ -521,7 +579,7 @@ void CListValue::Add(CValue* value) -float CListValue::GetNumber() +double CListValue::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h index 104e3e63283..2af5a330c43 100644 --- a/source/gameengine/Expressions/ListValue.h +++ b/source/gameengine/Expressions/ListValue.h @@ -36,7 +36,7 @@ public: virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* GetReplica(); public: @@ -59,12 +59,21 @@ public: bool CheckEqual(CValue* first,CValue* second); - virtual PyObject* _getattr(const char *attr); + virtual PyObject* py_getattro(PyObject* attr); + virtual PyObject* py_repr(void) { + PyObject *py_proxy= this->GetProxy(); + PyObject *py_list= PySequence_List(py_proxy); + PyObject *py_string= PyObject_Repr(py_list); + Py_DECREF(py_list); + Py_DECREF(py_proxy); + return py_string; + } KX_PYMETHOD_O(CListValue,append); KX_PYMETHOD_NOARGS(CListValue,reverse); KX_PYMETHOD_O(CListValue,index); KX_PYMETHOD_O(CListValue,count); + KX_PYMETHOD_O(CListValue,from_id); private: diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 1bead0a7664..6cfa14ddc80 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -54,50 +54,74 @@ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ + PyTypeObject PyObjectPlus::Type = { - PyObject_HEAD_INIT(&PyType_Type) + PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "PyObjectPlus", /*tp_name*/ - sizeof(PyObjectPlus), /*tp_basicsize*/ + sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - PyDestructor, /*tp_dealloc*/ - 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ - 0, /*tp_compare*/ - __repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call */ + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0, + py_base_getattro, + py_base_setattro, + 0,0,0,0,0,0,0,0,0, + Methods }; + PyObjectPlus::~PyObjectPlus() { - if (ob_refcnt) - { - _Py_ForgetReference(this); + if(m_proxy) { + Py_DECREF(m_proxy); /* Remove own reference, python may still have 1 */ + BGE_PROXY_REF(m_proxy)= NULL; } // assert(ob_refcnt==0); } +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 */ + delete self_plus; + } + + BGE_PROXY_REF(self)= NULL; // not really needed + } + PyObject_DEL( self ); +}; + PyObjectPlus::PyObjectPlus(PyTypeObject *T) // constructor { MT_assert(T != NULL); - this->ob_type = T; - _Py_NewReference(this); + m_proxy= NULL; }; /*------------------------------ * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods ------------------------------*/ PyMethodDef PyObjectPlus::Methods[] = { - {"isA", (PyCFunction) sPy_isA, METH_O}, + {"isA", (PyCFunction) sPyisA, METH_O}, {NULL, NULL} /* Sentinel */ }; +PyAttributeDef PyObjectPlus::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("isValid", PyObjectPlus, pyattr_get_is_valid), + {NULL} //Sentinel +}; + +PyObject* PyObjectPlus::pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + Py_RETURN_TRUE; +} + /*------------------------------ * PyObjectPlus Parents -- Every class, even the abstract one should have parents ------------------------------*/ @@ -106,566 +130,621 @@ PyParentObject PyObjectPlus::Parents[] = {&PyObjectPlus::Type, NULL}; /*------------------------------ * PyObjectPlus attributes -- attributes ------------------------------*/ -PyObject *PyObjectPlus::_getattr(const char *attr) + + +/* This should be the entry in Type since it takes the C++ class from PyObjectPlus_Proxy */ +PyObject *PyObjectPlus::py_base_getattro(PyObject * self, PyObject *attr) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + if(!strcmp("isValid", PyString_AsString(attr))) { + Py_RETURN_TRUE; + } + PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + return NULL; + } + return self_plus->py_getattro(attr); +} + +/* This should be the entry in Type since it takes the C++ class from PyObjectPlus_Proxy */ +int PyObjectPlus::py_base_setattro(PyObject *self, PyObject *attr, PyObject *value) { - if (!strcmp(attr, "__doc__") && GetType()->tp_doc) - return PyString_FromString(GetType()->tp_doc); + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + return -1; + } + + if (value==NULL) + return self_plus->py_delattro(attr); + + return self_plus->py_setattro(attr, value); +} - //if (streq(attr, "type")) - // return Py_BuildValue("s", (*(GetParents()))->tp_name); +PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the entry in Type. +{ + + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + return self_plus->py_repr(); +} - return Py_FindMethod(Methods, this, attr); +PyObject *PyObjectPlus::py_getattro(PyObject* attr) +{ + PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \ + if (descr == NULL) { + if (strcmp(PyString_AsString(attr), "__dict__")==0) { + return py_getattr_dict(NULL, Type.tp_dict); /* no Attributes yet */ + } + PyErr_Format(PyExc_AttributeError, "attribute \"%s\" not found", PyString_AsString(attr)); + return NULL; + } else { + /* Copied from py_getattro_up */ + if (PyCObject_Check(descr)) { + return py_get_attrdef((void *)this, (const PyAttributeDef*)PyCObject_AsVoidPtr(descr)); + } else if (descr->ob_type->tp_descr_get) { + return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); + } else { + fprintf(stderr, "Unknown attribute type (PyObjectPlus::py_getattro)"); + return descr; + } + /* end py_getattro_up copy */ + } } -int PyObjectPlus::_delattr(const char *attr) +int PyObjectPlus::py_delattro(PyObject* attr) { PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted"); return 1; } -int PyObjectPlus::_setattr(const char *attr, PyObject *value) +int PyObjectPlus::py_setattro(PyObject *attr, PyObject* value) { - //return PyObject::_setattr(attr,value); - //cerr << "Unknown attribute" << endl; PyErr_SetString(PyExc_AttributeError, "attribute cant be set"); - return 1; + return PY_SET_ATTR_MISSING; } -PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *self, const char *attr) +PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef) { - const PyAttributeDef *attrdef; - for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++) + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) + { + // fake attribute, ignore + return NULL; + } + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) + { + // the attribute has no field correspondance, handover processing to function. + if (attrdef->m_getFunction == NULL) + return NULL; + return (*attrdef->m_getFunction)(self, attrdef); + } + char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + if (attrdef->m_length > 1) { - if (!strcmp(attr, attrdef->m_name)) + PyObject* resultlist = PyList_New(attrdef->m_length); + for (unsigned int i=0; i<attrdef->m_length; i++) { - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) + switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *val = reinterpret_cast<bool*>(ptr); + ptr += sizeof(bool); + PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *val = reinterpret_cast<short int*>(ptr); + ptr += sizeof(short int); + PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) + { + Py_DECREF(resultlist); + return NULL; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *val = reinterpret_cast<int*>(ptr); + ptr += sizeof(int); + PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *val = reinterpret_cast<float*>(ptr); + ptr += sizeof(float); + PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val)); + break; + } + default: + // no support for array of complex data + Py_DECREF(resultlist); + return NULL; + } + } + return resultlist; + } + else + { + switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *val = reinterpret_cast<bool*>(ptr); + return PyInt_FromLong(*val); + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *val = reinterpret_cast<short int*>(ptr); + return PyInt_FromLong(*val); + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) { - // fake attribute, ignore return NULL; } - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; - if (attrdef->m_length > 1) + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: { - PyObject* resultlist = PyList_New(attrdef->m_length); - for (unsigned int i=0; i<attrdef->m_length; i++) - { - switch (attrdef->m_type) { - case KX_PYATTRIBUTE_TYPE_BOOL: - { - bool *val = reinterpret_cast<bool*>(ptr); - ptr += sizeof(bool); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); - break; - } - case KX_PYATTRIBUTE_TYPE_SHORT: - { - short int *val = reinterpret_cast<short int*>(ptr); - ptr += sizeof(short int); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); - break; - } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are like int, just make sure the field size is the same - if (sizeof(int) != attrdef->m_size) - { - Py_DECREF(resultlist); - return NULL; - } - // walkthrough - case KX_PYATTRIBUTE_TYPE_INT: - { - int *val = reinterpret_cast<int*>(ptr); - ptr += sizeof(int); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); - break; - } - case KX_PYATTRIBUTE_TYPE_FLOAT: - { - float *val = reinterpret_cast<float*>(ptr); - ptr += sizeof(float); - PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val)); - break; - } - default: - // no support for array of complex data - Py_DECREF(resultlist); - return NULL; - } - } - return resultlist; + int *val = reinterpret_cast<int*>(ptr); + return PyInt_FromLong(*val); } - else + case KX_PYATTRIBUTE_TYPE_FLOAT: { - switch (attrdef->m_type) { - case KX_PYATTRIBUTE_TYPE_BOOL: - { - bool *val = reinterpret_cast<bool*>(ptr); - return PyInt_FromLong(*val); - } - case KX_PYATTRIBUTE_TYPE_SHORT: - { - short int *val = reinterpret_cast<short int*>(ptr); - return PyInt_FromLong(*val); - } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are like int, just make sure the field size is the same - if (sizeof(int) != attrdef->m_size) - { - return NULL; - } - // walkthrough - case KX_PYATTRIBUTE_TYPE_INT: - { - int *val = reinterpret_cast<int*>(ptr); - return PyInt_FromLong(*val); - } - case KX_PYATTRIBUTE_TYPE_FLOAT: - { - float *val = reinterpret_cast<float*>(ptr); - return PyFloat_FromDouble(*val); - } - case KX_PYATTRIBUTE_TYPE_STRING: - { - STR_String *val = reinterpret_cast<STR_String*>(ptr); - return PyString_FromString(*val); - } - default: - return NULL; - } + float *val = reinterpret_cast<float*>(ptr); + return PyFloat_FromDouble(*val); } + case KX_PYATTRIBUTE_TYPE_STRING: + { + STR_String *val = reinterpret_cast<STR_String*>(ptr); + return PyString_FromString(*val); + } + default: + return NULL; } } - return NULL; } -int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, const char *attr, PyObject *value) +int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyObject *value) { - const PyAttributeDef *attrdef; void *undoBuffer = NULL; void *sourceBuffer = NULL; size_t bufferSize = 0; - - for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++) + + char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + if (attrdef->m_length > 1) { - if (!strcmp(attr, attrdef->m_name)) + if (!PySequence_Check(value)) + { + PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name); + return 1; + } + if (PySequence_Size(value) != attrdef->m_length) { - if (attrdef->m_access == KX_PYATTRIBUTE_RO || - attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) + PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name); + return 1; + } + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_FUNCTION: + if (attrdef->m_setFunction == NULL) { - PyErr_SetString(PyExc_AttributeError, "property is read-only"); + PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); return 1; } - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; - if (attrdef->m_length > 1) + return (*attrdef->m_setFunction)(self, attrdef, value); + case KX_PYATTRIBUTE_TYPE_BOOL: + bufferSize = sizeof(bool); + break; + case KX_PYATTRIBUTE_TYPE_SHORT: + bufferSize = sizeof(short int); + break; + case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_INT: + bufferSize = sizeof(int); + break; + case KX_PYATTRIBUTE_TYPE_FLOAT: + bufferSize = sizeof(float); + break; + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name); + return 1; + } + // let's implement a smart undo method + bufferSize *= attrdef->m_length; + undoBuffer = malloc(bufferSize); + sourceBuffer = ptr; + if (undoBuffer) + { + memcpy(undoBuffer, sourceBuffer, bufferSize); + } + 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); + switch (attrdef->m_type) { - if (!PySequence_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "expected a sequence"); - return 1; - } - if (PySequence_Size(value) != attrdef->m_length) - { - PyErr_SetString(PyExc_TypeError, "incorrect number of elements in sequence"); - return 1; - } - switch (attrdef->m_type) + case KX_PYATTRIBUTE_TYPE_BOOL: { - case KX_PYATTRIBUTE_TYPE_BOOL: - bufferSize = sizeof(bool); - break; - case KX_PYATTRIBUTE_TYPE_SHORT: - bufferSize = sizeof(short int); - break; - case KX_PYATTRIBUTE_TYPE_ENUM: - case KX_PYATTRIBUTE_TYPE_INT: - bufferSize = sizeof(int); - break; - case KX_PYATTRIBUTE_TYPE_FLOAT: - bufferSize = sizeof(float); + bool *var = reinterpret_cast<bool*>(ptr); + ptr += sizeof(bool); + if (PyInt_Check(item)) + { + *var = (PyInt_AsLong(item) != 0); + } + else if (PyBool_Check(item)) + { + *var = (item == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } break; - default: - // should not happen - PyErr_SetString(PyExc_AttributeError, "Unsupported attribute type, report to blender.org"); - return 1; } - // let's implement a smart undo method - bufferSize *= attrdef->m_length; - undoBuffer = malloc(bufferSize); - sourceBuffer = ptr; - if (undoBuffer) + case KX_PYATTRIBUTE_TYPE_SHORT: { - memcpy(undoBuffer, sourceBuffer, bufferSize); - } - 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); - switch (attrdef->m_type) + short int *var = reinterpret_cast<short int*>(ptr); + ptr += sizeof(short int); + if (PyInt_Check(item)) { - case KX_PYATTRIBUTE_TYPE_BOOL: - { - bool *var = reinterpret_cast<bool*>(ptr); - ptr += sizeof(bool); - if (PyInt_Check(item)) - { - *var = (PyInt_AsLong(item) != 0); - } - else if (PyBool_Check(item)) - { - *var = (item == Py_True); - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer or a bool"); - goto UNDO_AND_ERROR; - } - break; - } - case KX_PYATTRIBUTE_TYPE_SHORT: + long val = PyInt_AsLong(item); + if (attrdef->m_clamp) { - short int *var = reinterpret_cast<short int*>(ptr); - ptr += sizeof(short int); - if (PyInt_Check(item)) - { - long val = PyInt_AsLong(item); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) - val = attrdef->m_imin; - else if (val > attrdef->m_imax) - val = attrdef->m_imax; - } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_SetString(PyExc_ValueError, "item value out of range"); - goto UNDO_AND_ERROR; - } - *var = (short int)val; - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer"); - goto UNDO_AND_ERROR; - } - break; + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are equivalent to int, just make sure that the field size matches: - if (sizeof(int) != attrdef->m_size) + else if (val < attrdef->m_imin || val > attrdef->m_imax) { - PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org"); + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); goto UNDO_AND_ERROR; } - // walkthrough - case KX_PYATTRIBUTE_TYPE_INT: + *var = (short int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name); + goto UNDO_AND_ERROR; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *var = reinterpret_cast<int*>(ptr); + ptr += sizeof(int); + if (PyInt_Check(item)) + { + long val = PyInt_AsLong(item); + if (attrdef->m_clamp) { - int *var = reinterpret_cast<int*>(ptr); - ptr += sizeof(int); - if (PyInt_Check(item)) - { - long val = PyInt_AsLong(item); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) - val = attrdef->m_imin; - else if (val > attrdef->m_imax) - val = attrdef->m_imax; - } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_SetString(PyExc_ValueError, "item value out of range"); - goto UNDO_AND_ERROR; - } - *var = (int)val; - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer"); - goto UNDO_AND_ERROR; - } - break; + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; } - case KX_PYATTRIBUTE_TYPE_FLOAT: + else if (val < attrdef->m_imin || val > attrdef->m_imax) { - float *var = reinterpret_cast<float*>(ptr); - ptr += sizeof(float); - double val = PyFloat_AsDouble(item); - if (val == -1.0 && PyErr_Occurred()) - { - PyErr_SetString(PyExc_TypeError, "expected a float"); - goto UNDO_AND_ERROR; - } - else 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_SetString(PyExc_ValueError, "item value out of range"); - goto UNDO_AND_ERROR; - } - *var = (float)val; - break; + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; } - default: - // should not happen - PyErr_SetString(PyExc_AttributeError, "attribute type check error, report to blender.org"); + *var = (int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); goto UNDO_AND_ERROR; } + break; } - // no error, call check function if any - if (attrdef->m_function != NULL) + case KX_PYATTRIBUTE_TYPE_FLOAT: { - if ((*attrdef->m_function)(self, attrdef) != 0) + float *var = reinterpret_cast<float*>(ptr); + ptr += sizeof(float); + double val = PyFloat_AsDouble(item); + if (val == -1.0 && PyErr_Occurred()) { - // post check returned an error, restore values - UNDO_AND_ERROR: - if (undoBuffer) - { - memcpy(sourceBuffer, undoBuffer, bufferSize); - free(undoBuffer); - } - return 1; + PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; } + else 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, "item value out of range for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + *var = (float)val; + break; } + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name); + goto UNDO_AND_ERROR; + } + } + // no error, call check function if any + if (attrdef->m_checkFunction != NULL) + { + if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + { + // post check returned an error, restore values + UNDO_AND_ERROR: if (undoBuffer) + { + memcpy(sourceBuffer, undoBuffer, bufferSize); free(undoBuffer); - return 0; + } + return 1; + } + } + if (undoBuffer) + free(undoBuffer); + return 0; + } + else // simple attribute value + { + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) + { + if (attrdef->m_setFunction == NULL) + { + PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); + return 1; } - else // simple attribute value + return (*attrdef->m_setFunction)(self, attrdef, value); + } + if (attrdef->m_checkFunction != NULL) + { + // post check function is provided, prepare undo buffer + sourceBuffer = ptr; + switch (attrdef->m_type) { - - if (attrdef->m_function != NULL) + case KX_PYATTRIBUTE_TYPE_BOOL: + bufferSize = sizeof(bool); + break; + case KX_PYATTRIBUTE_TYPE_SHORT: + bufferSize = sizeof(short); + break; + case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_INT: + bufferSize = sizeof(int); + break; + case KX_PYATTRIBUTE_TYPE_FLOAT: + bufferSize = sizeof(float); + break; + case KX_PYATTRIBUTE_TYPE_STRING: + sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr(); + if (sourceBuffer) + bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1; + break; + default: + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); + return 1; + } + if (bufferSize) + { + undoBuffer = malloc(bufferSize); + if (undoBuffer) + { + memcpy(undoBuffer, sourceBuffer, bufferSize); + } + } + } + + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *var = reinterpret_cast<bool*>(ptr); + if (PyInt_Check(value)) + { + *var = (PyInt_AsLong(value) != 0); + } + else if (PyBool_Check(value)) + { + *var = (value == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *var = reinterpret_cast<short int*>(ptr); + if (PyInt_Check(value)) { - // post check function is provided, prepare undo buffer - sourceBuffer = ptr; - switch (attrdef->m_type) + long val = PyInt_AsLong(value); + if (attrdef->m_clamp) { - case KX_PYATTRIBUTE_TYPE_BOOL: - bufferSize = sizeof(bool); - break; - case KX_PYATTRIBUTE_TYPE_SHORT: - bufferSize = sizeof(short); - break; - case KX_PYATTRIBUTE_TYPE_ENUM: - case KX_PYATTRIBUTE_TYPE_INT: - bufferSize = sizeof(int); - break; - case KX_PYATTRIBUTE_TYPE_FLOAT: - bufferSize = sizeof(float); - break; - case KX_PYATTRIBUTE_TYPE_STRING: - sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr(); - if (sourceBuffer) - bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1; - break; - default: - PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org"); - return 1; + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; } - if (bufferSize) + else if (val < attrdef->m_imin || val > attrdef->m_imax) { - undoBuffer = malloc(bufferSize); - if (undoBuffer) - { - memcpy(undoBuffer, sourceBuffer, bufferSize); - } + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; } + *var = (short int)val; } - - switch (attrdef->m_type) + else { - case KX_PYATTRIBUTE_TYPE_BOOL: - { - bool *var = reinterpret_cast<bool*>(ptr); - if (PyInt_Check(value)) - { - *var = (PyInt_AsLong(value) != 0); - } - else if (PyBool_Check(value)) - { - *var = (value == Py_True); - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer or a bool"); - goto FREE_AND_ERROR; - } - break; - } - case KX_PYATTRIBUTE_TYPE_SHORT: + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name); + goto FREE_AND_ERROR; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *var = reinterpret_cast<int*>(ptr); + if (PyInt_Check(value)) + { + long val = PyInt_AsLong(value); + if (attrdef->m_clamp) { - short int *var = reinterpret_cast<short int*>(ptr); - if (PyInt_Check(value)) - { - long val = PyInt_AsLong(value); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) - val = attrdef->m_imin; - else if (val > attrdef->m_imax) - val = attrdef->m_imax; - } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_SetString(PyExc_ValueError, "value out of range"); - goto FREE_AND_ERROR; - } - *var = (short int)val; - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer"); - goto FREE_AND_ERROR; - } - break; + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are equivalent to int, just make sure that the field size matches: - if (sizeof(int) != attrdef->m_size) + else if (val < attrdef->m_imin || val > attrdef->m_imax) { - PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org"); + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); goto FREE_AND_ERROR; } - // walkthrough - case KX_PYATTRIBUTE_TYPE_INT: - { - int *var = reinterpret_cast<int*>(ptr); - if (PyInt_Check(value)) - { - long val = PyInt_AsLong(value); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) - val = attrdef->m_imin; - else if (val > attrdef->m_imax) - val = attrdef->m_imax; - } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_SetString(PyExc_ValueError, "value out of range"); - goto FREE_AND_ERROR; - } - *var = (int)val; - } - else - { - PyErr_SetString(PyExc_TypeError, "expected an integer"); - goto FREE_AND_ERROR; - } - break; - } - case KX_PYATTRIBUTE_TYPE_FLOAT: + *var = (int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *var = reinterpret_cast<float*>(ptr); + double val = PyFloat_AsDouble(value); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + else 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); + goto FREE_AND_ERROR; + } + *var = (float)val; + break; + } + case KX_PYATTRIBUTE_TYPE_STRING: + { + STR_String *var = reinterpret_cast<STR_String*>(ptr); + if (PyString_Check(value)) + { + char *val = PyString_AsString(value); + if (attrdef->m_clamp) { - float *var = reinterpret_cast<float*>(ptr); - double val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) + if (strlen(val) < attrdef->m_imin) { - PyErr_SetString(PyExc_TypeError, "expected a float"); + // can't increase the length of the string + PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name); goto FREE_AND_ERROR; } - else 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_SetString(PyExc_ValueError, "value out of range"); - goto FREE_AND_ERROR; - } - *var = (float)val; - break; - } - case KX_PYATTRIBUTE_TYPE_STRING: - { - STR_String *var = reinterpret_cast<STR_String*>(ptr); - if (PyString_Check(value)) + else if (strlen(val) > attrdef->m_imax) { - char *val = PyString_AsString(value); - if (attrdef->m_clamp) - { - if (strlen(val) < attrdef->m_imin) - { - // can't increase the length of the string - PyErr_SetString(PyExc_ValueError, "string length too short"); - goto FREE_AND_ERROR; - } - else if (strlen(val) > attrdef->m_imax) - { - // trim the string - char c = val[attrdef->m_imax]; - val[attrdef->m_imax] = 0; - *var = val; - val[attrdef->m_imax] = c; - break; - } - } else if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax) - { - PyErr_SetString(PyExc_ValueError, "string length out of range"); - goto FREE_AND_ERROR; - } + // trim the string + char c = val[attrdef->m_imax]; + val[attrdef->m_imax] = 0; *var = val; + val[attrdef->m_imax] = c; + break; } - else - { - PyErr_SetString(PyExc_TypeError, "expected a string"); - goto FREE_AND_ERROR; - } - break; + } else if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; } - default: - // should not happen - PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org"); + *var = val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); goto FREE_AND_ERROR; } + break; } - // check if post processing is needed - if (attrdef->m_function != NULL) + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); + goto FREE_AND_ERROR; + } + } + // check if post processing is needed + if (attrdef->m_checkFunction != NULL) + { + if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + { + // restore value + RESTORE_AND_ERROR: + if (undoBuffer) { - if ((*attrdef->m_function)(self, attrdef) != 0) + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING) { - // restore value - RESTORE_AND_ERROR: - if (undoBuffer) - { - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING) - { - // special case for STR_String: restore the string - STR_String *var = reinterpret_cast<STR_String*>(ptr); - *var = reinterpret_cast<char*>(undoBuffer); - } - else - { - // other field type have direct values - memcpy(ptr, undoBuffer, bufferSize); - } - } - FREE_AND_ERROR: - if (undoBuffer) - free(undoBuffer); - return 1; + // special case for STR_String: restore the string + STR_String *var = reinterpret_cast<STR_String*>(ptr); + *var = reinterpret_cast<char*>(undoBuffer); + } + else + { + // other field type have direct values + memcpy(ptr, undoBuffer, bufferSize); } } + FREE_AND_ERROR: if (undoBuffer) free(undoBuffer); - return 0; + return 1; } } - return -1; + if (undoBuffer) + free(undoBuffer); + return 0; } + + /*------------------------------ * PyObjectPlus repr -- representations ------------------------------*/ -PyObject *PyObjectPlus::_repr(void) +PyObject *PyObjectPlus::py_repr(void) { PyErr_SetString(PyExc_SystemError, "Representation not overridden by object."); return NULL; @@ -676,38 +755,43 @@ PyObject *PyObjectPlus::_repr(void) ------------------------------*/ bool PyObjectPlus::isA(PyTypeObject *T) // if called with a Type, use "typename" { - return isA(T->tp_name); + int i; + PyParentObject P; + PyParentObject *Ps = GetParents(); + + for (P = Ps[i=0]; P != NULL; P = Ps[i++]) + if (P==T) + return true; + + return false; } bool PyObjectPlus::isA(const char *mytypename) // check typename of each parent { - int i; - PyParentObject P; - PyParentObject *Ps = GetParents(); + int i; + PyParentObject P; + PyParentObject *Ps = GetParents(); - for (P = Ps[i=0]; P != NULL; P = Ps[i++]) - { - if (strcmp(P->tp_name, mytypename)==0) - return true; - } - - return false; + for (P = Ps[i=0]; P != NULL; P = Ps[i++]) + if (strcmp(P->tp_name, mytypename)==0) + return true; + + return false; } -PyObject *PyObjectPlus::Py_isA(PyObject *value) // Python wrapper for isA +PyObject *PyObjectPlus::PyisA(PyObject *value) // Python wrapper for isA { - if (!PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError, "expected a string"); - return NULL; - } - if(isA(PyString_AsString(value))) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; + if (PyType_Check(value)) { + return PyBool_FromLong(isA((PyTypeObject *)value)); + } else if (PyString_Check(value)) { + return PyBool_FromLong(isA(PyString_AsString(value))); + } + PyErr_SetString(PyExc_TypeError, "object.isA(value): expected a type or a string"); + return NULL; } -/* Utility function called by the macro _getattr_up() +/* Utility function called by the macro py_getattro_up() * for getting ob.__dict__() values from our PyObject * this is used by python for doing dir() on an object, so its good * if we return a list of attributes and methods. @@ -715,26 +799,57 @@ PyObject *PyObjectPlus::Py_isA(PyObject *value) // Python wrapper for isA * Other then making dir() useful the value returned from __dict__() is not useful * since every value is a Py_None * */ -PyObject *_getattr_dict(PyObject *pydict, PyMethodDef *meth, PyAttributeDef *attrdef) +PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict) { if(pydict==NULL) { /* incase calling __dict__ on the parent of this object raised an error */ PyErr_Clear(); pydict = PyDict_New(); } - if(meth) { - for (; meth->ml_name != NULL; meth++) { - PyDict_SetItemString(pydict, meth->ml_name, Py_None); - } + PyDict_Update(pydict, tp_dict); + return pydict; +} + + + +PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) +{ + if (self->m_proxy==NULL) + { + self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); + BGE_PROXY_PYOWNS(self->m_proxy) = false; } + //PyObject_Print(self->m_proxy, stdout, 0); + //printf("ref %d\n", self->m_proxy->ob_refcnt); - if(attrdef) { - for (; attrdef->m_name != NULL; attrdef++) { - PyDict_SetItemString(pydict, attrdef->m_name, Py_None); + BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ + 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) +{ + if (self->m_proxy) + { + if(py_owns) + { /* Free */ + BGE_PROXY_REF(self->m_proxy) = NULL; + Py_DECREF(self->m_proxy); + self->m_proxy= NULL; + } + else { + Py_INCREF(self->m_proxy); + return self->m_proxy; } + } - - return pydict; + + GetProxy_Ext(self, tp); + 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 */ + } + return self->m_proxy; } #endif //NO_EXP_PYTHON_EMBEDDING diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 1a5f50a3d23..370717a919b 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -50,18 +50,19 @@ also in api2_2x/gen_utils.h */ #ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_BuildValue("O", Py_None) +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif #ifndef Py_RETURN_FALSE -#define Py_RETURN_FALSE return PyBool_FromLong(0) +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False #endif #ifndef Py_RETURN_TRUE -#define Py_RETURN_TRUE return PyBool_FromLong(1) +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True #endif /* for pre Py 2.5 */ #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; +typedef Py_ssize_t (*lenfunc)(PyObject *); #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN #define PY_METHODCHAR char * @@ -72,11 +73,28 @@ typedef int Py_ssize_t; #define PY_METHODCHAR const char * #endif +#include "descrobject.h" + + static inline void Py_Fatal(const char *M) { fprintf(stderr, "%s\n", M); exit(-1); }; +typedef struct { + PyObject_HEAD /* required python macro */ + class PyObjectPlus *ref; + bool py_owns; +} 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_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) + +/* Note, sometimes we dont care what BGE type this is as long as its a proxy */ +#define BGE_PROXY_CHECK_TYPE(_self) ((_self)->ob_type->tp_dealloc == py_base_dealloc) + + // This must be the first line of each // PyC++ class #define Py_Header \ @@ -86,79 +104,130 @@ static inline void Py_Fatal(const char *M) { static PyAttributeDef Attributes[]; \ static PyParentObject Parents[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ - virtual PyParentObject *GetParents(void) {return Parents;} + virtual PyParentObject *GetParents(void) {return Parents;} \ + virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; \ - // This defines the _getattr_up macro + + // This defines the py_getattro_up macro // which allows attribute and method calls // to be properly passed up the hierarchy. -#define _getattr_up(Parent) \ - PyObject *rvalue = Py_FindMethod(Methods, this, attr); \ + +#define py_getattro_up(Parent) \ + \ + PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \ \ - if (rvalue == NULL) { \ + if(descr) { \ + if (PyCObject_Check(descr)) { \ + return py_get_attrdef((void *)this, (const PyAttributeDef*)PyCObject_AsVoidPtr(descr)); \ + } else if (descr->ob_type->tp_descr_get) { \ + return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); \ + } else { \ + fprintf(stderr, "unknown attribute type"); \ + return descr; \ + } \ + } else { \ PyErr_Clear(); \ - rvalue = Parent::_getattr(attr); \ + PyObject *rvalue= Parent::py_getattro(attr); \ + \ + if (strcmp(PyString_AsString(attr), "__dict__")==0) { \ + return py_getattr_dict(rvalue, Type.tp_dict); \ + } \ + \ + return rvalue; \ } \ - if ((rvalue == NULL) && !strcmp(attr, "__dict__")) {\ + return NULL; + + +/* + * nonzero values are an error for setattr + * however because of the nested lookups we need to know if the errors + * was because the attribute didnt exits of if there was some problem setting the value + */ + +#define PY_SET_ATTR_COERCE_FAIL 2 +#define PY_SET_ATTR_FAIL 1 +#define PY_SET_ATTR_MISSING -1 +#define PY_SET_ATTR_SUCCESS 0 + +#define py_setattro_up(Parent) \ + PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \ + \ + if(descr) { \ + if (PyCObject_Check(descr)) { \ + const PyAttributeDef* attrdef= reinterpret_cast<const PyAttributeDef *>(PyCObject_AsVoidPtr(descr)); \ + if (attrdef->m_access == KX_PYATTRIBUTE_RO) { \ + PyErr_Format(PyExc_AttributeError, "\"%s\" is read only", PyString_AsString(attr)); \ + return PY_SET_ATTR_FAIL; \ + } \ + else { \ + return py_set_attrdef((void *)this, attrdef, value); \ + } \ + } else { \ + PyErr_Format(PyExc_AttributeError, "\"%s\" cannot be set", PyString_AsString(attr)); \ + return PY_SET_ATTR_FAIL; \ + } \ + } else { \ PyErr_Clear(); \ - rvalue = _getattr_dict(Parent::_getattr(attr), Methods, Attributes); \ - } \ - return rvalue; \ + return Parent::py_setattro(attr, value); \ + } + /** * These macros are helpfull when embedding Python routines. The second * macro is one that also requires a documentation string */ #define KX_PYMETHOD(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ + PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ #define KX_PYMETHOD_VARARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args); \ + PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ #define KX_PYMETHOD_NOARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self); \ + PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ #define KX_PYMETHOD_O(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* value); \ + PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ #define KX_PYMETHOD_DOC(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ + PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args); \ + PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_O(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* value); \ + PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self); \ + PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ static const char method_name##_doc[]; \ @@ -181,19 +250,19 @@ static inline void Py_Fatal(const char *M) { */ #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*) +PyObject* class_name::Py##method_name(PyObject* args, PyObject*) #define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* args) +PyObject* class_name::Py##method_name(PyObject* args) #define KX_PYMETHODDEF_DOC_O(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* value) +PyObject* class_name::Py##method_name(PyObject* value) #define KX_PYMETHODDEF_DOC_NOARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*) +PyObject* class_name::Py##method_name() /** * Attribute management @@ -206,6 +275,7 @@ enum KX_PYATTRIBUTE_TYPE { KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_TYPE_DUMMY, + KX_PYATTRIBUTE_TYPE_FUNCTION, }; enum KX_PYATTRIBUTE_ACCESS { @@ -214,7 +284,9 @@ enum KX_PYATTRIBUTE_ACCESS { }; struct KX_PYATTRIBUTE_DEF; -typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); +typedef int (*KX_PYATTRIBUTE_CHECK_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); +typedef int (*KX_PYATTRIBUTE_SET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +typedef PyObject* (*KX_PYATTRIBUTE_GET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); typedef struct KX_PYATTRIBUTE_DEF { const char *m_name; // name of the python attribute @@ -228,7 +300,10 @@ typedef struct KX_PYATTRIBUTE_DEF { 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 - KX_PYATTRIBUTE_FUNCTION m_function; // static function to check the assignment, returns 0 if no error + KX_PYATTRIBUTE_CHECK_FUNCTION m_checkFunction; // static function to check the assignment, returns 0 if no error + KX_PYATTRIBUTE_SET_FUNCTION m_setFunction; // static function to check the assignment, returns 0 if no error + KX_PYATTRIBUTE_GET_FUNCTION m_getFunction; // static function to check the assignment, returns 0 if no error + // The following pointers are just used to have compile time check for attribute type. // It would have been good to use a union but that would require C99 compatibility // to initialize specific union fields through designated initializers. @@ -242,150 +317,145 @@ typedef struct KX_PYATTRIBUTE_DEF { } 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} } + { 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} } #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, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { 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} } #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, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { 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} } #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, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { 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} } // 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} } + { 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} } #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} } + { 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} } #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} } + { 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} } #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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL, NULL} } + { 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} } // 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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL} } + { 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} } #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, ((object *)0)->field, NULL, NULL} } + { 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} } // 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, &((object *)0)->field, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL} } + { 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} } #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, &((object *)0)->field, NULL, NULL} } + { 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} } // 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, &((object *)0)->field, NULL} } + { 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} } #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, &((object *)0)->field, NULL} } + { 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} } #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, &((object *)0)->field, NULL} } + { 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} } #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, ((object *)0)->field, NULL} } + { 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} } #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, ((object *)0)->field, NULL} } + { 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} } #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, ((object *)0)->field, NULL} } + { 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} } #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, &((object *)0)->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} } #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, &((object *)0)->field} } + { 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} } #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, &((object *)0)->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} } + +#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} } +#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} } +#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} } +#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} } -//Multiple integer -#define KX_PYATTRIBUTE_MINT_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, &((object *)0)->field, NULL, NULL} } /*------------------------------ * PyObjectPlus ------------------------------*/ typedef PyTypeObject * PyParentObject; // Define the PyParent Object -class PyObjectPlus : public PyObject +class PyObjectPlus { // The PyObjectPlus abstract class Py_Header; // Always start with Py_Header public: PyObjectPlus(PyTypeObject *T); + + PyObject *m_proxy; /* actually a PyObjectPlus_Proxy */ virtual ~PyObjectPlus(); // destructor - static void PyDestructor(PyObject *P) // python wrapper - { - delete ((PyObjectPlus *) P); - }; -// void INCREF(void) { -// Py_INCREF(this); -// }; // incref method -// void DECREF(void) { -// Py_DECREF(this); -// }; // decref method + /* These static functions are referenced by ALL PyObjectPlus_Proxy types + * they take the C++ reference from the PyObjectPlus_Proxy and call + * its own virtual py_getattro, py_setattro etc. functions. + */ + static void py_base_dealloc(PyObject *self); + static PyObject* py_base_getattro(PyObject * self, PyObject *attr); + static int py_base_setattro(PyObject *self, PyObject *attr, PyObject *value); + static PyObject* py_base_repr(PyObject *self); + + /* 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_getattro(PyObject *attr); + virtual int py_delattro(PyObject *attr); + virtual int py_setattro(PyObject *attr, PyObject *value); + virtual PyObject* py_repr(void); + + static PyObject* py_get_attrdef(void *self, const PyAttributeDef *attrdef); + static int py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyObject *value); - virtual PyObject *_getattr(const char *attr); // _getattr method - static PyObject *__getattr(PyObject * PyObj, char *attr) // This should be the entry in Type. - { - return ((PyObjectPlus*) PyObj)->_getattr(attr); - } - static PyObject *_getattr_self(const PyAttributeDef attrlist[], void *self, const char *attr); - static int _setattr_self(const PyAttributeDef attrlist[], void *self, const char *attr, PyObject *value); + /* isA() methods, shonky replacement for pythons issubclass() + * which we cant use because we have our own subclass system */ + bool isA(PyTypeObject *T); + bool isA(const char *mytypename); - virtual int _delattr(const char *attr); - virtual int _setattr(const char *attr, PyObject *value); // _setattr method - static int __setattr(PyObject *PyObj, // This should be the entry in Type. - char *attr, - PyObject *value) - { - if (!value) - return ((PyObjectPlus*) PyObj)->_delattr(attr); - return ((PyObjectPlus*) PyObj)->_setattr(attr, value); - } + KX_PYMETHOD_O(PyObjectPlus,isA); - virtual PyObject *_repr(void); // _repr method - static PyObject *__repr(PyObject *PyObj) // This should be the entry in Type. - { - return ((PyObjectPlus*) PyObj)->_repr(); - } + /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ + static PyObject* pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - // isA methods - bool isA(PyTypeObject *T); - bool isA(const char *mytypename); - PyObject *Py_isA(PyObject *value); - static PyObject *sPy_isA(PyObject *self, PyObject *value) - { - return ((PyObjectPlus*)self)->Py_isA(value); - } + static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); + static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); }; -PyObject *_getattr_dict(PyObject *pydict, PyMethodDef *meth, PyAttributeDef *attrdef); +PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict); #endif // _adr_py_lib_h_ diff --git a/source/gameengine/Expressions/StringValue.cpp b/source/gameengine/Expressions/StringValue.cpp index 1ef8c5629a0..2b3c62c411e 100644 --- a/source/gameengine/Expressions/StringValue.cpp +++ b/source/gameengine/Expressions/StringValue.cpp @@ -113,7 +113,7 @@ this object -float CStringValue::GetNumber() +double CStringValue::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/StringValue.h b/source/gameengine/Expressions/StringValue.h index b824d4ef86d..16575ed7ffa 100644 --- a/source/gameengine/Expressions/StringValue.h +++ b/source/gameengine/Expressions/StringValue.h @@ -33,7 +33,7 @@ public: /// CValue implementation virtual bool IsEqual(const STR_String & other); virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index ebb12636ac2..7cb97909119 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -36,125 +36,24 @@ bool CValue::m_ignore_deprecation_warnings(false); #ifndef NO_EXP_PYTHON_EMBEDDING -PyObject* cvalue_add(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_ADD_OPERATOR,(CValue*)w); -} -PyObject* cvalue_sub(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_SUB_OPERATOR,(CValue*)w); -} -PyObject* cvalue_mul(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_MUL_OPERATOR,(CValue*)w); -} -PyObject* cvalue_div(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_DIV_OPERATOR,(CValue*)w); -} -PyObject* cvalue_mod(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_MOD_OPERATOR,(CValue*)w); -} -PyObject* cvalue_neg(PyObject*v) -{ - return ((CValue*)v)->Calc(VALUE_NEG_OPERATOR,(CValue*)v); -} -PyObject* cvalue_pos(PyObject*v) -{ - return ((CValue*)v)->Calc(VALUE_POS_OPERATOR,(CValue*)v); -} - - -int MyPyCompare (PyObject* v,PyObject* w) -{ - CValue* eqval = ((CValue*)v)->Calc(VALUE_EQL_OPERATOR,(CValue*)w); - STR_String txt = eqval->GetText(); - eqval->Release(); - if (txt=="TRUE") - return 0; - CValue* lessval = ((CValue*)v)->Calc(VALUE_LES_OPERATOR,(CValue*)w); - txt = lessval->GetText(); - lessval->Release(); - if (txt=="TRUE") - return -1; - - return 1; -} - - -int cvalue_coerce(PyObject** pv,PyObject** pw) -{ - if (PyInt_Check(*pw)) { - double db = (double)PyInt_AsLong(*pw); - *pw = new CIntValue((int) db); - Py_INCREF(*pv); - return 0; - } - else if (PyLong_Check(*pw)) { - double db = PyLong_AsDouble(*pw); - *pw = new CFloatValue(db); - Py_INCREF(*pv); - return 0; - } - else if (PyFloat_Check(*pw)) { - double db = PyFloat_AsDouble(*pw); - *pw = new CFloatValue(db); - Py_INCREF(*pv); - return 0; - } else if (PyString_Check(*pw)) { - const STR_String str = PyString_AsString(*pw); - *pw = new CStringValue(str,""); - Py_INCREF(*pv); - return 0; - } - return 1; /* Can't do it */ - -} -static PyNumberMethods cvalue_as_number = { - (binaryfunc)cvalue_add, /*nb_add*/ - (binaryfunc)cvalue_sub, /*nb_subtract*/ - (binaryfunc)cvalue_mul, /*nb_multiply*/ - (binaryfunc)cvalue_div, /*nb_divide*/ - (binaryfunc)cvalue_mod, /*nb_remainder*/ - 0,//(binaryfunc)cvalue_divmod, /*nb_divmod*/ - 0,//0,//0,//0,//(ternaryfunc)cvalue_pow, /*nb_power*/ - (unaryfunc)cvalue_neg, /*nb_negative*/ - 0,//(unaryfunc)cvalue_pos, /*nb_positive*/ - 0,//(unaryfunc)cvalue_abs, /*nb_absolute*/ - 0,//(inquiry)cvalue_nonzero, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - (coercion)cvalue_coerce, /*nb_coerce*/ - 0,//(unaryfunc)cvalue_int, /*nb_int*/ - 0,//(unaryfunc)cvalue_long, /*nb_long*/ - 0,//(unaryfunc)cvalue_float, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ -}; - - PyTypeObject CValue::Type = { - PyObject_HEAD_INIT(&PyType_Type) + PyObject_HEAD_INIT(NULL) 0, "CValue", - sizeof(CValue), + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, 0, - PyDestructor, 0, - __getattr, - __setattr, - &MyPyCompare, - __repr, - &cvalue_as_number, 0, 0, + py_base_repr, 0, - 0 + 0,0,0,0,0, + py_base_getattro, + py_base_setattro, + 0,0,0,0,0,0,0,0,0, + Methods }; PyParentObject CValue::Parents[] = { @@ -168,7 +67,7 @@ PyMethodDef CValue::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* CValue::PyGetName(PyObject* self) +PyObject* CValue::PyGetName() { return PyString_FromString(this->GetName()); } @@ -320,55 +219,70 @@ STR_String CValue::op2str (VALUE_OPERATOR op) // void CValue::SetProperty(const STR_String & name,CValue* ioProperty) { - // Check if somebody is setting an empty property if (ioProperty==NULL) - { + { // Check if somebody is setting an empty property trace("Warning:trying to set empty property!"); return; } - // Make sure we have a property array - if (m_pNamedPropertyArray == NULL) + if (m_pNamedPropertyArray) + { // Try to replace property (if so -> exit as soon as we replaced it) + CValue* oldval = (*m_pNamedPropertyArray)[name]; + if (oldval) + oldval->Release(); + } + else { // Make sure we have a property array m_pNamedPropertyArray = new std::map<STR_String,CValue *>; - - // Try to replace property (if so -> exit as soon as we replaced it) - CValue* oldval = (*m_pNamedPropertyArray)[name]; - if (oldval) - { - oldval->Release(); } // Add property at end of array (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); } +void CValue::SetProperty(const char* name,CValue* ioProperty) +{ + if (ioProperty==NULL) + { // Check if somebody is setting an empty property + trace("Warning:trying to set empty property!"); + return; + } + if (m_pNamedPropertyArray) + { // Try to replace property (if so -> exit as soon as we replaced it) + CValue* oldval = (*m_pNamedPropertyArray)[name]; + if (oldval) + oldval->Release(); + } + else { // Make sure we have a property array + m_pNamedPropertyArray = new std::map<STR_String,CValue *>; + } + + // Add property at end of array + (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); +} // // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> // CValue* CValue::GetProperty(const STR_String & inName) { - // Check properties, as soon as we found it -> Return a pointer to the property - CValue* result = NULL; - if (m_pNamedPropertyArray) - { - std::map<STR_String,CValue*>::iterator it = (*m_pNamedPropertyArray).find(inName); - if (!( it==m_pNamedPropertyArray->end())) - { - result = (*it).second; - } - + if (m_pNamedPropertyArray) { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) + return (*it).second; } - //for (int i=0; i<m_pValuePropertyArray->size(); i++) - // if ((*m_pValuePropertyArray)[i]->GetName() == inName) - // return (*m_pValuePropertyArray)[i]; - - // Did not find property with name <inName>, return NULL property pointer - return result; + return NULL; } - +CValue* CValue::GetProperty(const char *inName) +{ + if (m_pNamedPropertyArray) { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) + return (*it).second; + } + return NULL; +} // // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> @@ -386,7 +300,7 @@ float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) { CValue *property = GetProperty(inName); if (property) - return property->GetNumber(); + return property->GetNumber(); else return defnumber; } @@ -396,26 +310,20 @@ float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) // // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed // -bool CValue::RemoveProperty(const STR_String & inName) +bool CValue::RemoveProperty(const char *inName) { // Check if there are properties at all which can be removed - if (m_pNamedPropertyArray) { - CValue* val = GetProperty(inName); - if (NULL != val) + if (m_pNamedPropertyArray) + { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) { - val->Release(); - m_pNamedPropertyArray->erase(inName); + ((*it).second)->Release(); + m_pNamedPropertyArray->erase(it); return true; } - } - - char err[128]; - if (m_pNamedPropertyArray) - sprintf(err, "attribute \"%s\" dosnt exist", inName.ReadPtr()); - else - sprintf(err, "attribute \"%s\" dosnt exist (no property array)", inName.ReadPtr()); + } - PyErr_SetString(PyExc_AttributeError, err); return false; } @@ -426,8 +334,10 @@ vector<STR_String> CValue::GetPropertyNames() { vector<STR_String> result; if(!m_pNamedPropertyArray) return result; - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + result.reserve(m_pNamedPropertyArray->size()); + + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { result.push_back((*it).first); } @@ -444,8 +354,8 @@ void CValue::ClearProperties() return; // Remove all properties - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) { CValue* tmpval = (*it).second; //STR_String name = (*it).first; @@ -464,9 +374,11 @@ void CValue::ClearProperties() // void CValue::SetPropertiesModified(bool inModified) { - int numprops = GetPropertyCount(); - for (int i=0; i<numprops; i++) - GetProperty(i)->SetModified(inModified); + if(!m_pNamedPropertyArray) return; + std::map<STR_String,CValue*>::iterator it; + + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) + ((*it).second)->SetModified(inModified); } @@ -476,11 +388,13 @@ void CValue::SetPropertiesModified(bool inModified) // bool CValue::IsAnyPropertyModified() { - int numprops = GetPropertyCount(); - for (int i=0;i<numprops;i++) - if (GetProperty(i)->IsModified()) + if(!m_pNamedPropertyArray) return false; + std::map<STR_String,CValue*>::iterator it; + + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) + if (((*it).second)->IsModified()) return true; - + return false; } @@ -489,7 +403,6 @@ bool CValue::IsAnyPropertyModified() // // Get property number <inIndex> // - CValue* CValue::GetProperty(int inIndex) { @@ -498,8 +411,8 @@ CValue* CValue::GetProperty(int inIndex) if (m_pNamedPropertyArray) { - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { if (count++==inIndex) { @@ -535,8 +448,8 @@ void CValue::CloneProperties(CValue *replica) if (m_pNamedPropertyArray) { replica->m_pNamedPropertyArray=NULL; - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { CValue *val = (*it).second->GetReplica(); replica->SetProperty((*it).first,val); @@ -595,6 +508,7 @@ int CValue::Release() { // Reference count reached 0, delete ourselves and return 0 // MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); + delete this; return 0; } @@ -624,9 +538,6 @@ void CValue::AddDataToReplica(CValue *replica) { replica->m_refcount = 1; - //register with Python - _Py_NewReference(replica); - #ifdef _DEBUG //gRefCountValue++; #endif @@ -685,39 +596,28 @@ PyAttributeDef CValue::Attributes[] = { }; -PyObject* CValue::_getattr(const char *attr) +PyObject* CValue::py_getattro(PyObject *attr) { - CValue* resultattr = FindIdentifier(STR_String(attr)); - STR_String text; + char *attr_str= PyString_AsString(attr); + CValue* resultattr = GetProperty(attr_str); if (resultattr) { - if (resultattr->IsError()) - { - resultattr->Release(); - } else - { - // to avoid some compare problems, return a real pythonthing - PyObject* pyconvert = resultattr->ConvertValueToPython(); - if (pyconvert) - { - resultattr->Release(); - return pyconvert; - } else - { - // also check if it's already in pythoninterpreter! - return resultattr; - } - - } + PyObject* pyconvert = resultattr->ConvertValueToPython(); + + if (pyconvert) + return pyconvert; + else + return resultattr->GetProxy(); } - _getattr_up(PyObjectPlus); + py_getattro_up(PyObjectPlus); } CValue* CValue::ConvertPythonToValue(PyObject* pyobj) { CValue* vallie = NULL; - + /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */ +#if 0 if (PyList_Check(pyobj)) { CListValue* listval = new CListValue(); @@ -748,13 +648,18 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) } } else +#endif if (PyFloat_Check(pyobj)) { vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) ); } else if (PyInt_Check(pyobj)) { - vallie = new CIntValue( (int)PyInt_AS_LONG(pyobj) ); + vallie = new CIntValue( (cInt)PyInt_AS_LONG(pyobj) ); + } else + if (PyLong_Check(pyobj)) + { + vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) ); } else if (PyString_Check(pyobj)) { @@ -766,42 +671,56 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) } else { /* return an error value from the caller */ - PyErr_SetString(PyExc_TypeError, "This python value could not be assigned to a game engine property"); + PyErr_SetString(PyExc_TypeError, "This python type could not be converted to a to a game engine property"); } return vallie; } -int CValue::_delattr(const char *attr) +int CValue::py_delattro(PyObject *attr) { - if (!RemoveProperty(STR_String(attr))) /* sets error */ - return 1; - return 0; + char *attr_str= PyString_AsString(attr); + if (RemoveProperty(STR_String(attr_str))) + return 0; + + PyErr_Format(PyExc_AttributeError, "attribute \"%s\" dosnt exist", attr_str); + return 1; } -int CValue::_setattr(const char *attr,PyObject* pyobj) +int CValue::py_setattro(PyObject *attr, PyObject* pyobj) { + char *attr_str= PyString_AsString(attr); + CValue* oldprop = GetProperty(attr_str); + CValue* vallie = ConvertPythonToValue(pyobj); if (vallie) { - STR_String attr_str = attr; - CValue* oldprop = GetProperty(attr_str); - if (oldprop) - { oldprop->SetValue(vallie); - } else - { + else SetProperty(attr_str, vallie); - } + vallie->Release(); - } else - { - return 1; /* ConvertPythonToValue sets the error message */ + } + else { + // ConvertPythonToValue sets the error message + // must return missing so KX_GameObect knows this + // attribute was not a function or bult in attribute, + // + // CValue attributes override internal attributes + // so if it exists as a CValue attribute already, + // assume your trying to set it to a differnt CValue attribute + // otherwise return PY_SET_ATTR_MISSING so children + // classes know they can set it without conflict + + if (GetProperty(attr_str)) + return PY_SET_ATTR_COERCE_FAIL; /* failed to set an existing attribute */ + else + return PY_SET_ATTR_MISSING; /* allow the KX_GameObject dict to set */ } - //PyObjectPlus::_setattr(attr,value); - return 0; + //PyObjectPlus::py_setattro(attr,value); + return PY_SET_ATTR_SUCCESS; }; PyObject* CValue::ConvertKeysToPython( void ) @@ -811,8 +730,8 @@ PyObject* CValue::ConvertKeysToPython( void ) if (m_pNamedPropertyArray) { - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { pystr = PyString_FromString( (*it).first ); PyList_Append(pylist, pystr); @@ -826,7 +745,7 @@ PyObject* CValue::ConvertKeysToPython( void ) PyObject* CValue::PyMake(PyObject* ignored,PyObject* args) { - //if (!PyArg_ParseTuple(args,"s",&name)) return NULL; + //if (!PyArg_ParseTuple(args,"s:make",&name)) return NULL; Py_RETURN_NONE;//new CValue(); } */ @@ -878,7 +797,7 @@ void CValue::ShowDeprecationWarning(const char* old_way,const char* new_way) PyObject *getframe, *frame; PyObject *f_lineno, *f_code, *co_filename; - getframe = PySys_GetObject("_getframe"); // borrowed + getframe = PySys_GetObject((char *)"_getframe"); // borrowed if (getframe) { frame = PyObject_CallObject(getframe, NULL); if (frame) { diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index caf1064dc32..a687e1a493c 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -217,33 +217,14 @@ public: CValue(PyTypeObject *T = &Type); //static PyObject* PyMake(PyObject*,PyObject*); - virtual PyObject *_repr(void) + virtual PyObject *py_repr(void) { - return Py_BuildValue("s",(const char*)GetText()); + return PyString_FromString((const char*)GetText()); } - virtual PyObject* _getattr(const char *attr); - - void SpecialRelease() - { - int i=0; - if (ob_refcnt == 0) - { - _Py_NewReference(this); - - } else - { - i++; - } - Release(); - } - static void PyDestructor(PyObject *P) // python wrapper - { - ((CValue*)P)->SpecialRelease(); - }; - + virtual PyObject* py_getattro(PyObject *attr); virtual PyObject* ConvertValueToPython() { return NULL; } @@ -251,8 +232,8 @@ public: virtual CValue* ConvertPythonToValue(PyObject* pyobj); - virtual int _delattr(const char *attr); - virtual int _setattr(const char *attr, PyObject* value); + virtual int py_delattro(PyObject *attr); + virtual int py_setattro(PyObject *attr, PyObject* value); virtual PyObject* ConvertKeysToPython( void ); @@ -280,13 +261,16 @@ public: int GetRefCount() { return m_refcount; } virtual CValue* AddRef(); // Add a reference to this value virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) + /// Property Management virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed - virtual CValue* GetProperty(const STR_String & inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> + virtual void SetProperty(const char* name,CValue* ioProperty); + virtual CValue* GetProperty(const char* inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> + virtual CValue* GetProperty(const STR_String & inName); STR_String GetPropertyText(const STR_String & inName,const STR_String& deftext=""); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> float GetPropertyNumber(const STR_String& inName,float defnumber); - virtual bool RemoveProperty(const STR_String & inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed + virtual bool RemoveProperty(const char *inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed virtual vector<STR_String> GetPropertyNames(); virtual void ClearProperties(); // Clear all properties @@ -304,7 +288,7 @@ public: virtual void SetColorOperator(VALUE_OPERATOR op); virtual const STR_String & GetText() = 0; - virtual float GetNumber() = 0; + virtual double GetNumber() = 0; double* ZeroVector() { return m_sZeroVec; }; virtual double* GetVector3(bool bGetTransformedVec = false); diff --git a/source/gameengine/Expressions/VectorValue.cpp b/source/gameengine/Expressions/VectorValue.cpp index bea6902eba8..497a50b90e7 100644 --- a/source/gameengine/Expressions/VectorValue.cpp +++ b/source/gameengine/Expressions/VectorValue.cpp @@ -156,7 +156,7 @@ this object return ret; } -float CVectorValue::GetNumber() +double CVectorValue::GetNumber() { return m_vec[KX_X]; } diff --git a/source/gameengine/Expressions/VectorValue.h b/source/gameengine/Expressions/VectorValue.h index 5d9b2a98891..99bf0abb11b 100644 --- a/source/gameengine/Expressions/VectorValue.h +++ b/source/gameengine/Expressions/VectorValue.h @@ -32,7 +32,7 @@ public: void SetVector(double newvec[]); void Configure(CValue* menuvalue); virtual double* GetVector3(bool bGetTransformedVec=false); - virtual float GetNumber(); + virtual double GetNumber(); CValue* Calc(VALUE_OPERATOR op, CValue *val) { return val->CalcFinal(VALUE_VECTOR_TYPE, op, this); diff --git a/source/gameengine/Expressions/VoidValue.h b/source/gameengine/Expressions/VoidValue.h index 4bde0254787..10a6ff9ad3d 100644 --- a/source/gameengine/Expressions/VoidValue.h +++ b/source/gameengine/Expressions/VoidValue.h @@ -47,7 +47,7 @@ public: /// Value -> String or number virtual const STR_String & GetText(); // Get string description of void value (unimplemented) - virtual float GetNumber() { return -1; } + virtual double GetNumber() { return -1; } /// Value calculation virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); |